* 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>
Architecture Decision Records — OLP
This directory holds the OLP Architecture Decision Records (ADRs) — short documents that capture the why behind structural choices.
Read these before proposing governance, plug-in contract, IR, fallback, cache, or provider-inclusion changes.
Numbering
ADRs in OLP start at 0001 (the project's founding decision). OLP did not inherit the 0001 placeholder convention OCP used; the project starts on a fresh numbering line.
New ADRs increment from the highest existing number. Filenames are NNNN-<short-slug>.md.
Index
| ADR | Title | What it covers |
|---|---|---|
| 0001 | Project Founding | Why OLP exists (the 2026-06-15 Anthropic billing-split trigger), mission + non-mission boundaries, explicit supersession of OCP ADR 0005 "No Multi-Provider". |
| 0002 | Plugin Architecture for Providers | The lib/providers/<name>.mjs plug-in model, the Provider contract (name / models / auth / spawn / estimateCost / quotaStatus / healthCheck / hints), static in-tree registry, why-not full external plugin discovery. |
| 0003 | Intermediate Representation (IR) Design | The OLP-internal canonical request/response shape between the OpenAI-compat entry surface and each provider plugin. v1.0 IR fields, IR-vs-OpenAI-vs-native-provider three-shape model, IR is not exposed externally. |
| 0004 | Fallback Engine Semantics & Safety | Trigger taxonomy (Hard / Soft / Deterministic-deferred / Cost-aware-deferred), idempotent-failure safety (first-chunk rule), chain advancement one-at-a-time, observability headers. |
| 0005 | Cache Layer Cross-Provider Design | Cache key composition over (provider, model, messages, …), per-model isolation, D1+D2+D3+D4 port from OCP v3.13.0, cross-provider fallback cache behaviour (correct miss). |
| 0006 | Provider Inclusion / Exclusion + Risk-Tier Framework | The 4-tier classification (A excluded by default / B explicit consent / C opt-in / D eligible-for-default-enabled), Candidate-vs-Enabled distinction, current v0.1 candidate inventory (0 Enabled), Antigravity exclusion rationale (named prohibition + no cost advantage + reinstatement friction; pending primary-source pin), consent UX, future provider addition procedure. |
| 0007 | Multi-Key Auth (lib/keys.mjs) |
Phase 2 design ADR (D43-B, 2026-05-25). Option 2 (filesystem manifest at ~/.olp/keys/<key-id>/manifest.json) + opaque olp_<32-byte> token + SHA-256 hash. Owner / guest / anonymous tier gating with explicit config.json auth.allow_anonymous (default false). Bootstrap keygen command surface + OLP_OWNER_TOKEN env override with stable synthetic key_id. Audit ndjson append-only at ~/.olp/logs/audit.ndjson, warn+1-retry on append failure. Rejects direct SQLite port at v0.2.0 due to Node baseline (engines >=18 + CI 20/24 vs node:sqlite added 22.5.0 / RC); Option 3 hybrid documented as forward path when Phase 3+ Dashboard / SQL-aggregate quota arrives. |
| 0008 | Dashboard + Audit Query Layer | Phase 3 design ADR (D48, 2026-05-25). Static HTML dashboard + vanilla JS + fetch (no build step). In-memory ndjson scan for aggregate queries (O(N) per call; family-scale acceptable; defers SQLite migration to Option 3 hybrid trigger). Daily audit rotation audit-YYYY-MM-DD.ndjson on first append after UTC midnight; cross-file query layer for rolling 30-day windows. Owner-only gating on /dashboard + 3 /v0/management/* JSON endpoints reusing ADR 0007 § 7 auth model. 30s page poll (no SSE infra). Panels: per-provider quota / 24h request+cache+fallback / 30d spend trend / top-N fallback chains per spec § 4.6. Opens ADR 0007 § 12 Phase 3 deferral (Dashboard + audit query + rotation). |
When to write a new ADR
Open one whenever:
- A structural rule is being added or changed (e.g., new IR field, new trigger type, new cache-key composition).
- A new provider plugin is being proposed (per ADR 0002 + ADR 0006 — ADR is a hard prerequisite for plugin merge).
- A decision encodes a lesson from an external event (provider policy change, drift incident).
- A future contributor reading the code alone could plausibly undo or re-litigate the choice.
Skip ADRs for routine implementation choices (algorithm pick, naming) — those belong in commit messages.
Format
Keep ADRs short — Context / Decision / Consequences / Alternatives is the standard skeleton. Cite incidents, PRs, or commits where useful. Length per ADR ~150–250 lines; longer than that, split.