First R3 (Theater) piece. Reworks the stale artifact-keyed ReplayRoute into the turn-keyed hero over the #716 sealed-replay backend, and fully retires the dead W-026 artifact-keyed machinery on both sides (the NOT_YET_MIRRORED comment anticipated this). The hero makes determinism *felt*: pick a journaled turn, CORE re-executes its prompt in a sealed fresh runtime, and the result renders as a hash verdict (≡ equivalent / ≠ diverged) + the original/replay DigestBadges + a leaf diff (critical weighted above informational, each with a ≠ glyph). The 'What this proves' card surfaces comparison_basis + origin_state and states the honest limit: a divergence means nondeterminism OR origin-state influence, never rendered on its own as a determinism failure. Retirement (verified zero serving uses): - Python schemas.py: removed ReplayComparison/ReplayDivergence/ReplayStatus/ ReplayDivergenceSeverity; scripts/dump-enums.py drops the two replay enums; both snapshots regenerated (deterministic: dump == committed) - TS: removed ReplayComparison/ReplayDivergence/ReplayDivergenceSeverity; added TurnReplayComparison/TurnReplayDivergence (+ basis/origin/severity unions); NOT_YET_MIRRORED now empty (every engine schema mirrored) - badges: removed ReplayStatusBadge + ReplayDivergenceSeverityBadge + meta/enums + their enumCoverage cases (hero renders severity inline) - api: fetchReplayComparison/useReplayComparison -> fetchTurnReplay/ useTurnReplay (/replay/<turnId>) - deleted ArtifactList, ReplayComparisonPanel, ReplayDiffViewer, ReplayMetadataTable, old replay.test.tsx - App route /replay/:artifactId? -> /replay/:turnId?; conformance row turn-keyed (loading 'Loading turns...', empty 'No turns recorded yet.') Tests: ReplayRoute.test.tsx (equivalence hero + honesty card, diverged critical leaf, informational-only label, replace-mode select, j/k spine). Full vitest 358 green; workbench Python 34 green; both snapshots deterministic. Follow-up flagged (not in this PR to keep it focused): the artifact query hooks (useArtifacts/useArtifactDetail/fetchArtifacts*) are now orphaned but entangled with the still-live artifact EvidenceSubject kind — a separate cleanup once an Artifacts route or that subject's fate is decided. Brief: docs/handoff/wave-R3-briefs-2026-06-13.md (all four R3 pieces).
5.3 KiB
Wave R3 Briefs — Theater (the wow, honest)
Date: 2026-06-13
Plan: docs/workbench/wave-R-mastery-revamp.md § Wave R3.
Predecessor: Wave R2 complete (#714–#721; all six routes real). Replay
backend already merged (#716, GET /replay/{turn_id} → TurnReplayComparison).
Four pieces. The Replay Moment is first (its backend exists and the old
artifact-keyed ReplayRoute is now stale against it). The others are
independent and can be authored after.
Standing constraints (all briefs)
Same as Wave R2: worktree off fresh origin/main; green-local before push
(pnpm build && pnpm test); STOP after checks green, Shay merges;
token-only styling (hexScan); shrink-only NOT_YET_MIRRORED; conformance
rows (ADR-0162 §6); no new mutation endpoints; no invented data; no
force-directed / nondeterministic layout — ever.
Brief R3-Replay — The Replay Moment (first; reworks + retires)
The hero flow. Turn-keyed sealed replay made felt: same prompt, same genesis substrate → bit-identical envelope, rendered as hash≡hash with an honest leaf diff. Consumes the merged #716 backend.
This PR also retires the dead W-026 artifact-keyed replay machinery
(confirmed zero serving uses) on both sides — the NOT_YET_MIRRORED comment
already anticipates it.
Retirement surface (verified)
- Python (
workbench/schemas.py): deleteReplayDivergenceSeverity,ReplayStatus,ReplayDivergence,ReplayComparison(the artifact-keyed block). Keep theTurnReplay*block. Zero word-boundary uses elsewhere. - Snapshots: regenerate both —
pnpm schema:snapshot(dropsReplayComparison/ReplayDivergence) andpnpm enum:snapshot(dropsReplayStatus/ReplayDivergenceSeverity). - TS (
types/api.ts): removeReplayComparison/ReplayDivergence/ReplayDivergenceSeverity; addTurnReplayComparison/TurnReplayDivergence(+ theTurnReplayDivergenceSeverity/TurnReplayBasis/TurnReplayOriginStateunions). Remove bothTurnReplay*entries fromNOT_YET_MIRRORED. - Badges (
design/components/badges/{types,mappings,index}.ts*): removeReplayStatusBadge+ReplayDivergenceSeverityBadge+ their meta/types; drop their two cases fromenumCoverage.test.ts. The hero renders the new severity (critical/informational) inline with a≠glyph — no new enum-tracked badge. - API (
client.ts/queries.ts): removefetchReplayComparison/useReplayComparison; addfetchTurnReplay(turnId)→/replay/<turnId>anduseTurnReplay(turnId). - Route dir (
app/replay/): deleteArtifactList,ReplayComparisonPanel,ReplayDiffViewer,ReplayMetadataTable, and the oldreplay.test.tsx.
New ReplayRoute (turn-keyed hero)
- List journaled turns (reuse
useTraceTurns) in the left pane (VirtualizedList- useListNavigation + SearchInput), same as Trace.
- Select → navigate
/replay/<turnId>(replace) →useTurnReplay(turnId). - Hero:
original_trace_hashvsreplay_trace_hashrendered big; a clear≡ equivalent(whenequivalent) or≠ divergedverdict. Honesty card statescomparison_basis(sealed_fresh_runtime_single_turn) andorigin_state(unrecorded) — a divergence means nondeterminism OR origin-state influence, never disambiguated; never render divergence as a determinism-failure verdict. - Leaf diff: each
divergenceas a row withpath, original vs replay, and a≠glyph;criticalweighted aboveinformational; informational divergences (timestamp/cost/digest) explicitly labeled as expected. - Publishes the
turnsubject for the inspector (identity → detail), like Trace. - App route
path="replay/:turnId?"; conformance row turn-keyed (loading "Loading turns...", empty "No turns recorded yet. Use Chat to create evidence." +core chat). - Tests: hero equivalence (hash≡hash), a tampered-leaf divergence renders
≠at the right path, informational-only divergence still reads equivalent, the honesty fields render, j/k spine, replace-mode URL selection.
Verification
cd workbench-ui && pnpm build && pnpm test
# plus the Python lane the snapshots feed:
uv run python scripts/dump-schemas.py | diff - workbench-ui/schema-snapshot.json
uv run python scripts/dump-enums.py | diff - workbench-ui/enum-snapshot.json
Brief R3-DAG — Deterministic DAG viewer
One hand-rolled component (design/components/Dag/): longest-path layering,
lexicographic tie-break, ~150 lines, golden-file layout tests, no graph
dependency (force-directed = doctrine violation). Pan/zoom/click-node →
inspector. Consumers: proposal chains, the 8 PCCP proof-promotion scenarios
(demos/proof_carrying_promotion), entailment traces. Pure layout function;
golden tests pin node coordinates.
Brief R3-Demo — Demo Theater route
GET /demos, POST /demos/{id}/run (new read + a scoped run endpoint).
Scenario results with evidence-class badges and "what this proves / what this
does not prove" honesty cards; proposer-was-wrong scenarios visually
highlighted. Backend brief first (Python), then the route.
Brief R3-Ledger — wrong=0 ledger view
Evals renders the correct/refused/wrong triplet as the PRIMARY visualization; refusal reasons inspectable; failures-first ordering. Additive to the existing EvalsRoute — no retirement, lowest risk of the four.