docs: D79 — Phase 5 constitutional layer (ADR 0012 + ADR 0002 Amendment 8 + ADR 0013) (#50)

* docs: D79 — Phase 5 constitutional layer (ADR 0012 + ADR 0002 Amendment 8 + ADR 0013)

Three coupled governance documents land together as the Phase 5 constitutional
layer (Iron Rule 11 IDR — reviewing them separately cannot verify
consumer-producer alignment). Phase 5 opens 2026-05-26; D79 is governance-only,
no code changes.

- ADR 0012 (Phase 5 charter) — port OCP's plan-usage probe to
  `lib/providers/anthropic.mjs:quotaStatus()` (D80) + extend
  `/v0/management/dashboard-data` for new shape (D81) + Claude.ai-style
  dashboard restructure with 1-min auto-refresh + manual refresh (D82) +
  Suite 38/39 tests (D83) + optional mistral probe at D84 (codex skipped —
  no public API) + v0.5.0 close (maintainer-triggered). ~6 D-days.

- ADR 0002 Amendment 8 (direct-API READ-ONLY exemption) — plugin contract
  amendment permitting quotaStatus() to call provider HTTP APIs directly,
  subject to three constraints: READ-ONLY (no mutating calls),
  subscription-scope (reuses spawn-path credentials), idempotent failure
  (returns null on any error, never throws). No other contract method gains
  this permission.

- ADR 0013 (OAuth READ-ONLY consumption + schema-drift mitigation) —
  implementation discipline for ADR 0002 Amendment 8. Seven rules: (1)
  credential reuse via plugin's readAuthArtifact(), (2) READ-ONLY at wire
  (max_tokens:1, headers-only parse, body discarded), (3) cache TTL 5min +
  60s-3600s exponential refresh backoff + stale-cache-on-failure, (4)
  opt-in via `~/.olp/config.json providers.<name>.quota_probe_enabled`
  (default false), (5) schema-drift mitigation via dual-path verification
  (compiled-binary `strings` + live API probe diff), (6) failure
  transparency through `olp doctor` + dashboard staleness markers, (7)
  explicit out-of-scope clarifications.

Pre-flight institutional-knowledge audit (Iron Rule 12 prior-art search)
captured at `~/.cc-rules/memory/learnings/anthropic_plan_usage_probe_schema_2026_05_26.md`
(cross-machine git-sync). Findings:

- OCP probe (server.mjs:842-1109) still works against current
  api.anthropic.com — tested live from PI231 OAuth credentials 2026-05-26.
- 13 `anthropic-ratelimit-unified-*` response headers confirmed
  (3 new since OCP 2026-04 capture: 5h-status, 7d-status, overage-reset;
  no removals or renames).
- Claude Code v2.1.x is now distributed as compiled native binary
  (Mach-O on macOS, ELF on Linux) — OCP's "grep cli.js" verification is no
  longer applicable. ADR 0013 Rule 5 replaces with dual-path verification
  (`strings` over the binary + live API probe diff).
- OAuth refresh path (platform.claude.com/v1/oauth/token + client_id
  9d1c250a-...) all unchanged.

Authority:
- ALIGNMENT.md Rule 1 (citation): audit memory + OCP server.mjs:842-1109 +
  live `/v1/messages` probe transcript 2026-05-26.
- ALIGNMENT.md Rule 2 (provider-CLI-as-authority): Amendment 8 documents the
  exemption; the probe mirrors observed CLI behaviour.
- ALIGNMENT.md Rule 5 (CI alignment.yml): not triggered (docs/ excluded by
  workflow `paths:` filter); blacklisted `/api/oauth/usage` token referenced
  only as meta-references ("must continue to blacklist").
- CLAUDE.md release_kit overlay: Phase 5 open; D-day commits stay under
  "Unreleased" until maintainer-triggered v0.5.0 close.

Iron Rule 10: fresh-context reviewer required before merge per CLAUDE.md
hard requirement #3.

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

* docs: D79 fold-in — 6 in-PR nits from fresh-context reviewer (PR #50)

Reviewer verdict: APPROVE_WITH_MINOR (0 blocking, 9 nits — 6 in-PR, 3 outside-PR).
Folding in the 6 in-PR nits here; the 3 outside-PR ones (audit-memory chronology,
audit-memory D80/D81 mapping, ALIGNMENT.md cross-ref to Amendment 8) are deferred.

Folded-in nits:

1. ADR 0002 Amendment 8: added a 5th "does NOT permit" bullet making per-endpoint
   containment explicit. Amendment 8 permits the kind of call; ADR 0013 Rule 2
   enumerates which specific endpoint. Re-opening per-endpoint scope requires an
   ADR 0013 amendment, not a Amendment-8-only interpretation.

2. ADR 0013 Rule 5: added "Path A prerequisites" paragraph documenting that
   strings (GNU/BSD binutils/coreutils) + Claude Code v2.1.x install are required
   for compiled-binary verification. Windows reviewers need WSL or binutils-mingw.

3. ADR 0013 Rule 5: added "Trigger for re-running the diff" paragraph naming three
   explicit hooks for major-version-bump detection: Annual Alignment Audit
   (14 May), olp doctor anthropic.quota_probe_reachable failure, manual
   maintainer attention. Documented graceful-degradation failure mode.

4. ADR 0012 D80 estimate: 1.5d → 2d. Reviewer flagged 1.5d as optimistic
   compared to D61-D63 (2.5d for narrower SSE heartbeat scope). Aligning.

5. ADR 0012 D84: moved Mistral GO/NO-GO spike to D79 close (before D80 starts),
   not mid-phase. Reduces mid-phase scope drift risk. Outcome will be amended
   into this charter as a D79-close amendment.

6. ADR 0012 Authority + cross-references: replaced "Claude Code <version> §
   OAuth bearer + ratelimit headers" with "compiled-binary strings evidence
   per audit memory § Path A". Claude Code v2.1.x has no traditional section
   structure because it is a Mach-O / ELF compiled binary.

Deferred (outside-PR) nits documented in PR review thread:
- Audit memory historical-table chronology error (cb6c2a8 placed last; was
  second chronologically — narrative arc still holds, dates need correction).
- Audit memory D80/D81 mapping mismatch (memory says D81 adds new fields;
  ADR 0012 says D80 parses all 13).
- ALIGNMENT.md cross-reference to Amendment 8 (Class-specific Exceptions
  subsection should name Amendment 8 explicitly).

All three outside-PR items are docs-only and not load-bearing for D80
implementation. Will fold in either at D80 commit (audit-memory updates)
or as a tiny constitutional cleanup PR (ALIGNMENT.md cross-ref).

Iron Rule 10: reviewer was a fresh-context opus subagent; their full review
is recorded in PR #50 thread.

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>
This commit is contained in:
dtzp555-max
2026-05-26 16:30:09 +10:00
committed by GitHub
co-authored by taodeng Claude Opus 4.7
parent 704d4fc8a0
commit 1605400052
5 changed files with 356 additions and 1 deletions
@@ -0,0 +1,127 @@
# ADR 0012 — Phase 5 Charter: Provider Quota Probes + Dashboard Enrichment
**Status:** Accepted (Phase 5 open as of 2026-05-26)
**Date:** 2026-05-26
**D-day:** D79 (charter + ADR 0002 Amendment 8 + ADR 0013 land together as the constitutional layer of Phase 5)
---
## Context
Phase 4 (ADR 0010) shipped OLP's operator + client UX layer — `bin/olp` operator CLI, `olp doctor` framework, `olp-connect` zero-config IDE wiring, OpenClaw `/olp` slash commands, anonymous-key deployment-context limits, SSE heartbeat. v0.4.4 is the current shipped state. Phase 4 closed every gap on the OCP-feature-parity matrix EXCEPT one: **live quota / plan-usage surfacing**.
Today `lib/providers/anthropic.mjs:445` has a stub `quotaStatus()` returning `null` (D4 placeholder). The OLP dashboard's quota panel renders "—" for all providers. OCP, in contrast, exposes a live "39% session / 30% weekly" panel — the maintainer uses this multiple times per day to decide when to throttle voluntary `claude -p` traffic away from interactive sessions. OLP cannot become an OCP successor in practice (vs. just feature-parity-on-paper) until quota surfacing works.
A pre-flight institutional-knowledge audit (2026-05-26 — see `~/.cc-rules/memory/learnings/anthropic_plan_usage_probe_schema_2026_05_26.md`) confirmed:
1. **The OCP probe still works today** — Anthropic returns the same `anthropic-ratelimit-unified-*` headers on every `POST /v1/messages` call. Tested live 2026-05-26 from PI231 OAuth credentials.
2. **Schema added 3 fields since OCP's 2026-04 capture**`5h-status`, `7d-status` (per-window status), `overage-reset` (only on active overage). No fields removed or renamed.
3. **Verification protocol has shifted** — Claude Code v2.1.x is now a **compiled binary** (Mach-O / ELF), not bundled JS. OCP's "grep cli.js" approach no longer applies; the replacement protocol is `strings` against the binary + periodic live probe diff.
4. **OAuth refresh path unchanged**`platform.claude.com/v1/oauth/token` + `9d1c250a-...` client_id + 60s-3600s exponential backoff.
The audit makes Phase 5 implementation low-risk: this is a port of a working OCP function, not a re-derivation. The work is mechanical + adapter-layer plumbing into OLP's plugin contract.
A parallel maintainer request (2026-05-26, with reference screenshot of claude.ai/settings/usage) asked for Claude.ai-style dashboard enrichment: per-row utilization bars, reset countdown, 1-minute auto-refresh, manual refresh button. P5-1 (probe) + P5-2 (dashboard) together unlock both: the data plus the surface. v1.x roadmap #8 is closed by P5-2.
---
## Decision
Phase 5 scope is **Provider quota probes + dashboard enrichment**. The phase opens 2026-05-26 with D79 (this charter + ADR 0002 Amendment 8 + ADR 0013 OAuth READ-ONLY consumption rules). Phase 5 close ships v0.5.0; per `CLAUDE.md release_kit.phase_rolling_mode`, the close PR is maintainer-triggered.
### In scope — Phase 5 D-day plan (~6 D-days)
| D-day | Deliverable | Authority | Estimate |
|---|---|---|---|
| **D79** | This charter ADR 0012 + ADR 0002 Amendment 8 (direct-API READ-ONLY) + ADR 0013 (OAuth READ-ONLY consumption rules + schema-drift mitigation) + `package.json` `current_pre_release_identifier``0.5.0-phase5` + `CLAUDE.md release_kit.phase_rolling_mode.current_phase` → Phase 5 | This charter + audit memory | 0.5d |
| **D80** | `lib/providers/anthropic.mjs:quotaStatus()` ported from OCP `server.mjs:842-1109` — full probe with macOS-keychain auth read added (existing OLP reader only handles env + `.credentials.json`) + 5min cache + 60s-3600s refresh backoff + stale-cache-on-429 + all 13 headers parsed (including new 5h-status / 7d-status / overage-reset) | Port OCP probe + ALIGNMENT.md Rule 2 exemption per ADR 0002 Amendment 8 + audit memory | 2d |
| **D81** | `lib/audit-query.mjs` + `/v0/management/dashboard-data` extended to surface the new quota shape per provider (utilization, reset, representative-claim, fallback-percentage, overage-status). Audit-query stays in-memory scan per ADR 0008 Lane 2 = A (no SQLite). Schema migration documented in ADR 0008 § Amendment | ADR 0008 + this charter | 1d |
| **D82** | `dashboard.html` Claude.ai-style restructure — per-provider rows replace the current single Quota panel; each row: provider badge, model placeholder, utilization bar (5h + 7d), reset countdown ("Your limit will reset at HH:MM AM/PM" format from the user-shared claude.ai screenshot), status badge, representative-claim hint. 1-minute auto-refresh via `setInterval` with `document.visibilityState` guard. Manual refresh button calls `/v0/management/dashboard-data` directly | v1.x roadmap #8 + maintainer reference screenshot | 1.5d |
| **D83** | Test coverage — Suite 38 quota-probe unit tests (mock HTTP server returning the 13 headers; assert parse + cache + backoff + stale-on-429); Suite 39 dashboard rendering smoke (curl `/dashboard` after pre-seeding mock quota cache; assert HTML contains expected utilization strings); update Suite 33 doctor checks for new `anthropic.quota_probe_reachable` check | Test convention from existing suites | 1d |
| **D84** | (optional) `lib/providers/mistral.mjs:quotaStatus()` — Mistral GO/NO-GO decided at D79 close (30-min docs spike before D80 starts), NOT mid-phase. If Mistral exposes `/v1/usage` or equivalent → D84 ports the probe with a parallel ADR 0002 Amendment 8 invocation. If NOT exposed → D84 is dropped from the plan and mistral row shows "spend tracking only" badge sourced from audit-query. Codex explicitly skipped — `openai/codex` CLI has no public quota API. GO/NO-GO outcome documented in this charter as a D79-close amendment | Live audit at D79 close (~30 min spike) | 0.5d if GO; 0d if NO-GO |
| **close** | v0.5.0 release PR — `package.json` `0.4.4 → 0.5.0`, CHANGELOG promotion, `release_kit.phase_rolling_mode.current_pre_release_identifier` advance to Phase 6 token | `CLAUDE.md release_kit overlay` | maintainer-triggered |
### Out of Phase 5 scope (with explicit triggers)
#### `X-OLP-Cost-USD` per-request response header
**Status:** Deferred to Phase 6. Was listed in ADR 0010 § Out-of-scope as "Phase 5 prerequisite". The prerequisite (provider-cost weights table) is non-trivial — needs per-(provider, model) `input_cost_per_1k_tokens` / `output_cost_per_1k_tokens` / `cache_read_discount` data sourced from each provider's published pricing page. Phase 5 already pulls in two new ADRs; adding a third data-onboarding ADR is scope creep.
**Re-open condition.** Phase 6 unless a maintainer reports a cost-attribution debugging need that warrants pulling forward.
#### `context_window_exceeded` fallback trigger (LiteLLM prior-art)
**Status:** Deferred. ADR 0010 listed this as opportunistic-in-Phase-5 unless the trigger fires sooner. The trigger has not fired in Phase 4 production traffic. Continue to defer.
#### per-(provider, model) live stats Map (replacing audit-query scan)
**Status:** Deferred. Current scan latency is ~20ms at 7-day depth. Acceptable until volume grows (>100k requests/day). Re-evaluate at Phase 6 if dashboard latency degrades.
#### Anthropic interactive-mode P0 (ADR 0009)
**Status:** Still trigger-gated on Anthropic's 2026-06-15 billing-split rollout. Phase 5 does NOT depend on P0 — the quota probe reads `anthropic-ratelimit-unified-*` headers regardless of which billing pool the spawn path consumes. If P0 succeeds Phase 7+ Phase 5's probe code remains unchanged; if P0 fails Phase 5's probe code remains unchanged. The probe is billing-pool-agnostic because the headers are subscription-pool metadata, not Agent-SDK-Credit metadata.
#### `/v1/messages` Anthropic-shape entry surface
**Status:** Still deferred per ADR 0010 § Out-of-scope. No change in Phase 5.
#### v1.x roadmap #3 / #5 / #6
**Status:** Still trigger-gated per `docs/v1x-roadmap.md`. None has fired. Continue to defer.
### Opportunistic Phase 5 micro-additions (not blocking)
Items small enough to land alongside a planned D-day without scope creep, if encountered:
- README § Dashboard screenshot update (post-P5-2 enrichment) — capture from MacBook test path per `~/.cc-rules/memory/feedback/mac_mini_never_for_testing.md`.
- `olp usage` CLI subcommand (bin/olp.mjs) surfaces the parsed quota shape in terminal form. Already partially exists (cmdUsage in bin/olp.mjs); confirm payload alignment after D80.
- Add `claude_code_oauth_client_id` config override in `~/.olp/config.json` so power users can override the hardcoded `9d1c250a-...` UUID without env-var fiddling. Mirrors compiled binary's `CLAUDE_CODE_OAUTH_CLIENT_ID` env support.
- `docs/provider-audits/anthropic.md` re-capture with current `claude --version` (v2.1.142 MacBook / v2.1.150 PI231) + binary distribution layout note.
### Exit gate — v0.5.0 close criteria
1. D79 — D84 all merged with fresh-context opus reviewer APPROVE per Iron Rule 10.
2. CI green on every D-day merge commit and on the v0.5.0 release commit head. `alignment.yml` blacklist re-confirmed (no new hallucinated tokens introduced).
3. README § Quota / Plan Usage section present with screenshot of the enriched dashboard. README § Supported Providers table updated to note "quota probe: anthropic ✅, mistral ⚠️/✅ (D84 outcome), codex ❌ (no public API)".
4. ADR 0012 (this charter) + ADR 0002 Amendment 8 + ADR 0013 (OAuth READ-ONLY consumption) on disk.
5. `CHANGELOG.md "Unreleased"` promoted to `"## v0.5.0 — <date>"` with D79 — D84 entries.
6. `package.json` bumped to `0.5.0`.
7. `CLAUDE.md release_kit.phase_rolling_mode.current_phase` advances `Phase 5 → Phase 6`; `current_pre_release_identifier` advances `0.5.0-phase5 → 0.6.0-phase6`.
8. Standing autopilot grant covers D-day-by-D-day execution; v0.5.0 close PR is maintainer-triggered.
9. Live MacBook E2E verification — dashboard renders enriched panel with real quota data (probe live, not mocked).
---
## Consequences
**Positive.**
- OLP finally has the load-bearing observability OCP had — maintainer can see live "39% session / 30% weekly" and decide whether voluntary `claude -p` traffic stays or moves.
- Family members on the LAN see real reset times instead of "—", which makes the "wait 2 hours" guidance concrete vs. abstract.
- The institutional-knowledge audit captured the schema in a memory file pinned with date stamps — future ports (mistral, future provider) re-use the verification protocol without re-deriving.
- v1.x roadmap #8 (Dashboard enrichment per Claude.ai-style usage page) closes inside Phase 5 rather than waiting for a separate phase.
- Compiled-binary-distribution awareness ("no more cli.js to grep") is now codified in OLP governance; the next time Anthropic ships a major CC version, the verification protocol is already written.
**Negative.**
- ADR 0002 gains another amendment (Amendment 8). The constitution surface area for `anthropic.mjs` grows. Counter-pressure: the alternative (probe lives in `server.mjs`, like OCP) violates the plugin-architecture principle that per-provider knowledge stays in `lib/providers/`. Amendment 8 is the smaller violation.
- The probe makes one `/v1/messages` call per 5min cache miss. That's ~12 calls/hour worst case across the whole proxy (probe is per-credentials, not per-key). With `max_tokens: 1` the cost is < $0.01/day at family-scale traffic. Negligible but not zero.
- Schema-drift risk over the long horizon. Anthropic could rename or remove headers in a future version. The mitigation protocol (strings + live probe diff) is in place, but it's a manual check — needs to be invoked by the maintainer or scheduled.
- Dashboard refactor introduces a breaking-change risk for the existing dashboard.html consumers (none today, but conceptually). Bumping to v0.5.0 signals this clearly.
**Neutral.**
- Phase 5 has more ADR work than Phase 4 (3 governance docs vs. 2). The constitutional layer is deliberately heavier because direct-API access is the single biggest authority decision since the plugin contract itself.
---
## Authority + cross-references
- **Iron Rule 11 (IDR)** — Phase 5 ships across 6 D-days, each a minimum reviewable unit. The governance trio (this ADR + Amendment 8 + ADR 0013) lands at D79 as a single coupled commit (reviewing them separately cannot verify consumer-producer alignment), per ADR 0002 Amendment 7's precedent.
- **Iron Rule 12 (prior-art search)** — discharged via the audit memory at `~/.cc-rules/memory/learnings/anthropic_plan_usage_probe_schema_2026_05_26.md`. Memory committed prior to D80 implementation.
- **ALIGNMENT.md Rule 1 (citation)** — D80 commit must cite compiled-binary `strings` evidence per audit memory § Path A (Claude Code v2.1.x has no traditional `§ section` structure because it is a Mach-O / ELF compiled binary) plus the audit memory file path. Live-probe transcript MUST be included in the commit body.
- **ALIGNMENT.md Rule 2 (provider-CLI-as-authority)** — direct-API access bypasses the spawn-binary contract. Amendment 8 is the explicit exemption. Without Amendment 8, the D80 commit is unalignable.
- **ALIGNMENT.md Rule 5 (CI alignment.yml)** — must continue to pass. `api.anthropic.com/v1/messages` is NOT on the blacklist (correct — that's the real endpoint). The hallucinated `/api/oauth/usage` IS on the blacklist (transitive from OCP) and must remain.
- **ADR 0002 Amendment 8** — companion ADR. Direct-API access scoping; READ-ONLY constraint; opt-in via config flag (default off).
- **ADR 0013** — companion ADR. OAuth credentials shared between spawn path + probe path; refresh backoff; schema-drift mitigation protocol.
- **CLAUDE.md release_kit** — Phase boundary triggers maintainer-led version bump. D-day commits within Phase 5 stay under "Unreleased". `0.5.0-phase5` is the pre-release identifier during the phase.