think
16px
820px

SDD progress ledger — observatory dashboard P1 plan 2 (feat/dashboard-p1)

FINAL STATE (2026-07-05): COMPLETE, MERGED, LIVE

7 tasks + test-env fix + final whole-branch review + rate-label fix (e4cf727) done.
Merged to master a869a80; tag dash-p1. LIVE at http://192.168.83.20:8320/ (real audit
data; 209 tests). Stop: ssh ai-ahu 'cd ~/ahu-observatory-dashboard/deploy && docker compose down'.
Screenshots: x056.think.val.id/{1-executive-light,2-operator-light,3-auditor-light,4-executive-dark}.png
Backlog items listed below (all triaged BACKLOG by final review) + observatory API gaps
(no status group_by, no p50/p95/p99, no upstream_class field) for a future observatory task.

Plan: docs/superpowers/plans/2026-07-04-observatory-dashboard.md
Consumes the LIVE observatory API at http://192.168.83.20:8300 (real chatbot audit data flowing).
Toolchain: pnpm (nvm node v24.11.0). dataviz + ui-ux-pro-max skills mandatory per frontend task.

Task 1: complete (commits 6f7d231..13709e8, review Approved — palette re-validated, DTOs diffed vs server.go, DNS-race fix tested in real Docker net). Note for T2: theme toggle must set BOTH shadcn .dark class AND viz data-theme attr.

Task 2: complete (commits 13709e8..c1aa1a5, review Approved — theme dual-set via applyTheme, 401 Proxy-interceptor on every method, role UI-only, all verified in code). TOOLCHAIN NOTE for T3+: force nvm Node 24 bin first — linuxbrew Node 25 on PATH has a broken global localStorage that shadows jsdom.
Task 3: complete (commits c1aa1a5..8fbfe64, dataviz review Approved — entity→slot stability + palette validation reproduced independently; own 38 tests pass). Review found a PRE-EXISTING (since Task 2) env break: theme.test.ts fails 6/6 on Node 25 (localStorage shadowing) — fixing now for unconditional green.
Task 3.5 (test-env fix): complete (commit 5962bb0, test-only) — full suite green on BOTH Node 25.6.1 and 24.11.0; probe-gated in-memory Storage polyfill in src/test/setup.ts, no version sniffing. Folded into final whole-branch review (not separately gated — test-infra, objectively verified). Suite is now unconditionally green; T4-6 no longer need forced Node 24.
Task 4: complete (commits 5962bb0..fe00a25 incl. fix fe00a25: stat tiles show "Unavailable" on query isError never fabricated 0/Good + per-query wiring + dev/prod subtitle; re-review Approved, failure reproduced against live component. 114 tests. Math/dataviz/scope/API-gap-honesty all verified. Added additive error prop to Task 3 chart primitives.)
Task 5: complete (commits fe00a25..01ff553, review Approved [2nd reviewer — 1st went silent; SendMessage is the working report channel, NOT "output directly"]. 169 tests. Keyset last-row cursor no-dup/gap + filter-reset + auditor-only View-bodies all verified with real-invariant tests, suite reran clean. View-bodies deep-links /audit?event_id=... — Task 6 MUST consume via useSearchParams.)
Task 6: complete (commits 01ff553..4ad3824, review Approved — all compliance behaviors verified against actual server.go handlers + the emitting CallDetailDrawer. 205 tests. Recorded-notice unconditional, deep-link real, bad_chain_pos fidelity, hashed-actor labeling, 403 graceful. Flagged: verify-chain from/to accept NaN silently [server atoiOr→0, safe]; raw-body path unit-only.)
ALL 6 BUILD TASKS DONE. Task 7 = live deploy on ai-ahu + screenshots (exit gate).
Task 7: complete (commit b40f24e + tag dash-p1 — LIVE at http://192.168.83.20:8320/. Image 60.3MB, shipped via docker save|ssh load [no on-host build]. Real data verified: 10 calls/10% err/2094 tokens, external-calls tile=1 dashscope red+caveat, keyset load-more zero-overlap, auditor body-view wrote access-log row, verify-chain ok. 4 screenshots @ x056.think.val.id/{1-executive-light,2-operator-light,3-auditor-light,4-executive-dark}.png. Stop: ssh ai-ahu 'cd ~/ahu-observatory-dashboard/deploy && docker compose down'. Notes: host UTC vs +07; observatory /healthz ingested/pending are process counters not DB totals.)
Final whole-branch review (fable): 1 Important pre-merge fix — "Calls/min"/"Tokens/min" titles are 60× wrong on the 7d preset (1h buckets under per-min label). Honesty end-to-end / trust-critical surfaces / auth / dataviz / scope / deploy all verified clean. All 11 ledger minors → BACKLOG (none must-fix). Fix subagent running: derive rate label from range.bucket, redeploy, re-tag.
BACKLOG (final-review triage, all deferred): nginx /healthz prefix + root user; theme FOUC + RequireRole test; T5 semantic-button + debounce; T3 seriesColor ??0 + per-instance slots + single-series labels; T6 verify-chain NaN + raw-body path; PLUS new fast-follows: sparse-bucket zero-fill (counts only, not latency), keepPreviousData staleness cue, external-tile subtitle hardcodes dev-host wording (fix at prod promotion), verify-chain banner should echo verified range + clear on input edit. 110 tests. Found /api/series has NO status dimension {engine,upstream,traffic_class only} — refused to fake per-bucket status, moved ok/error to summary-backed tile+BarBreakdown. upstream_class absent from API → allowlist+ext- prefix classification via group_by=upstream. Added additive error prop to Task 3 chart primitives.)

OBSERVATORY API BACKLOG surfaced by dashboard build (for a future observatory task)

  • /api/series has no status group_by → no per-bucket ok/error time-series possible
  • no p50/p95/p99 (avg/max only)
  • no upstream_class field on summary/series → dashboard classifies external via allowlist

Deferred minors for final review

  • T1: nginx location /healthz is prefix not exact (location = /healthz tighter); nginx runtime stage runs as root (future hardening)
  • T2: theme FOUC (dark pref flashes light before React mounts — add a blocking stamp script in index.html); no component test for RequireRole redirect (Playwright-only)
  • T5: table rows tabIndex+onClick not semantic button (a11y, keyboard-operable+focus-ring, internal tool → Minor); no debounce on free-text filters (accepted at ~10-call volume)
  • T3: TimeSeriesChart seriesColor fallback slots.get(id) ?? 0 paints a 9th+ entity in slot 0 (collision) instead of "Other" — unreachable at ≤4 series but doesn't mirror entity-slots.ts's ceiling; useEntitySlots is per-instance ref so two charts on one page need consistent first-seen ordering (note for T4); single-series still draws end-labels (cosmetic)

Deferred minors for final review

(none yet)

Binding scope reminders

  • Consume ONLY endpoints that exist in ../ahu-ai-observatory/internal/api/server.go
  • Fleet/GPU/queue telemetry + true p95/p99 are OUT (P3 / API addition) — visible placeholders, never faked
  • dataviz non-negotiables are per-task reviewer gates; validate_palette.js on exact hues both modes
  • Role picked manually at login (no /whoami); server is the real gate, UI handles 403