core/docs/handoff/wave-R3-briefs-2026-06-13.md
Shay 4d8aa1dac9 feat(workbench): the Replay Moment — turn-keyed hero + retire W-026 artifact replay (Wave R3)
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).
2026-06-12 22:07:34 -07:00

112 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.