diff --git a/AGENTS.md b/AGENTS.md index 1ceb81e..7fb2520 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,7 +41,7 @@ Runtime: Node.js (ESM, `.mjs` throughout). No build step. No bundler. `server.mj - `bin/olp-keys.mjs` — keygen CLI bootstrap surface per ADR 0007 § 9.1. **✅ Shipped at D47.** Subcommands: `keygen [--owner|--name=X|--providers=csv|--force]`, `list [--owner-only|--include-revoked]`, `revoke --id=X`. Plaintext token printed once on keygen. Installed via `package.json bin` so `npx olp-keys ...` works (also `npm run olp-keys ...`). - `lib/audit.mjs` — append-only ndjson audit per ADR 0007 § 6.2 + § 8. **🟡 D45 — appendAuditEvent + getAuditDropCount shipped. Fires per /v1/chat/completions + /v1/models request including 401/403/5xx paths. Warn+1-retry on append failure; no memory buffer at Phase 2 (forward path).** **D52 will extend with daily rotation per ADR 0008 § 5.** - `lib/audit-query.mjs` — audit ndjson aggregate query layer per ADR 0008 § 4. **🟡 D49 — discoverAuditFiles + readAuditWindow + aggregateRequests + topFallbackChains + spendTrendDaily + cacheHitRateWindow shipped. Cross-file walk over `audit.ndjson` (live) + `audit-YYYY-MM-DD.ndjson` (rotated). PII guard: aggregate shapes never include message content. In-memory scan per request (ADR 0008 Lane 2 = A; SQLite hybrid deferred to ADR 0007 § 13 trigger).** -- `dashboard.html` — owner-only multi-provider dashboard (quota panels, fallback rate, cache hit rate). **🟡 D50 — placeholder stub shipped at repo root + `/dashboard` route in server.mjs serves it owner-only_block. D51 lands the full multi-panel UI (quota + 24h request stats + 30d spend trend + top fallback chains) per ADR 0008 § 6.** +- `dashboard.html` — owner-only multi-provider dashboard (4 panels: per-provider quota / 24h request+cache+fallback / 30d spend trend SVG sparkline / top-10 fallback chains). **✅ D51 — full UI shipped at repo root per ADR 0008 § 6. Vanilla HTML + JS + fetch (no build step, no framework, no CDN). 30s page poll with `document.visibilityState` pause/resume. Served by `/dashboard` route in server.mjs owner-only_block. Cached in memory at first request via `_loadDashboardHtml`.** - `models-registry.json` — single source of truth for `(provider, model) → metadata`. SPOT. - `ALIGNMENT.md` — the constitution. Binding for any plugin / entry-surface / IR change. - `docs/adr/` — Architecture Decision Records. Read the index in `docs/adr/README.md` before proposing governance, SPOT, or contract changes. diff --git a/CHANGELOG.md b/CHANGELOG.md index 85ffb2d..eed1fb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,41 @@ All notable changes to OLP land here. Per `CLAUDE.md` release_kit overlay, this ## Unreleased +### D51 — `dashboard.html` full multi-panel UI (Phase 3) + +Fourth Phase 3 D-day. Replaces the D50 `dashboard.html` placeholder with the full 4-panel UI per ADR 0008 § 6. Vanilla HTML + JS + fetch — no build step, no framework, no CDN (Lane 1 = A). 30s page poll with `document.visibilityState` pause/resume (Lane 4 = A). + +- **4 panels rendered from `/v0/management/dashboard-data`** (the single backing endpoint, per Lane 2 in-memory query model): + - **Panel 1 — Per-provider quota**: table of `{ Provider | Available | Status }`; surfaces `null` available as "n/a" + capturing per-provider `provider.quotaStatus()` errors as a red status pill (graceful degradation per ADR § 9). + - **Panel 2 — Last 24h: request count + cache hit + fallback rate**: per-provider row of `{ Requests | Cache hit % | Fallback rate % }`. Cache hit sourced from `cache_hit_24h.by_provider[p].hit_rate`; fallback rate computed from `window_24h.by_provider[p].fallback_count / count`. + - **Panel 3 — Request count last 30 days (SVG sparkline)**: vanilla SVG bar chart with `
" banner; console.warn for operator debugging.
+ - Per-panel "Loading…" / "No requests in window." / "No fallback chains triggered" empty states.
+- **DOM helpers**: small `el(tag, attrs, ...children)` + `svgEl(tag, attrs)` factories — no framework, ~10 lines each. Sparkline uses native `` for tooltips (no JS hover handlers).
+- **Critical correctness invariants** (per ADR 0008 § 6 + Lane 1 = A):
+ - No `