Production-line record: the already-executed Wave 1 and R2-B/R2-T/R2-A briefs, plus the new part-2 pack — R2-S (EvidenceSubject extension + Proposals wrinkles, gating), then Runs, Packs, Vault (fail-closed), Settings. Strictly sequential merges; operators stop after checks green.
8 KiB
8 KiB
Wave R2 Route Briefs — R2-T (Trace) then R2-A (Audit)
Date: 2026-06-12
Plan: docs/workbench/wave-R-mastery-revamp.md § Wave R2.
Execution: strictly sequential (R2-T merges before R2-A starts — they
share App.tsx, types/api.ts, and routeConformance.test.tsx).
Agent: GPT5.5-Thinking (XHIGH)
Standing constraints (both briefs)
- Worktree off fresh
origin/main; verify the gate lines before any code. - Pre-push verification is the gate (the lane runs in CI, but green-local first). After pushing and confirming checks green: STOP and report. Shay merges.
- Token-only styling —
src/design/doctrine/hexScan.test.tsenforces it. - TS mirrors: when you add an interface for a schema listed in
NOT_YET_MIRRORED(src/design/doctrine/schemaDrift.test.ts), you MUST remove its entry — the drift gate fails in both directions by design. - Surfaces stay distinct:
surface≠articulation_surface≠walk_surface. Trace is the canonical proof of this contract. - Selected rows use
--color-selected-bg/--color-selected-border; focus ring is keyboard position only. - Every route state honors ADR-0162 §6 — and adds itself to
routeConformance.test.tsx(MOUNT_ROUTEStable). - No new mutation endpoints. No invented data — absent evidence renders honest absence states.
Brief R2-T — Trace Route (the flagship)
Worktree + gates
cd /Users/kaizenpro/Projects/core
git fetch origin
git worktree add ../core-wb-r2-trace origin/main -b feat/wb-r2-trace-route
cd ../core-wb-r2-trace
ls workbench-ui/src/app/EvidenceChainRail.tsx || echo "STOP: R1 (#713) not merged"
ls workbench/journal.py || echo "STOP: journal missing"
cd workbench-ui && pnpm install --frozen-lockfile
Read first
docs/workbench/wave-1-evidence-spine.md§ 1E (the original spec — this brief upgrades it onto the landed substrate)docs/workbench/api-contract-v1.md(surface separation, line ~231)workbench/journal.py+workbench/schemas.py(TurnJournalEntrySchema / TurnJournalSummarySchema — your TS mirror source)src/app/evidenceAddress.ts(the codec already speaks/trace/<turnId>)src/app/proposals/ProposalsRoute.tsx(the reference implementation of the triad: window-scope list nav + URL selection + subject publication)src/design/components/— Panel, VirtualizedList, TabBar, DigestBadge, Timestamp, SearchInput, StableJsonViewersrc/app/routeConformance.test.tsx(the contract your route joins)
Deliverables
- TS mirrors in
src/types/api.ts:TurnJournalEntry,TurnJournalSummary(field-exact perschema-snapshot.json). Remove bothSchemaentries fromNOT_YET_MIRRORED— the drift gate now proves the mirror. - Client + hooks:
fetchTraceTurns(limit?, offset?),fetchTraceTurn(turnId)inclient.ts;useTraceTurns(),useTraceTurn(turnId)(enabled only with a turnId) inqueries.ts. src/app/trace/TraceRoute.tsxreplacing the placeholder (deletesrc/routes/TraceRoutePlaceholder.tsx, updateApp.tsx— the/trace/:turnId?param path already exists from R0c):SplitPane(horizontal,id="trace"): timeline left, evidence right.- Left:
SearchInput(filter by prompt text or trace-hash prefix) +VirtualizedListof summaries — each row:Timestamp, prompt excerpt (first line, truncated),DigestBadge(stripsha256:, default 12-char). List nav via the VirtualizedList's built-in keyboard spine. Selected row uses the selected tokens. - Right:
Panel+TabBar, five tabs:- Surfaces — all three, explicitly labeled:
surface"User Surface (response)",articulation_surface"Articulation Surface (realizer)",walk_surface"Walk Surface (telemetry/evidence)". Each in its own bordered card, mono. THIS is the canonical proof of the surface-separation contract — a test must assert all three labels render distinctly. - Grounding —
MetadataTable+ GroundingSource/EpistemicState/ NormativeClearance badges. - Verdicts — identity/safety/ethics verdicts, refusal_emitted, hedge_injected.
- Metadata — turn_id, turn_cost_ms, checkpoint_emitted, proposal
candidates, journal_digest (
DigestBadge). - Raw —
StableJsonViewer, collapsed behind an explicit expand (calm default, infinite depth).
- Surfaces — all three, explicitly labeled:
- Selection: writes
/trace/<turnId>via the codec (replace, notpush), publishessetSubject({ kind: "turn", turnId, data })— the inspector and EvidenceChainRail light from real fields. Deep link restores selection (param read on load).pushRecentItemwithTurn #<id>so the palette's Recent section learns turns. - Empty state: "No turns recorded yet. Use Chat to create
evidence." + next action
{ kind: "cli", command: "core chat" }. - versor_condition: DO NOT add. The journal does not carry it; rendering it would require backend changes (investigate-first item, deferred). Render nothing rather than synthesize.
- Conformance row: add Trace to
MOUNT_ROUTES(loading "Loading trace…", the standard error contract via your ErrorState props, the empty statement + command above). The/trace/turnsendpoint returns the envelope with{ items: [...] }. - Route tests (
src/app/trace/TraceRoute.test.tsx): mocked fetch; timeline renders; selecting shows the evidence panel; the three surface labels render distinctly; raw JSON is collapsed by default; deep link/trace/3restores selection;j/kmoves the timeline.
Verification before push
cd workbench-ui && pnpm build && pnpm test && pnpm test:e2e
PR title: feat(workbench): Trace route — turn evidence timeline over the journal (Wave R2-T)
Brief R2-A — Audit Route (AFTER R2-T merges)
Worktree + gates
cd /Users/kaizenpro/Projects/core
git fetch origin
git worktree add ../core-wb-r2-audit origin/main -b feat/wb-r2-audit-route
cd ../core-wb-r2-audit
ls workbench-ui/src/app/trace/TraceRoute.tsx || echo "STOP: R2-T not merged"
cd workbench-ui && pnpm install --frozen-lockfile
Read first
workbench/schemas.py(AuditEvent) +workbench/api.py(GET /audit/events— landed in #712, pagination + stable ordering)docs/workbench/wave-R-mastery-revamp.md§ R2 Audit
Deliverables
- TS mirror:
AuditEventintypes/api.ts; remove fromNOT_YET_MIRRORED. Timelineprimitive (src/design/components/Timeline/): vertical, deterministic ordering as delivered by the API (never re-sort client-side), each entry showsTimestamp, source tag, summary; entries withmutation_boundary: trueget visual weight (selected-token border, NOT color-only — include a label). Unit tested; preview entry.src/app/audit/AuditRoute.tsxreplacing the placeholder:Panel+SearchInput(filter by source/summary) +VirtualizedList- backedTimeline; pagination via the API's limit/offset (a quiet "Load more", no infinite scroll).- Scope boundary — explicitly deferred: audit events do NOT become
evidence subjects in this PR. Extending the
EvidenceSubjectunion touches the codec/inspector/rail and is a separate, small, reviewed PR (it will be spec'd by Claude). Selection here is visual focus only. - Conformance row + route tests (mocked fetch: list, filter, mutation-boundary weighting, pagination, empty "No audit events recorded." + next action, error contract, loading "Loading audit events…").
Verification before push
cd workbench-ui && pnpm build && pnpm test && pnpm test:e2e
PR title: feat(workbench): Audit route — event timeline with mutation-boundary weighting (Wave R2-A)
After this pack
Remaining R2: Runs, Packs, Vault (fail-closed until persisted evidence
exists), Settings — briefs authored after R2-T/R2-A land. Then R3 theater:
/replay backend + the Replay Moment, deterministic DAG viewer, Demo
Theater, wrong=0 ledger.