Commit Graph
7 Commits
Author SHA1 Message Date
0bdecd1235 feat+test+docs: D68-D70 — bin/olp-connect + /health.anonymousKey + ADR 0011 (#43)
* feat+test+docs: D68+D69+D70 — bin/olp-connect + /health.anonymousKey + ADR 0011

Third substantive Phase 4 implementation. 3 D-days bundled per Iron Rule
11 IDR — olp-connect consumes /health.anonymousKey for zero-config
client setup, both governed by ADR 0011's trusted-LAN-only invariant.

## D68 — bin/olp-connect (zero-config client setup)

Ports OCP ocp-connect (721 lines) → OLP olp-connect (564 lines, pure bash).
Bash over Node (per ADR 0010 § Notes) because client machines may lack
recent Node; bash + curl + python3 = max portability.

CLI: `olp-connect <host-ip> [--port PORT] [--key API_KEY] [--no-system-env]
                            [--dry-run] [--help] [--version]`

Workflow:
1. Connectivity probe (curl /health, 5s timeout, distinguishes TCP
   unreachable from auth-required)
2. Auth resolution: --key flag → /health.anonymousKey (D69) → interactive
   prompt fallback
3. Smoke test (GET /v1/models with bearer)
4. IDE detection + per-IDE config:
   - Claude Code: detect + warn (NOT supported as OLP client per ADR 0010)
   - Cline: detect + print manual VSCode-settings snippet
   - Continue.dev: detect (extension OR ~/.continue/config.yaml) + write
     idempotent models: entry
   - Cursor: detect + print snippet + WARNING (per prior-art known
     base-URL fragility)
   - Aider: detect + write OPENAI_API_BASE + OPENAI_API_KEY to rc files
   - OpenClaw: detect + print "install /olp plugin (D71-D73 deliverable)"
5. System-level env: macOS launchctl setenv / Linux ~/.config/environment.d
   (so VSCode/Cursor started via Dock inherit)
6. Summary + test command

Idempotent (bracketed `# OLP LAN (added by olp-connect)` ... `# /OLP LAN`
blocks in rc files). --dry-run exercises every state-change site without
modifying anything. Exit 0/1/2 conventions.

Installed via package.json bin so `npx olp-connect` works.

## D69 — /health.anonymousKey + auth.advertise_anonymous_key

server.mjs handleHealth emits OPTIONAL `anonymousKey: "olp_..."` field
when ALL THREE prerequisites hold:
1. config.json auth.advertise_anonymous_key === true
2. config.json auth.allow_anonymous === true (per ADR 0007 § 7)
3. At least one non-revoked key has plaintext_advertise field set

Default-off: field is ABSENT (not null) — preserves v0.3.x /health shape;
existing tests don't regress.

bin/olp-keys.mjs new flags: `keygen --anonymous --advertise` writes the
plaintext into the manifest's optional `plaintext_advertise` field AND
prints a WARNING about disk-storage + /health exposure + ADR 0011
pointer. Owner-tier --advertise rejected at BOTH CLI + lib layers.

Implementation note: reused existing guest tier (no new owner_tier:
'anonymous'); plaintext_advertise is a forward-compat optional manifest
field per ADR 0007 § 4 unknown-fields-allowed convention. Cleaner than
introducing a new tier.

anonymousKey appears in BOTH trimmed AND full /health payloads — the
trimmed payload's purpose is to be readable by anonymous clients so they
can self-bootstrap. Tested.

Startup warns on prereq failure (anonymous_key_advertised_but_denied /
anonymous_key_advertised_but_no_anonymous_key_exists) so the relaxed-
posture failure mode is observable. Graceful-degrade: server still
boots; handleHealth re-checks at request time and silently omits the
field when any prereq fails (defense-in-depth).

## D70 — ADR 0011 (anonymous-key deployment-context limits)

New ADR codifying the trusted-LAN-only invariant.

Trade-off documented: anonymous key advertised via /health = anyone who
can reach the server can read /health and use the key. Acceptable ONLY
when "anyone who can reach the server" ≈ "trusted family on the LAN".
Public-internet deployment = instant compromise.

Soft enforcement: server logs startup warn if BIND_ADDRESS resolves to
a public IP AND advertise_anonymous_key: true. No hard allowlist (TLS-
fronted private networks indistinguishable from public from server's
perspective).

Re-evaluation trigger: any time OLP gains "expose to public internet"
deployment mode (e.g., Cloudflare Tunnel guidance in README), revisit.

References ADR 0007 § 7 (identity classes), ADR 0010 § Phase 4 charter
D68-D70 line, OCP server.mjs:148/1454/1488/1555 (PROXY_ANONYMOUS_KEY
reference).

## Test count

658 → 672 (+14 D68-D70 tests across Suite 34: 5 keys.mjs unit + 6 /health
HTTP integration + 3 CLI integration).

## Scope discipline

NO /v1/messages entry surface (out of Phase 4 per ADR 0010).
NO olp-plugin/ Telegram plugin (D71-D73).
NO docs/integrations/*.md files (D71-D73).
NO CHANGELOG / package.json version bump (Phase 4 close handles versioning;
only package.json bin entry for olp-connect added).
NO new npm deps.

## Authority

- ADR 0010 § Phase 4 D-day plan D68-D70 line
- ADR 0011 (this commit — new ADR)
- ADR 0007 § 4 (manifest forward-compat unknown fields) + § 7 (identity
  classes) + § 9 (keygen flow) — extended by D69 plaintext_advertise
- OCP ocp-connect /Users/taodeng/ocp/ocp-connect (port reference)
- OCP server.mjs:148, 1454, 1488, 1555 (PROXY_ANONYMOUS_KEY reference)
- 2026-05-26 brainstorm (Top 5 OCP inheritance candidates, item 3:
  /health.anonymousKey + olp-connect zero-config UX)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: D68-D70 reviewer P1 + P2 fold-in — README impact note + listKeys redaction + schema_version note

Reviewer APPROVE WITH MINOR — 0 P0, 1 P1, 2 P2; all three folded in.

P1 — README impact note for new Phase 4 user-visible surfaces.

Per CLAUDE.md release_kit.new_feature_doc_expectations:
- new env / config knob → README § Environment Variables
- new endpoint or response field → README § API Endpoints
- new CLI surface → dedicated §

README now documents:
- /health.anonymousKey optional field (in API Endpoints table) with cross-
  ref to ADR 0011 + the three-prereq gate
- streaming.heartbeat_interval_ms config (D61) + auth.advertise_anonymous_key
  config (D69) under new "config.json keys introduced at Phase 4" subsection
- Operator CLI surfaces summary: olp / olp-connect / olp-keys keygen
  --anonymous --advertise, with cross-refs to ADR 0010 + 0002 Amendment 7

P2-1 — lib/keys.mjs listKeys() now strips plaintext_advertise alongside
token_hash. Callers wanting the advertised plaintext for the /health
publication path MUST go through findAdvertisedKey() — the only sanctioned
read site. Defends against a future caller of listKeys() leaking the
plaintext into logs / HTTP responses / dashboards. Tests still pass
(no in-repo caller of listKeys depends on plaintext_advertise being
present).

P2-2 — ADR 0011 now documents the schema_version-stays-at-1 decision
explicitly. Additive optional fields don't require bump per ADR 0007 § 4,
but a future archaeologist asking "why didn't D69 bump schema_version?"
now has a one-line answer. Same paragraph documents the listKeys()
redaction policy in plain text alongside the manifest-field contract.

672/672 tests still pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 09:15:09 +10:00
0048481764 feat+docs: D60 — Phase 4 charter (ADR 0010) + default OLP_PORT 3456 → 4567 (#40)
* feat+docs: D60 — Phase 4 charter (ADR 0010) + default OLP_PORT 3456 → 4567

Opens Phase 4 (Operator + Client UX) end-to-end. Per release_kit.phase_rolling_mode,
the version bump fires at Phase 4 close (v0.4.0), not at this D-day; D60 only
ships governance + the port default change.

## ADR 0010 — Phase 4 Charter

Phase 4 scope = 5 D-day groups (~13 D-days total):
- D60 (this commit): charter + default port
- D61-D63: SSE heartbeat + recentErrors[20] ring + /status combined endpoint
- D64-D67: olp Node-based CLI scaffold + olp doctor next_action framework
- D68-D70: olp-connect zero-config IDE setup + /health.anonymousKey + ADR 0011
- D71-D73: olp-plugin/ OpenClaw gateway plugin + docs/integrations/*.md bundle

Charter records the EXPLICIT DECISION to DEFER /v1/messages (Anthropic-shape
entry surface) on the rationale: under ADR 0009 P0 failure it provides no
billing benefit AND degrades worse on fallback than OpenAI-shape clients
(because OpenAI tool schema is the cross-provider lingua franca; Anthropic-
specific features cache_control / computer_use / text_editor / thinking
blocks have no clean fallback mapping). Re-open trigger: (a) ADR 0009 P0
success AND (b) maintainer-named family CC user.

README posture updated: Claude Code listed as NOT SUPPORTED as an OLP
client; recommended alternative is "Cline + OLP" (same fallback chain
available, better cross-provider compatibility).

## Default port 3456 → 4567

server.mjs:74 default value moves so OLP and OCP (which stays on 3456) can
co-host on the same machine without OLP_PORT env override. Existing
deployments wanting the pre-D60 default can set OLP_PORT=3456 in launchd
plist / shell env.

Verified port-change invariants:
- All test-features.mjs suites use port: 0 (ephemeral) — 0 test-surface impact
- Cache / fallback / provider plugins port-agnostic
- Dashboard 30s poll + management endpoints use relative paths
- 623/623 tests pass on D60 branch HEAD

## ADR amendments

- ADR 0001 § "Decision" port-conflict paragraph: struck + amended (co-host
  is now possible via 3456 → 4567 + launchd labels dev.olp.proxy vs
  dev.ocp.proxy)
- ADR 0008 § 6.6 default-port reference updated
- docs/adr/README.md index gains ADR 0010 row

## Authority

- ADR 0010 (this commit)
- ADR 0009 (interactive-mode placeholder — /v1/messages defer rationale)
- 2026-05-26 brainstorm: OCP comprehensive feature audit (subagent output)
  + multi-provider proxy / IDE integration prior-art survey (subagent
  output, both this session)
- docs/v1x-roadmap.md (Phase 4 was the named destination)
- CLAUDE.md release_kit.phase_rolling_mode (current_phase already Phase 4;
  this charter formalizes contents)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: D60 reviewer P2-1 — soften ADR 0001 launchd-label assertion to forward-tense

Reviewer flagged the ADR 0001 amendment's launchd-label collision claim
("avoided via dev.olp.proxy vs dev.ocp.proxy") as present-tense fact when
the OLP plist generator hasn't shipped yet (lands D64-D70 per ADR 0010).
Soften to forward-tense with explicit cross-reference. The factual
claim ("co-host is possible") still stands because plist label is
controlled by the OLP project anyway; this is precision, not correction.

P2-2 (README "since v0.4.0" forward-dated branding) explicitly accepted
as prior-art-consistent with D44+ Phase 2 mid-window doc conventions —
no change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 07:59:11 +10:00
179b4707a7 docs: ADR 0009 — Anthropic Interactive-Mode Path Placeholder (blocked on OCP P0) (#33)
Records OLP-side decision for the cross-project work OCP started in
ADR 0007 (interactive-mode execution pool to address post-2026-06-15
Anthropic billing split).

OPTION 3 — wait + port:

  - No OLP code change to lib/providers/anthropic.mjs until OCP
    ADR 0007 P0 experiment outcome lands (>= 2026-07-15).
  - Avoid duplicating the P0 risk by running an independent OLP
    experiment against the same Anthropic billing pool.
  - If P0 confirms Transport A (stdio NDJSON) or Transport B (PTY)
    bills as subscription rather than Agent SDK credit, port the
    validated pattern to OLP at that time.
  - If both transports fail, shelve this ADR; OLP Anthropic users
    fall back to Agent SDK $100 / month credit OR shift to multi-
    provider routing (Codex / Mistral) per Phase 1 design.

DECISION TREE recorded in § 3 so a future Phase 4 brief can act
mechanically once OCP P0 lands:

  Transport A wins → Option 1 (parallel impl) likely
  Transport B wins → Option 1 with PTY adapter (node-pty native dep
                     triggers engines-bump prior PR)
  Both fail        → Shelve ADR 0009
  Unobservable     → Extend wait

IMPLEMENTATION LANES (§ 4) — informational, not selected:

  Option 1 — OLP parallel implementation in lib/providers/anthropic.mjs
  Option 2 — Chain OCP as backend (OLP → OCP → Claude)
  Option 3 — Hybrid (prefer OCP backend, fallback to local pool)

NO PHASE 4 D-DAY scheduled. This is a decision-record placeholder
ONLY. Phase 4 standing-autopilot grant ("Phase 4+ requires new
authorization") still applies. When OCP P0 lands, maintainer issues
explicit Phase 4 "go" naming this ADR to trigger implementation
selection + D-day work.

DOCUMENTATION:

  - docs/adr/0009-interactive-mode-path-placeholder.md (new, ~200 lines)
  - docs/adr/README.md index: ADR 0009 row added
  - Cross-machine cc-rules memory (~/.cc-rules/memory/learnings/
    ocp_adr_0007_interactive_mode_pool.md, committed in cc-rules
    a16b775) bridges OCP ADR 0007 + OLP ADR 0009 so future Phase 4
    planning sessions in either repo pull the shared context.

Test count: 601 → 601 (docs-only; no test or .mjs file touched).

AUTHORITY:

  - OCP ADR 0007 (~/ocp/docs/adr/0007-interactive-mode-pool.md,
    Draft 2026-05-25) — the triggering external work.
  - OLP ADR 0001 (Project Founding) — the 2026-06-15 billing-split
    motivation that this ADR reaffirms.
  - OLP ADR 0006 (Provider Inclusion) — the anthropic plugin's tier
    that this ADR would amend if/when implemented.
  - CLAUDE.md release_kit overlay phase_rolling_mode (current_phase:
    Phase 4) — this ADR explicitly does NOT consume a Phase 4 D-day.
  - Standing autopilot grant — Phase 4+ requires new authorization;
    this placeholder is a decision-tree pre-record, not Phase 4
    implementation.

ALIGNMENT.md scope check: docs-only commit (new ADR + index update).
No provider plugin / entry surface / IR change.

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 17:49:16 +10:00
c0b696984f docs: D48 — ADR 0008 Phase 3 design draft (Dashboard + audit query layer) (#25)
* docs: D48 — ADR 0008 Phase 3 design draft (Dashboard + audit query layer, design-only)

First Phase 3 D-day. Design-only. Ratifies the storage / query model /
rotation / dashboard / refresh / scope decisions ahead of D49+
implementation D-days. Opens ADR 0007 § 12 deferral for Dashboard +
audit query layer + rotation.

NEW docs/adr/0008-dashboard-and-audit-query.md (~368 lines): 13 sections
+ Consequences + Authority citations. Per maintainer-pinned lanes
A/A/B/A/B from Phase 3 kickoff brief 2026-05-25:

  Lane 1 (tech stack): A — static HTML + vanilla JS + fetch; no build
    step; matches OLP "no bundler" ethos.
  Lane 2 (query model): A — in-memory scan of audit ndjson per request;
    O(N) per call; family-scale acceptable; defers SQLite hybrid to
    Option 3 trigger per ADR 0007 § 13 (requires engines bump as
    separate prior PR).
  Lane 3 (rotation): B — daily rotation, audit-YYYY-MM-DD.ndjson on
    first append after UTC midnight + optional bin/olp-audit-rotate.mjs
    external cron.
  Lane 4 (refresh): A — 30s page poll (no SSE infra at v0.3.0;
    pause when document.visibilityState is hidden).
  Lane 5 (dashboard scope): B — full per spec § 4.6: 4 panels (per-
    provider quota / 24h request+cache+fallback / 30d spend trend /
    top-N fallback chains).

ADR sections:

  §1 Context (what Phase 3 closes; what stays out)
  §2 Decision (5 lanes pinned)
  §3 Storage layout (~/.olp/logs/ with rotated date files)
  §4 lib/audit-query.mjs API (readAuditWindow, aggregateRequests,
     topFallbackChains, spendTrendDaily, cacheHitRateWindow)
  §5 Audit rotation (first-append-after-UTC-midnight trigger + cron
     alternative + concurrent-safety per-process lock)
  §6 Dashboard panels (4 panels per spec § 4.6, refresh + localhost-
     bound notes)
  §7 Server endpoints (/dashboard, /v0/management/dashboard-data, /v0/
     management/quota, /cache/stats — owner-only gated)
  §8 Auth gating (reuses ADR 0007 § 7 owner_only_endpoints config)
  §9 Failure modes + degradation (per-panel error states)
  §10 Acceptance criteria (15 testable items for D49-D54)
  §11 Forward path (Phase 4+ — SQLite migration, SSE push, key-mgmt UI)
  §12 Out of scope (explicitly NOT in Phase 3)
  §13 Phase 3 sprint shape (D48-D55)

CHANGED:

  - docs/adr/README.md: added ADR 0008 row with one-paragraph summary.
  - CHANGELOG.md Unreleased: D48 entry per release_kit overlay
    phase_rolling_mode discipline. Includes Phase 3 sprint shape table.

NOT IN D48 scope:

  - lib/audit-query.mjs (D49)
  - server.mjs endpoints (D50)
  - dashboard.html (D51)
  - lib/audit.mjs rotation extension + bin/olp-audit-rotate.mjs (D52)
  - tried_providers schema fix (D53; D45 P2 deferral)
  - Phase 3 close (D55; v0.3.0; maintainer-triggered)

Test count: 544 / 544 pass (design-only, no test change). Verified
locally via npm test before commit.

AUTHORITY:

  - ADR 0007 § 12 (opens Phase 3 Dashboard + audit query deferral).
  - ADR 0007 § 13 (rejects SQLite at Phase 3 per Node baseline +
    documents forward-path trigger).
  - OLP v0.1 spec § 4.6 + § 4.7 (Dashboard + observability endpoints
    planning authority).
  - OCP dashboard.html (prior-art reference for multi-panel HTML
    structure).
  - ADR 0002 (Provider.quotaStatus contract — Panel 1 data source).
  - ADR 0005 § Cache stats (/cache/stats endpoint pre-existing design).
  - CC 开发铁律 v1.6 § 10 — fresh-context opus reviewer required for
    design ADR.
  - Phase 3 kickoff via maintainer "go" 2026-05-25 + standing-autopilot
    grant (~/.cc-rules/memory/auto/standing_autopilot_phase_2.md in
    cc-rules bf0ed9a — Phase 3+ requires new authorization; the "go"
    supplied that).

ALIGNMENT.md scope check: this PR introduces a new ADR with full
authority citations per Rule 1 (Cite First). No provider plugin /
entry surface / IR change in this commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: D48 fold-in — opus reviewer findings (1 P2 + 2 P3, all ADR-text polish)

Fresh-context opus reviewer (PR #25) returned APPROVE_WITH_MINOR with 3
findings, all ADR-text polish. No design semantic change beyond the
clarifications.

P2 — § 8 + § 10 #9 gating-mode wording

  Original § 8 implied a new "block non-owner identities" behaviour
  without naming it; § 10 #9 tested only the universal
  allow_anonymous: false 401 case. Fix:
  - § 8 now formalizes two gating modes — owner_only_trim (Phase 2
    /health pattern) vs owner_only_block (new Phase 3 management-
    endpoints pattern) — and explains the management endpoints are
    owner_only_block because the entire payload is sensitive.
  - § 10 #9 now covers both 401 paths: (a) allow_anonymous: true
    + no header → anonymous identity → STILL 401 because management
    endpoints are owner_only_block; (b) allow_anonymous: false + no
    header → 401 at the authenticate middleware itself.

P3 #1 — /cache/stats citation accuracy

  Original § 7.4 + Authority block cited "ADR 0005 § Cache stats"
  which is not a real section. Corrected: planning authority is OLP
  v0.1 spec § 4.6; ADR 0005 references the endpoint in
  Consequences/Mitigations (~line 279) for the per-(provider, model)
  cache-hit-rate breakdown surface.

P3 #2 — cacheStore.stats() shape gap

  § 7.4 now explicitly acknowledges the current shape
  ({ hits, misses, size, inflightCount } global aggregate) lacks the
  per-(provider, model) breakdown spec § 4.6 implies; Phase 3 Panel 2
  sources per-provider counts from aggregateRequests (audit-side)
  instead. If a future panel needs the breakdown, D50 amends the
  store shape + an ADR 0005 amendment fires at that time. Phase 3
  acceptance criteria do not require the breakdown.

CHANGELOG.md Unreleased D48 entry: fold-in bullet added enumerating
the 3 fixes.

Test count: 544 / 544 pass (design-only, no test change). Verified
locally via npm test.

Authority: PR #25 fresh-context opus reviewer findings; CLAUDE.md
release_kit overlay phase_rolling_mode — under Unreleased.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 15:41:26 +10:00
d253c2b98d docs: D43-B — ADR 0007 multi-key auth design draft (design-only) (#19)
* docs: D43-B — ADR 0007 multi-key auth design draft (design-only, no code change)

Phase 2 mainline design ADR. Ratifies the storage / token / manifest /
atomic-write / owner-gating / bootstrap / Node-baseline decisions ahead
of D44+ implementation D-days.

Pure design doc — no .mjs / no tests / 4 files touched. Test count
468 → 468.

- docs/adr/0007-multi-key-auth.md (new, ~400 lines): 13 sections
  covering Context / Decision (Option 2 filesystem manifest + opaque
  token) / Storage layout / Manifest schema / Token format (olp_+32B
  base64url, SHA-256 hash) / Atomic write & audit append (manifest
  lifecycle-only atomic via tmpfile+fsync+rename; audit per-request
  append with warn+1-retry, no memory buffer at Phase 2) / Owner-vs-
  guest-vs-anonymous gating (config.json auth.allow_anonymous default
  false, no env auto-detection) / Audit ndjson schema (no PII) /
  Bootstrap & recovery (minimal keygen command surface +
  OLP_OWNER_TOKEN env override with stable __env_owner__ keyId) /
  Acceptance criteria (11 test surfaces) / Node baseline (Option 1
  SQLite port rejection rationale citing engines >=18 + CI 20/24 vs
  node:sqlite v22.5.0/RC) / Out of scope (Dashboard, quota
  enforcement, audit query, file locking deferred to Phase 3+) /
  Future forward (Option 3 hybrid migration trigger + preconditions).

- docs/adr/README.md index: added ADR 0007 row with one-paragraph
  summary covering storage choice + rejection rationale.

- docs/v1x-roadmap.md #2: marked PHASE 2 ACTIVE (no longer deferred);
  "Design ADR (NOT YET RATIFIED)" → "Design ADR (ratified) → ADR
  0007"; trigger updated to "already fired 2026-05-25"; code anchors
  pinned to exact line numbers (cache/store.mjs:77-79/:287, server
  .mjs:502/:531/:392/:1072/:1101).

- CHANGELOG.md Unreleased: D43-B entry per release_kit overlay
  phase_rolling_mode discipline.

Authority:
- Phase 2 kickoff handoff (~/.cc-rules/memory/handoffs/2026-05-25-phase-2-kickoff.md, cc-rules d9da966)
- OLP v0.1 spec § 4.5 (planning authority for ~/.olp/ layout)
- OCP keys.mjs (prior-art for opaque-key + per-key isolation model)
- Node node:sqlite docs (https://nodejs.org/api/sqlite.html — Option 1 rejection per ADR 0007 § 11)
- CC 开发铁律 v1.6 § 10 — fresh-context opus reviewer required for design ADR per Iron Rule 10

ALIGNMENT.md scope check: this PR introduces a new ADR; per ALIGNMENT.md
Rule 1 (Cite First), the ADR itself contains the authority citations
its decisions rest on (v0.1 spec § 4.5, OCP keys.mjs, Node docs URL).
No provider plugin / entry surface / IR change in this commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: D43-B fold-in — ADR 0007 reviewer findings (2 P2 + 3 P3, all polish)

Fresh-context opus reviewer (PR #19) returned APPROVE_WITH_MINOR with 2 P2
load-bearing-but-non-blocking findings + 3 P3 polish findings. All five
are accepted as suggested; design contract clarified without semantic
change.

- § 6.2 step 1 (P2 #1) — pin audit serialization to fire AFTER status_code
  is determined and latency_ms is measured. Makes acceptance criterion #2
  (anonymous-401 audit event records the 401 + latency) testable in the
  way the criterion was written.

- § 6.3.5 (P2 #2, new subsection) — explicit "Token validation MUST hit
  the manifest on every authenticated request (no in-process validation
  cache at Phase 2)" rule. The acceptance criterion #6 (post-revoke 401
  within the next request) was previously enforced only by the test; the
  rule now belongs to the design contract. Forward-path note documents
  when a Phase 3+ amendment may add a cache.

- § 6.1 atomic-write step 5 follow-up (P3 #3) — document the deliberate
  omission of directory fsync after rename. Single-process family-scale
  deployment accepts the tiny rename-loss window under abrupt host crash;
  future POSIX-strict deployments know where to add the step.

- § 9.4 (P3 #4) — declare token-collision between OLP_OWNER_TOKEN and
  a filesystem-stored key's plaintext as undefined behaviour. Operators
  MUST NOT reuse plaintext across both surfaces. Phase MAY add startup
  collision-detection later.

- § 10 criterion #4 (P3 #5) — rephrased to assert against the config-
  driven owner_only_endpoints predicate rather than a hardcoded trimmed
  payload shape. The test stays stable if an operator removes /health
  from owner_only_endpoints.

CHANGELOG D43-B entry: fold-in bullet added to summarize the 5 fixes.

Test count: 468 → 468 (npm test verified locally after fold-in).

Authority: PR #19 fresh-context opus reviewer findings; CLAUDE.md
release_kit overlay phase_rolling_mode — under Unreleased.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: D43-B fold-in #2 — maintainer text-review findings (1 P1 + 1 P2 + 1 P3)

Maintainer (codex) did final text review of PR #19 against the Phase 2
ADR-ratification checklist. Returned 3 findings; all accepted as
suggested. Two are contract-level (P1 safety + P2 factual); one is
trivial (P3 line-count drift). No semantic change beyond what the
findings called out.

P1 — § 6.3 / § 6.4 / § 10 #7 — revoke-dominates-touch safety contract

  Original § 6.3 said touchLastUsed used the same atomic-write pattern
  as 6.1; § 6.4 said concurrent CLI revoke + touchLastUsed left "both
  states valid" with "observability-grade" failure mode. Codex correctly
  identified the bug: a stale manifest snapshot held by the touch path
  could overwrite a fresh revoke and silently clear revoked_at back to
  null, breaking acceptance criterion #6 (post-revoke 401 within next
  request) under concurrent CLI revoke + in-flight server request. The
  ADR was promising security-grade behavior on a path that was actually
  last-write-wins.

  Fix:
  - § 6.3 rewritten with explicit read-modify-write discipline: touch
    MUST re-read latest manifest from disk inside the per-key write-lock,
    NO-OP if revoked_at is non-null, otherwise merge last_used_at
    preserving all other fields including revoked_at.
  - § 6.4 reframed from "both states valid" to "revoke dominates touch"
    safety frame, citing § 6.3 as the load-bearing discipline. The
    CLI revoke writer always wins the dimension that matters; touch
    may lose its last_used_at update if it raced.
  - § 10 criterion #7 expanded to test all three orderings (revoke
    -> touch, touch -> revoke, interleaved) with the explicit MUST:
    revoked_at is non-null and equals the revoke writer's timestamp
    after any interleaving; FAIL if any path produces revoked_at: null.
  - Forward-path § 6.4 file-locking note updated to clarify §6.3
    already holds the contract single-process; flock adds defense-in-
    depth for rare multi-writer TOCTOU.

P2 — § 11 forward path step (1) — Node baseline version history corrected

  Original wording "Node v22.5.0+ for unflagged but RC; Node TBD for
  stable" was wrong. v22.5.0 added with --experimental-sqlite flag;
  v22.12 still required the flag; the module moved past flag-gating
  in v22.13.0 (LTS) / v23.4.0 (current); entered Release Candidate at
  v25.7.0 per current docs.

  Fix: § 11 forward path step (1) rewritten with accurate versions +
  two Node release-history URLs cited (https://nodejs.org/download/
  release/v22.12.0/docs/api/sqlite.html and https://nodejs.org/api/
  sqlite.html). Minimum non-flag-gated baseline is now stated as
  >=22.13.0 (LTS) / >=23.4.0 (current); stable baseline TBD pending
  Node v25.x+. The rejection-evidence paragraph earlier in § 11
  ("v22.12 still required --experimental-sqlite ... current docs mark
  RC") was already correct and is untouched.

P3 — CHANGELOG D43-B line-count corrected

  Entry said ADR was "~270 lines"; actual file is 420 lines after both
  fold-ins. Changed to "~420 lines after fold-ins". Phase 2 fold-in #2
  bullet enumerates the 3 fixes in this commit; fold-in #1 bullet
  retained for the opus reviewer round.

Test count: 468 / 468 (npm test verified locally after fold-in;
design-only doc changes, no test file touched).

Authority: PR #19 maintainer text review findings 2026-05-25; CLAUDE.md
release_kit overlay phase_rolling_mode — under Unreleased; Node SQLite
docs URLs cited in ADR § 11 forward path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 12:56:35 +10:00
taodengandClaude Opus 4.7 (noreply@anthropic.com) dff428f3d0 docs(governance): fold in codex round-2 review findings (6 issues)
External Codex CLI review pass 2 surfaced 6 substantive issues that
round 1 fold-in missed — the self-consistency trap recurred when fold-in
was scoped only to files codex explicitly named in round 1. This commit
closes round 2 in full.

1. ADR 0002 contradicted ALIGNMENT.md (P1, codex round 2 finding 1)
   ADR 0002 still said "three default-enabled (Anthropic, OpenAI Codex,
   Mistral Vibe)" while ALIGNMENT.md (post round 1) said v0.1 ships zero
   Enabled Providers. Accepted ADR contradicted constitution.
   Fix: ADR 0002 + ADR 0001 + docs/adr/README.md index rewritten to
   Candidate framing.

2. release.yml would publish stale v0.1.0-bootstrap notes (P1, round 2
   finding 2)
   The "Unreleased" amendments would have been silently dropped on tag
   push because release.yml extracts only the matching version section.
   Fix: CHANGELOG restructured so the amended state IS the v0.1.0-
   bootstrap section. Full review history (opus + 2 codex rounds)
   captured inline.

3. package.json advertised non-existent entrypoints (P2, round 2
   finding 3)
   main/scripts.test/scripts.start pointed to files that do not exist.
   Local npm test and npm start failed; CI masked.
   Fix: remove all three from package.json. They return in Phase 1
   alongside the real files. test.yml bootstrap-tolerance updated to
   also skip when scripts.test is absent.

4. models-registry.json missing despite SPOT claim (P2, round 2
   finding 4)
   Fix: minimal stub committed (version + empty providers map).
   alignment.yml validator now actually runs.

5. alignment.yml commit-citation soft check Bash subshell trap (P2,
   round 2 finding 5)
   git log ... while read ... WARN=1 — the while loop ran in a subshell
   because of the pipe, so WARN never propagated out. The post-loop
   check always reported "clean" even when warnings fired.
   Fix: process substitution done less than less than (git log ...).

6. Tier A "permanent" wording inconsistent across ADR 0006 + alignment.
   yml workflow text (P3, round 2 finding 6)
   Fix: unified to "Excluded by default with no routine reinstatement
   path; re-inclusion requires ADR 0006 supersession or amendment with
   new primary-source evidence."

Reviewer: OpenAI Codex CLI (external, fresh-context, pass 2). Iron Rule
10 satisfied — round 2 reviewer was not the implementer of round 1
fold-in.

Memory learning updated: the self-consistency trap recurs in the fold-in
step. Future fold-ins must grep the entire repo for the concept, not
only edit files the reviewer named. See learnings/ai_reviewer_self_
consistency_trap.md in cross-machine memory.

Co-Authored-By: Claude Opus 4.7 (noreply@anthropic.com)
2026-05-23 16:35:23 +10:00
taodengandClaude Opus 4.7 0041fb1017 chore: bootstrap OLP v0.1 — multi-provider LLM proxy
Initial release. OLP (Open LLM Proxy) is a personal- and family-scale
multi-provider LLM proxy that supersedes OCP (Open Claude Proxy).

Trigger: Anthropic's 2026-05-14 announcement (effective 2026-06-15)
moves `claude -p` / Agent SDK / third-party agent traffic out of the
Pro/Max subscription pool into a separate fixed monthly Agent SDK
Credit pool. OCP's foundational assumption ("subscription = unlimited
within rate limits") breaks for Anthropic on that date. Spreading
risk across multiple providers is the structural response.

Phase 0 lands:
- ALIGNMENT.md (constitution: 5 Rules, 3 Authorities, 4-tier Risk
  Framework, 8-provider inventory)
- AGENTS.md (multi-tool agent guidelines; inherits cc-rules)
- CLAUDE.md (Claude-Code session instructions + release_kit overlay)
- README.md (phase-aware skeleton)
- docs/adr/0001-0006 (Founding ADRs: project founding / plugin
  architecture / IR design / fallback engine / cross-provider cache /
  provider inclusion + risk-tier framework)
- .github/PULL_REQUEST_TEMPLATE.md (8-radio Change Type + per-type
  Authority Evidence + Iron Rule 10 reviewer checklist)
- .github/workflows/alignment.yml (blacklist + Antigravity exclusion
  enforcement + models-registry validator + commit-citation soft check)
- .github/workflows/release.yml (auto-release on tag with version
  match check per Iron Rule 5)
- .github/workflows/test.yml (Node 20/24 matrix, bootstrap-tolerant)
- package.json, .gitignore, LICENSE (MIT), CHANGELOG.md

Provider inventory at bootstrap:
  Tier D (default-enabled):       anthropic, openai, mistral
  Tier C (opt-in):                grok, kimi
  Tier B (opt-in + consent):      minimax, glm, qwen
  Tier A (permanently excluded):  google-antigravity

Supersedes OCP ADR 0005 (No Multi-Provider) per OLP ADR 0001. OCP
will enter maintenance mode when OLP v0.1 ships per Phase 7 plan.

Iron Rule 10 gate: fresh-context independent opus reviewer audited
all 15 governance files against OLP v0.1 spec + OCP precedent.
Verdict: APPROVE_WITH_MINOR. Two minor findings folded in:
  1. alignment.yml heredoc EOF moved to column 0 (was indented;
     bash parse failed silently on real blacklist hits, printing
     a cryptic "syntax error" instead of the structured ALIGNMENT
     GUARDRAIL FAILURE banner).
  2. AGENTS.md clarified that the SPOT discipline for
     models-registry.json will be codified by a Phase-1 ADR (OLP
     ADR 0003 is currently the IR design, not a SPOT codification;
     OCP's ADR 0003 is the precedent but OLP's registry shape
     differs and warrants its own ADR).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 15:46:56 +10:00