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).
112 lines
5.3 KiB
Markdown
112 lines
5.3 KiB
Markdown
# 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`): delete `ReplayDivergenceSeverity`,
|
||
`ReplayStatus`, `ReplayDivergence`, `ReplayComparison` (the artifact-keyed
|
||
block). Keep the `TurnReplay*` block. Zero word-boundary uses elsewhere.
|
||
- **Snapshots**: regenerate both — `pnpm schema:snapshot` (drops
|
||
`ReplayComparison`/`ReplayDivergence`) and `pnpm enum:snapshot` (drops
|
||
`ReplayStatus`/`ReplayDivergenceSeverity`).
|
||
- **TS** (`types/api.ts`): remove `ReplayComparison`/`ReplayDivergence`/
|
||
`ReplayDivergenceSeverity`; add `TurnReplayComparison`/`TurnReplayDivergence`
|
||
(+ the `TurnReplayDivergenceSeverity`/`TurnReplayBasis`/`TurnReplayOriginState`
|
||
unions). Remove both `TurnReplay*` entries from `NOT_YET_MIRRORED`.
|
||
- **Badges** (`design/components/badges/{types,mappings,index}.ts*`): remove
|
||
`ReplayStatusBadge` + `ReplayDivergenceSeverityBadge` + their meta/types;
|
||
drop their two cases from `enumCoverage.test.ts`. The hero renders the new
|
||
severity (`critical`/`informational`) inline with a `≠` glyph — no new
|
||
enum-tracked badge.
|
||
- **API** (`client.ts`/`queries.ts`): remove `fetchReplayComparison`/
|
||
`useReplayComparison`; add `fetchTurnReplay(turnId)` → `/replay/<turnId>` and
|
||
`useTurnReplay(turnId)`.
|
||
- **Route dir** (`app/replay/`): delete `ArtifactList`, `ReplayComparisonPanel`,
|
||
`ReplayDiffViewer`, `ReplayMetadataTable`, and the old `replay.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_hash` vs `replay_trace_hash` rendered big; a clear
|
||
`≡ equivalent` (when `equivalent`) or `≠ diverged` verdict. **Honesty card**
|
||
states `comparison_basis` (`sealed_fresh_runtime_single_turn`) and
|
||
`origin_state` (`unrecorded`) — a divergence means nondeterminism OR
|
||
origin-state influence, never disambiguated; never render divergence as a
|
||
determinism-failure verdict.
|
||
- Leaf diff: each `divergence` as a row with `path`, original vs replay, and a
|
||
`≠` glyph; `critical` weighted above `informational`; informational
|
||
divergences (timestamp/cost/digest) explicitly labeled as expected.
|
||
- Publishes the `turn` subject 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
|
||
|
||
```bash
|
||
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.
|