Merge pull request #707 from AssetOverflow/feat/wb-mastery-revamp-docs
docs(workbench): Wave R mastery revamp plan + R0/R1 dispatch brief pack
This commit is contained in:
commit
52d5d815ec
3 changed files with 662 additions and 1 deletions
346
docs/handoff/wave-R-mastery-briefs-2026-06-12.md
Normal file
346
docs/handoff/wave-R-mastery-briefs-2026-06-12.md
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
# Wave R Mastery Revamp — Dispatch Briefs (R0a–R0d, R1)
|
||||
|
||||
Date: 2026-06-12
|
||||
Plan: `docs/workbench/wave-R-mastery-revamp.md` (read it first — it is the
|
||||
governing spec; this pack is the per-operator cut).
|
||||
|
||||
## Dispatch order
|
||||
|
||||
```
|
||||
Echelon 1 (parallel dispatch): R0a ∥ R0b ∥ R0c
|
||||
Echelon 2: R0d (after R0c merges)
|
||||
Echelon 3: R1 (after all R0 merges)
|
||||
```
|
||||
|
||||
**Merge order is a strict train even though dispatch is parallel:**
|
||||
R0a merges FIRST (smallest PR; carries the honesty fix; lands the CI lane
|
||||
that then verifies R0b/R0c). R0b and R0c merge next, either order, each
|
||||
rebased on merged main before push if R0a landed meanwhile. R0d after R0c.
|
||||
Never combine R0 briefs into one PR.
|
||||
|
||||
Brief 5 (Trace route, `wave-1-evidence-spine-briefs-2026-06-12.md`) **stays
|
||||
on hold** until R0 lands; it gets re-issued upgraded as the first R2 brief.
|
||||
|
||||
## Standing constraints (every brief)
|
||||
|
||||
- Worktree per operator, always off fresh `origin/main` — never share a
|
||||
working dir.
|
||||
- The merge pipeline is automated; **pre-push verification is the gate.**
|
||||
Run your brief's verification block before pushing.
|
||||
- Token-only styling (no raw hex/rgb outside `tokens.css`); no color-only
|
||||
encoding; motion only via `--motion-*` tokens; `prefers-reduced-motion`
|
||||
collapses to instant.
|
||||
- ADR-0162 no-go list applies verbatim (no thinking animations, no
|
||||
glassmorphism, no toasts that auto-dismiss audit events, no icon-only
|
||||
buttons).
|
||||
- Surfaces stay distinct everywhere: `surface` ≠ `articulation_surface` ≠
|
||||
`walk_surface`.
|
||||
- No mutation endpoints, no writes outside `workbench_data/` from workbench
|
||||
code.
|
||||
- Until R0a merges: full `pnpm test` may hang on teardown. Verify with
|
||||
`pnpm build` + per-file `pnpm vitest run <file>`; `pkill -9 -f vitest`
|
||||
afterwards if needed.
|
||||
- Commit format `<type>(workbench): <description>`; push with `-u`; open a
|
||||
PR titled as given in the brief.
|
||||
|
||||
---
|
||||
|
||||
## Brief R0a — Test-runner hardening + frontend CI lane
|
||||
|
||||
**Suggested operator:** Codex
|
||||
**Scope:** `workbench-ui/` test config + timer hygiene; one new GitHub
|
||||
workflow. No product code changes beyond timer cleanup.
|
||||
|
||||
### Worktree
|
||||
|
||||
```bash
|
||||
cd /Users/kaizenpro/Projects/core
|
||||
git fetch origin
|
||||
git worktree add ../core-wb-r0a origin/main -b feat/wb-r0a-test-hardening
|
||||
cd ../core-wb-r0a/workbench-ui && pnpm install
|
||||
```
|
||||
|
||||
### Context
|
||||
|
||||
Full multi-file `pnpm test` hangs on worker teardown — tests pass, the
|
||||
process never exits. Diagnosed 2026-06-12: live handles at teardown
|
||||
(`Timestamp.tsx` `setInterval(..., 60_000)`, copy-feedback `setTimeout`s);
|
||||
`vite.config.ts` has no `testTimeout`/`teardownTimeout`; switching pools does
|
||||
not fix it; single files exit clean. Separately: **no CI workflow runs
|
||||
workbench-ui at all** (`smoke.yml` / `full-pytest.yml` are Python-only).
|
||||
|
||||
### Deliverables
|
||||
|
||||
1. `vite.config.ts` test config: `testTimeout: 10_000`,
|
||||
`hookTimeout: 10_000`, `teardownTimeout: 5_000`. Tune pool options only
|
||||
if measurements justify it — caps first, knobs second.
|
||||
2. Timer hygiene: audit every `setInterval`/`setTimeout`/`AbortController`
|
||||
under `src/`; ensure each has a cleanup path on unmount. In tests that
|
||||
mount timer-scheduling components (`Timestamp`, copy buttons), use
|
||||
`vi.useFakeTimers()` with restoration in `afterEach`.
|
||||
3. Prove it: full `pnpm test` runs to completion AND the process exits.
|
||||
Record wall-clock in the PR body.
|
||||
4. New `.github/workflows/workbench-ui.yml`:
|
||||
- `on: pull_request` + `push: branches: [main]`, both with
|
||||
`paths: ['workbench-ui/**', '.github/workflows/workbench-ui.yml']`
|
||||
(the workflow validates changes to itself)
|
||||
- single job, `timeout-minutes: 15`: pnpm setup (frozen lockfile) →
|
||||
`pnpm build` → `pnpm test`
|
||||
- Node 20, pnpm via `corepack` or `pnpm/action-setup`
|
||||
5. Honesty fix, **unconditional**: remove the `j/k`, `/`, and
|
||||
`Enter — Open selected item` rows from `KeyboardHelp.tsx` and its test
|
||||
expectations — the overlay must not advertise shortcuts that do not
|
||||
exist. (`Enter` is real only inside the palette, which carries its own
|
||||
hint; as a global list affordance it is false until R0d.) R0d restores
|
||||
these rows as real, registry-backed entries.
|
||||
6. Minimal route conformance test (front-loaded from R1):
|
||||
`src/app/routeConformance.test.tsx`, parametrized over the implemented
|
||||
routes (Chat, Proposals, Evals, Replay). For each route, under mocked
|
||||
query states, assert: empty state renders a one-line absence statement +
|
||||
a next action; error state renders what-failed + mutation status +
|
||||
reproducer + retry-safety; loading state renders a specific label (never
|
||||
"Thinking…"). Per ADR-0162 §6. Fix routes that fail; no expected-fail
|
||||
lists (a test that tolerates violations is decoration).
|
||||
|
||||
### Verification before push
|
||||
|
||||
```bash
|
||||
cd workbench-ui && pnpm build && time pnpm test # must EXIT, all green
|
||||
git -C .. diff --stat origin/main # only intended files
|
||||
```
|
||||
|
||||
PR title: `fix(workbench): test-runner teardown hardening + frontend CI lane`
|
||||
|
||||
---
|
||||
|
||||
## Brief R0b — Playwright smoke lane
|
||||
|
||||
**Suggested operator:** GPT5.5-Thinking
|
||||
**Scope:** `workbench-ui/` e2e only. Pays ADR-0162 acceptance-criteria debt
|
||||
(§ acceptance 5, 6, 7). No product code changes except test hooks
|
||||
(`data-testid` additions are allowed, sparingly).
|
||||
|
||||
### Worktree
|
||||
|
||||
```bash
|
||||
cd /Users/kaizenpro/Projects/core
|
||||
git fetch origin
|
||||
git worktree add ../core-wb-r0b origin/main -b feat/wb-r0b-playwright
|
||||
cd ../core-wb-r0b/workbench-ui && pnpm install
|
||||
```
|
||||
|
||||
### Deliverables
|
||||
|
||||
1. `@playwright/test` devDependency (pinned), `playwright.config.ts` with
|
||||
`webServer` serving the built app (`pnpm build && vite preview`),
|
||||
chromium-only project (keep the lane lean).
|
||||
2. `e2e/palette.spec.ts` — from each of the ten routes: `Meta+K` opens the
|
||||
palette; selecting a navigation command reaches every route (URL
|
||||
asserted). The app must be usable with the backend absent — routes render
|
||||
their error/empty states, never a white screen (this doubles as an
|
||||
offline-resilience assertion).
|
||||
3. `e2e/reduced-motion.spec.ts` — with `reducedMotion: 'reduce'`, tokenized
|
||||
motion collapses to instant (assert computed transition/animation
|
||||
durations are `0s` on a drawer open and palette open).
|
||||
4. `e2e/preview-offline.spec.ts` — `context.route('**', abort)` for
|
||||
non-localhost requests; `/preview` still renders every primitive section
|
||||
(fonts are self-hosted; nothing may fetch the network).
|
||||
5. `pnpm test:e2e` script; add a **separate job** to
|
||||
`.github/workflows/workbench-ui.yml` if R0a's workflow exists on your
|
||||
base, else create the file with just your job (merge is trivial either
|
||||
way) — `timeout-minutes: 15`, cache playwright browsers.
|
||||
|
||||
### Verification before push
|
||||
|
||||
```bash
|
||||
cd workbench-ui && pnpm build && pnpm test:e2e # all green locally
|
||||
```
|
||||
|
||||
PR title: `test(workbench): playwright smoke lane (ADR-0162 acceptance 5-7)`
|
||||
|
||||
---
|
||||
|
||||
## Brief R0c — Evidence addresses (URL = subject)
|
||||
|
||||
**Suggested operator:** Claude
|
||||
**Scope:** React/TypeScript. The audit-native deep-linking substrate every
|
||||
R2 route will consume.
|
||||
|
||||
### Worktree
|
||||
|
||||
```bash
|
||||
cd /Users/kaizenpro/Projects/core
|
||||
git fetch origin
|
||||
git worktree add ../core-wb-r0c origin/main -b feat/wb-r0c-evidence-addresses
|
||||
cd ../core-wb-r0c/workbench-ui && pnpm install
|
||||
```
|
||||
|
||||
### Read first
|
||||
|
||||
- `docs/workbench/wave-R-mastery-revamp.md` § R0c
|
||||
- `workbench-ui/src/app/evidenceContext.tsx` (the `EvidenceSubject` union)
|
||||
- `workbench-ui/src/app/App.tsx`, `useGlobalKeyboard.ts`,
|
||||
`commandRegistry.ts`
|
||||
|
||||
### Deliverables
|
||||
|
||||
1. `workbench-ui/src/app/evidenceAddress.ts`:
|
||||
- `subjectToUrl(subject: EvidenceSubject): string` — canonical path
|
||||
(`/trace/42`, `/proposals/<id>`, `/evals/<lane>`, `/replay/<artifact>`)
|
||||
plus `?inspect=` when the inspector is open on a different subject
|
||||
- `urlToSubject(params, searchParams): { route: EvidenceSubject | null,
|
||||
inspect: EvidenceSubject | null }` — total inverse; malformed input
|
||||
returns `null`, never throws
|
||||
- The codec speaks ALL subject kinds now, including ones whose routes are
|
||||
still placeholders — the grammar is fixed once.
|
||||
2. `App.tsx` route params: `/trace/:turnId?`, `/proposals/:proposalId?`,
|
||||
`/evals/:laneId?`, `/replay/:artifactId?`. Placeholder routes keep flat
|
||||
paths.
|
||||
3. `EvidenceProvider` ↔ URL sync: `?inspect=` carries inspector subject +
|
||||
open state; deep link restores it; subject changes update the URL
|
||||
(`replace`, not `push` — selection churn must not pollute history).
|
||||
4. Existing routes restore selection from their param on load and write it
|
||||
on selection change: `ProposalsRoute`, `EvalsRoute`, `ReplayRoute`.
|
||||
5. `Cmd+Shift+C` in `useGlobalKeyboard`: copies
|
||||
`window.location.origin + subjectToUrl(current subject)`; no-op with no
|
||||
subject; input-focus guard applies. Visible copy-confirmation must not
|
||||
auto-dismiss audit context (a transient inline "Copied" on the inspector
|
||||
header is fine; no toast).
|
||||
6. Tests: codec round-trip for every subject kind (including malformed
|
||||
inputs); deep-link restores Proposals selection (MemoryRouter
|
||||
`initialEntries`); `?inspect=` restores inspector; URL updates use
|
||||
`replace`.
|
||||
|
||||
### Verification before push
|
||||
|
||||
```bash
|
||||
cd workbench-ui && pnpm build
|
||||
pnpm vitest run src/app/evidenceAddress.test.ts src/app/evidenceContext.test.tsx src/app/proposals/ProposalsRoute.test.tsx
|
||||
# (per-file runs until R0a lands; then plain `pnpm test`)
|
||||
```
|
||||
|
||||
PR title: `feat(workbench): evidence addresses — deep-linkable subjects + inspector URL state`
|
||||
|
||||
---
|
||||
|
||||
## Brief R0d — Interaction substrate (AFTER R0c merges)
|
||||
|
||||
**Suggested operator:** Codex or GPT5.5-Thinking
|
||||
**Scope:** React/TypeScript. List navigation, virtualization, panel chrome,
|
||||
inspector resize, palette action verbs.
|
||||
|
||||
### Worktree
|
||||
|
||||
```bash
|
||||
cd /Users/kaizenpro/Projects/core
|
||||
git fetch origin
|
||||
git worktree add ../core-wb-r0d origin/main -b feat/wb-r0d-interaction-substrate
|
||||
cd ../core-wb-r0d/workbench-ui && pnpm install
|
||||
ls src/app/evidenceAddress.ts || echo "STOP: R0c not merged"
|
||||
```
|
||||
|
||||
### Deliverables
|
||||
|
||||
1. `src/design/hooks/useListNavigation.ts`: `j`/`k`/`ArrowUp`/`ArrowDown`/
|
||||
`Home`/`End` move focus, `Enter` activates, input-focus guard (reuse the
|
||||
`isInputFocused` pattern from `useGlobalKeyboard.ts`). Roving tabindex or
|
||||
`aria-activedescendant` — focused row visibly distinct, screen-reader
|
||||
coherent. Unit tested.
|
||||
2. `src/design/components/VirtualizedList/`: wraps `@tanstack/react-virtual`
|
||||
(add dep, pinned), composes `useListNavigation`, deterministic item keys,
|
||||
stable scroll restoration. Tested (virtualization kicks in above the
|
||||
threshold; keyboard nav still works across virtualized boundaries).
|
||||
3. `src/design/components/Panel/`: header (title + toolbar slot) + body
|
||||
chrome, token-only. This is the standard panel every R2 route composes.
|
||||
4. Inspector resize in `Shell.tsx`: wire the existing `SplitPane` for the
|
||||
inspector column; width persisted to localStorage **with guarded access**
|
||||
(see commit `af8d4f75` for the precedent — storage can throw).
|
||||
5. Palette action commands: `commandRegistry.ts` gains an action kind
|
||||
(discriminated union: `navigate` | `action`); routes register/unregister
|
||||
their own commands on mount (the deferred Wave-1 call-site pattern).
|
||||
First verbs: "Copy evidence link" (calls R0c's address copy), "Toggle
|
||||
inspector", and Evals registers "Run eval lane <lane>" (executes the
|
||||
existing read-only `POST /evals/run` — ADR-0160-allowed lane, not a
|
||||
mutation).
|
||||
6. Wire it for real: Proposals list and Replay artifact list adopt
|
||||
`useListNavigation` + `SearchInput` (the `/` shortcut becomes real where
|
||||
mounted).
|
||||
7. `Kbd` primitive (front-loaded from R1): a small token-only component for
|
||||
rendering key chords; `KeyboardHelp` and palette shortcut hints adopt it.
|
||||
8. `KeyboardHelp.tsx` becomes **registry-driven**: the overlay renders its
|
||||
rows from the shortcut/command registry instead of a hand-maintained
|
||||
array, so advertising an unimplemented shortcut is structurally
|
||||
impossible. The rows R0a removed (`j/k`, `/`, `Enter`) return here as
|
||||
real registry entries. Test: every row in the rendered overlay
|
||||
corresponds to a registered, handled shortcut.
|
||||
|
||||
### Verification before push
|
||||
|
||||
```bash
|
||||
cd workbench-ui && pnpm build && pnpm test # R0a is merged by now: full run must exit green
|
||||
```
|
||||
|
||||
PR title: `feat(workbench): interaction substrate — list nav, virtualization, panel chrome, inspector resize, palette verbs`
|
||||
|
||||
---
|
||||
|
||||
## Brief R1 — Design mastery pass (AFTER all R0 merges)
|
||||
|
||||
**Suggested operator:** Claude
|
||||
**Scope:** one PR, visual + doctrine-as-tests. No new routes, no new
|
||||
endpoints.
|
||||
|
||||
### Worktree
|
||||
|
||||
```bash
|
||||
cd /Users/kaizenpro/Projects/core
|
||||
git fetch origin
|
||||
git worktree add ../core-wb-r1 origin/main -b feat/wb-r1-design-mastery
|
||||
cd ../core-wb-r1/workbench-ui && pnpm install
|
||||
ls src/design/components/Panel || echo "STOP: R0d not merged"
|
||||
```
|
||||
|
||||
### Deliverables
|
||||
|
||||
1. Typography precision: `tabular-nums` on every metric cell
|
||||
(`MetadataTable` values, eval metrics, `turn_cost_ms`); type-scale audit
|
||||
against ADR-0162 §2; `text-wrap: balance` on headings.
|
||||
2. Selection-state unification: one tokenized treatment for selected vs
|
||||
focused rows, applied across Proposals / Evals / Replay lists.
|
||||
3. Hash display standard: 12-char truncation + copy + mono everywhere;
|
||||
consolidate `src/app/chat/CopyableHash.tsx` into `DigestBadge` and delete
|
||||
the duplicate (cleanup-as-you-find: imports, tests, preview entries).
|
||||
4. `EvidenceChainRail` in `RightInspector`: the seven spine stages (intent →
|
||||
subject → provenance → admissibility → replay → authority → action), each
|
||||
rendered lit (evidence present) / dim (not applicable) / hollow (not
|
||||
recorded). Status derives ONLY from fields the subject carries — never
|
||||
inferred, never faked. "Not recorded" is an honest, visible state.
|
||||
5. Empty-state glyphs: small static deterministic monochrome SVGs (inline,
|
||||
no asset fetches).
|
||||
6. `Panel` adoption in Proposals + Evals routes (Chat/Replay opportunistic).
|
||||
7. **Doctrine-as-tests** (route conformance shipped in R0a; extend it to any
|
||||
surface this PR touches, then add):
|
||||
- Raw-hex scan: vitest node test walking `src/**` asserting no
|
||||
hex/rgb literals outside `tokens.css`.
|
||||
- Schema-drift gate: `scripts/dump-schemas.py` (read-only AST walk over
|
||||
`workbench/schemas.py`, exact `scripts/dump-enums.py` pattern) →
|
||||
`schema-snapshot.json` → vitest asserts `src/types/api.ts` covers every
|
||||
dataclass field. Engine schema drift fails loudly at test time.
|
||||
|
||||
### Verification before push
|
||||
|
||||
```bash
|
||||
cd workbench-ui && pnpm build && pnpm test && pnpm test:e2e
|
||||
cd .. && uv run python scripts/dump-schemas.py > /dev/null # script runs clean
|
||||
```
|
||||
|
||||
PR title: `feat(workbench): design mastery pass — chain rail, typography, doctrine-as-tests`
|
||||
|
||||
---
|
||||
|
||||
## After this pack
|
||||
|
||||
R2 briefs (Trace upgraded, Runs, Audit, Packs, Vault, Settings — parallel)
|
||||
and R3 briefs (Replay Moment, deterministic DAG viewer, Demo Theater,
|
||||
wrong=0 ledger) are authored once R0/R1 are on main, against the real
|
||||
substrate. Specs and exclusions: `docs/workbench/wave-R-mastery-revamp.md`.
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
# Wave 1 — Evidence Spine
|
||||
|
||||
Status: approved plan
|
||||
Status: approved plan (Wave 1 shipped: PRs #702, #703, #704, #706);
|
||||
Wave 2 / Wave 3 sequencing below is superseded by
|
||||
[wave-R-mastery-revamp.md](./wave-R-mastery-revamp.md)
|
||||
Date: 2026-06-12
|
||||
Supersedes: implementation-plan.md phases W-032+
|
||||
Peer-reviewed by: Codex (architectural path selection), GPT5.5-Thinking (trace
|
||||
|
|
|
|||
313
docs/workbench/wave-R-mastery-revamp.md
Normal file
313
docs/workbench/wave-R-mastery-revamp.md
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
# Wave R — Mastery Revamp: Determinism Made Felt
|
||||
|
||||
Status: approved plan
|
||||
Date: 2026-06-12
|
||||
Refines: `wave-1-evidence-spine.md` — keeps its spine and Wave-1 deliverables
|
||||
(all shipped: PRs #702, #703, #704, #706); supersedes its Wave 2 / Wave 3
|
||||
sequencing with the upgraded specs below.
|
||||
Reviewed by: Claude Fable 5 (full re-audit of ADR-0160, ADR-0162, the shipped
|
||||
`origin/main` code, and the Wave 1 plan), approved by Shay.
|
||||
Execution-shape review (external, via Shay, 2026-06-12): R0 confirmed as a
|
||||
strict PR train, never one PR; honesty fix made unconditional in R0a; route
|
||||
conformance test front-loaded R1 → R0a; `Kbd` front-loaded R1 → R0d;
|
||||
KeyboardHelp made registry-driven in R0d; merge order pinned R0a-first.
|
||||
Declined with reasons: full serialization of echelon-1 dispatch (file
|
||||
surfaces verified disjoint; parallel dispatch retained with serial merge),
|
||||
and folding the Playwright lane into R0a (ADR-0162 acceptance 5–7 needs a
|
||||
dedicated, parallel-safe brief).
|
||||
|
||||
## Why a revamp before Wave 2
|
||||
|
||||
Wave 1 shipped the correct architecture — the evidence spine is real, tested,
|
||||
and on main. But a fresh audit of the shipped code against the doctrine found
|
||||
six gaps that compound if Wave 2 routes are built on top of them:
|
||||
|
||||
1. **The UI advertises capabilities that don't exist.** `KeyboardHelp.tsx`
|
||||
documents `j/k` list navigation and the Wave 1 keyboard map says it
|
||||
shipped — no list in the app implements it. `SearchInput`'s `/` binding is
|
||||
mounted nowhere. An audit-native product whose help overlay makes false
|
||||
claims is violating its own first pillar.
|
||||
2. **No evidence addresses.** Every route is a flat path (zero URL params in
|
||||
`App.tsx`). A selected turn, proposal, or eval result cannot be linked,
|
||||
bookmarked, or cited. For a product whose identity is "evidence you can
|
||||
hand to someone," the URL is the most important audit artifact — and it
|
||||
does not exist.
|
||||
3. **Doctrine lives in prose, not tests.** ADR-0162 acceptance criteria 5–7
|
||||
require Playwright (reduced-motion collapse, palette-from-every-route,
|
||||
offline preview). No Playwright exists. The empty/error/loading contract
|
||||
has no conformance test. Per CLAUDE.md's schema-defined proof obligations:
|
||||
a claim without a test that can meaningfully fail is decoration.
|
||||
4. **The deferred substrate is exactly what compounds.** Inspector resize,
|
||||
per-route `setSubject` call sites, palette action-commands, shared list
|
||||
navigation — all deferred "until a route needs them." Six Wave-2 routes
|
||||
need all of them simultaneously. Deferring means rework ×6.
|
||||
5. **Wave 2/3 were spec'd as CRUD.** "List with badges + detail panel" six
|
||||
times. Nothing visualizes the structures that make CORE distinct:
|
||||
proposition chains, proof-carrying promotion DAGs, entailment traces, the
|
||||
wrong=0 ledger.
|
||||
6. **No frontend CI lane exists at all.** `smoke.yml` and `full-pytest.yml`
|
||||
are Python-only. Frontend PRs merge with zero frontend CI verification,
|
||||
and the local full `pnpm test` hangs on worker teardown (live timer
|
||||
handles; diagnosed 2026-06-12).
|
||||
|
||||
## The design thesis
|
||||
|
||||
The blueprint asks for "Linear's calm + Raycast's speed + Instruments'
|
||||
precision." That is the floor. The ceiling — what no other AI product can
|
||||
copy honestly — is:
|
||||
|
||||
> **Every other AI UI animates fake cognition. This one makes real
|
||||
> determinism *felt*.**
|
||||
|
||||
Mastery is not more motion or more chrome (the ADR-0162 no-go list stands
|
||||
unchanged). Mastery is a small set of **signature interactions** that are
|
||||
only possible *because* the engine is deterministic:
|
||||
|
||||
| Signature interaction | What it is | Pillar it embodies |
|
||||
|---|---|---|
|
||||
| **The Evidence Address** | Every evidence subject (turn / proposal / artifact / eval result) has a canonical URL; inspector state serializes into it; `Cmd+Shift+C` copies it anywhere | Audit-native — a claim becomes a pasteable link |
|
||||
| **The Evidence Chain Rail** | The spine's seven stages (intent → subject → provenance → admissibility → replay → authority → action) as a persistent compact rail in the inspector, each stage lit with its actual status | Calm default, infinite depth — structure, zero theater |
|
||||
| **The Replay Moment** | Select any turn → Replay → side-by-side original/replay → two trace hashes resolve **equal**, leaf diff confirms zero divergence | Replay before persuasion — the honest wow |
|
||||
| **Deterministic structure rendering** | Proposal chains / PCCP proof-promotion DAGs / entailment traces as layered SVG DAGs with deterministic layout (same input → same pixels) | All three — interactive where masterful, static where honest |
|
||||
| **The wrong=0 ledger surface** | Evals render the correct/refused/wrong triplet as the canonical visualization; refusals first-class; failures-first ordering | Audit-native — the engine's epistemic honesty, visible |
|
||||
|
||||
Deterministic layout is doctrine, not preference: force-directed layouts are
|
||||
seeded-random, so the same evidence would render differently across sessions —
|
||||
a literal replay violation. Layered longest-path layout with lexicographic
|
||||
tie-breaking renders identically forever and is screenshot-diffable.
|
||||
|
||||
---
|
||||
|
||||
## Wave R0 — Substrate hardening
|
||||
|
||||
Blocks everything. Four briefs; R0a ∥ R0b ∥ R0c can run in parallel, R0d
|
||||
lands after R0c. **Brief 5 (Trace route) dispatch HOLDS until R0 lands** —
|
||||
Trace is the first consumer of this substrate and building it twice is waste.
|
||||
|
||||
### R0a — Test-runner hardening + frontend CI lane
|
||||
|
||||
- [ ] `vite.config.ts` test config gains `testTimeout`, `hookTimeout`,
|
||||
`teardownTimeout` caps so a hung worker fails fast instead of hanging to
|
||||
a CI wall
|
||||
- [ ] Timer hygiene audit: every `setInterval`/`setTimeout` in
|
||||
`workbench-ui/src/` has a cleanup path; component tests that mount
|
||||
timer-scheduling components (`Timestamp`, copy-feedback buttons) use
|
||||
fake timers
|
||||
- [ ] Full multi-file `pnpm test` completes and **exits** locally
|
||||
- [ ] New `.github/workflows/workbench-ui.yml`: path-filtered to
|
||||
`workbench-ui/**` **and the workflow file itself** (it validates its
|
||||
own changes), runs `pnpm install --frozen-lockfile && pnpm build
|
||||
&& pnpm test`, `timeout-minutes: 15`
|
||||
- [ ] Remove the `j/k`, `/`, and `Enter — Open selected item` rows from
|
||||
`KeyboardHelp.tsx` **unconditionally** — the overlay must not advertise
|
||||
shortcuts that do not exist. R0d restores them when they become real
|
||||
(and makes the overlay registry-driven so this class of dishonesty is
|
||||
structurally impossible)
|
||||
- [ ] Minimal route conformance test (front-loaded from R1 on
|
||||
execution-shape review): parametrized over the implemented routes
|
||||
(Chat, Proposals, Evals, Replay), asserts empty / error / loading each
|
||||
render with next-action / reproducer / specific-label content
|
||||
(ADR-0162 §6). Minimal means existing routes only — the harness is
|
||||
the contract every later route must pass; fix what fails, no
|
||||
expected-fail lists
|
||||
|
||||
### R0b — Playwright smoke lane (pays ADR-0162 acceptance debt 5/6/7)
|
||||
|
||||
- [ ] `@playwright/test` devDependency + `playwright.config.ts` with
|
||||
`webServer` (vite preview build)
|
||||
- [ ] e2e spec 1: `⌘K` opens the palette from every route; palette navigates
|
||||
to every route (acceptance criterion 6)
|
||||
- [ ] e2e spec 2: `prefers-reduced-motion: reduce` collapses tokenized motion
|
||||
to instant (acceptance criterion 5)
|
||||
- [ ] e2e spec 3: `/preview` renders every primitive with network access
|
||||
blocked (acceptance criterion 7 — offline-safe, per operator
|
||||
circumstances)
|
||||
- [ ] `pnpm test:e2e` script; CI job added to `workbench-ui.yml` (separate
|
||||
job so vitest results are not hostage to browser install)
|
||||
|
||||
### R0c — Evidence addresses (URL = subject)
|
||||
|
||||
- [ ] `workbench-ui/src/app/evidenceAddress.ts`: `subjectToUrl(subject)` /
|
||||
`urlToSubject(params, search)` codec, round-trip property tested for
|
||||
every `EvidenceSubject` kind
|
||||
- [ ] Route params in `App.tsx`: `/trace/:turnId?`, `/proposals/:proposalId?`,
|
||||
`/evals/:laneId?`, `/replay/:artifactId?` (placeholders keep flat paths
|
||||
until their R2 route lands; the codec already speaks their grammar)
|
||||
- [ ] `?inspect=` query param carries the inspector subject + open state;
|
||||
`EvidenceProvider` syncs with the URL (deep link restores inspector)
|
||||
- [ ] Existing routes (Proposals, Evals, Replay) read their param on load to
|
||||
restore selection and write it on selection change
|
||||
- [ ] `Cmd+Shift+C` global shortcut + palette command "Copy evidence link"
|
||||
(registered but inert until R0d's action-command plumbing; ships the
|
||||
shortcut, R0d ships the palette verb)
|
||||
- [ ] Tests: codec round-trip; deep-link restores Proposals selection;
|
||||
inspector state survives a simulated reload
|
||||
|
||||
### R0d — Interaction substrate (lands after R0c)
|
||||
|
||||
- [ ] `useListNavigation` hook: `j/k` + arrows + `Home`/`End` + `Enter` +
|
||||
input-focus guard; roving-tabindex or `aria-activedescendant` pattern
|
||||
- [ ] `VirtualizedList` primitive over `@tanstack/react-virtual`,
|
||||
composing `useListNavigation`; deterministic keys
|
||||
- [ ] `Panel` primitive: header / toolbar-slot / body chrome so routes stop
|
||||
hand-rolling borders
|
||||
- [ ] Inspector resize: wire the existing `SplitPane` into `Shell.tsx` for
|
||||
the inspector column; width persisted (storage access guarded, per the
|
||||
`af8d4f75` precedent)
|
||||
- [ ] Palette action commands: `commandRegistry` gains an action kind;
|
||||
per-route `register()` call sites (the deferred Wave-1 item); first
|
||||
verbs: "Copy evidence link", "Toggle inspector", "Run eval lane …"
|
||||
(registered by the Evals route; executes the existing read-only
|
||||
`POST /evals/run` — an ADR-0160-allowed lane, not a mutation)
|
||||
- [ ] Wire `useListNavigation` + `SearchInput` into the Proposals list and
|
||||
Replay artifact list now (at least two real consumers; `/` becomes real
|
||||
where a `SearchInput` is mounted)
|
||||
- [ ] `Kbd` primitive (front-loaded from R1 — KeyboardHelp and palette
|
||||
shortcut hints consume it)
|
||||
- [ ] `KeyboardHelp.tsx` becomes **registry-driven**: the overlay renders
|
||||
from the shortcut/command registry instead of a hand-maintained list,
|
||||
so advertising an unimplemented shortcut is structurally impossible.
|
||||
The rows R0a removed return here as real, registry-backed entries
|
||||
|
||||
---
|
||||
|
||||
## Wave R1 — Design mastery pass (one PR, after R0)
|
||||
|
||||
- [ ] Typography precision: `tabular-nums` for every metric cell
|
||||
(`MetadataTable` values, eval metrics, turn costs); type-scale audit;
|
||||
`text-wrap: balance` on headings
|
||||
- [ ] Selection-state unification: selected row vs focused row are visually
|
||||
distinct and consistent across routes (tokens, not per-route CSS)
|
||||
- [ ] Hash display standard: one rule (12-char truncation + copy + mono)
|
||||
everywhere; consolidate `CopyableHash` (chat) with `DigestBadge`
|
||||
(cleanup-as-you-find: remove the duplicate)
|
||||
- [ ] `EvidenceChainRail` component in `RightInspector`: seven stages, each
|
||||
lit (evidence present) / dim (not applicable) / hollow (not recorded).
|
||||
Statuses derive only from fields the subject actually carries — a stage
|
||||
with no data renders "not recorded", never a guess
|
||||
- [ ] Empty-state glyphs: small static deterministic monochrome SVGs
|
||||
- [ ] `Panel` adoption in Proposals + Evals (Chat/Replay opportunistic)
|
||||
- [ ] **Doctrine-as-tests** (route conformance moved to R0a; the rest here):
|
||||
- [ ] Raw-hex scan test: no hex/rgb literals in `src/**` outside
|
||||
`tokens.css`
|
||||
- [ ] Schema-drift gate: `scripts/dump-schemas.py` (read-only AST walk
|
||||
of `workbench/schemas.py`, same pattern as `dump-enums.py`) →
|
||||
snapshot → vitest asserts `types/api.ts` field coverage
|
||||
|
||||
---
|
||||
|
||||
## Wave R2 — Projections (parallel briefs, written after R0/R1 land)
|
||||
|
||||
Every route is the same triad — **list (virtualized, `j/k`) → detail (tabs) →
|
||||
inspector (chain rail)** — with evidence addresses and a conformance test.
|
||||
Briefs get authored against the landed substrate; the specs below are the
|
||||
commitments.
|
||||
|
||||
### Trace (Brief 5, upgraded — first dispatch of R2)
|
||||
|
||||
Everything in the existing Brief 5, plus: URL param selection via R0c codec,
|
||||
`useListNavigation` + `VirtualizedList` for the timeline, `Panel` chrome,
|
||||
versor-condition strip (see journal note below), and the conformance test.
|
||||
|
||||
### Runs / Audit / Packs / Vault / Settings
|
||||
|
||||
- **Runs** — `GET /runs`, `GET /runs/{session_id}`; session list with
|
||||
checkpoint badges; every turn cross-links to `/trace/:turnId`.
|
||||
- **Audit** — `GET /audit/events`; vertical event timeline (new `Timeline`
|
||||
primitive); mutation-boundary events visually weighted above routine events.
|
||||
- **Packs** — `GET /packs`, `GET /packs/{pack_id}`; new `TreeView` primitive;
|
||||
manifest checksum displayed with `DigestBadge` (verify affordance).
|
||||
- **Vault** — `GET /vault/summary`, `GET /vault/entries`; epistemic-state
|
||||
badges; exact-recall provenance (`cga_inner` evidence shown, never an
|
||||
approximate score — runtime recall is exact by doctrine).
|
||||
- **Settings** — localStorage prefs + read-only runtime config display; no
|
||||
engine mutation (CLI-only, stated in the UI).
|
||||
|
||||
**Journal addition (additive, append-only-safe):** an optional
|
||||
`versor_condition` field on journal entries — **investigate first**: it ships
|
||||
only if `ChatTurnResult`/runtime already exposes the value for the turn. The
|
||||
workbench layer must never compute field algebra itself. Older entries render
|
||||
"not recorded".
|
||||
|
||||
---
|
||||
|
||||
## Wave R3 — Theater (the wow, honest)
|
||||
|
||||
- **The Replay Moment** — implement the `/replay/{id}` backend (currently
|
||||
501): re-run a journaled turn deterministically, return original + replay
|
||||
envelopes; frontend hero flow renders hash-to-hash equality and a leaf diff
|
||||
with `≠` glyphs. Read-only; replay does not checkpoint.
|
||||
- **Deterministic DAG viewer** — one component, hand-rolled layered layout
|
||||
(longest-path layering, lexicographic tie-break, ~150 lines, golden-file
|
||||
layout tests, no graph dependency). Pan/zoom/click-node-→-inspector.
|
||||
Consumers: proposal chains, PCCP proof-promotion (8 scenarios from
|
||||
`demos/proof_carrying_promotion`), entailment traces.
|
||||
- **Demo Theater route** — `GET /demos`, `POST /demos/{id}/run`; scenario
|
||||
results with evidence-class badges and "what this proves / what this does
|
||||
not prove" honesty cards; proposer-was-wrong scenarios visually highlighted.
|
||||
- **wrong=0 ledger view** — Evals renders the correct/refused/wrong triplet
|
||||
as the primary visualization; refusal reasons inspectable; failures-first.
|
||||
|
||||
---
|
||||
|
||||
## Dependency DAG
|
||||
|
||||
```
|
||||
R0a ─┐
|
||||
R0b ─┼─(R0c)──→ R0d ──→ R1 ──→ R2 (Trace ∥ Runs ∥ Audit ∥ Packs ∥ Vault ∥ Settings) ──→ R3
|
||||
R0c ─┘
|
||||
```
|
||||
|
||||
R0a / R0b / R0c are parallel-safe to **dispatch** (disjoint files; trivial
|
||||
`package.json` merge between R0b and R0d is sequenced away). **Merge order
|
||||
is a strict train: R0a merges first** — it is the smallest PR, carries the
|
||||
honesty fix, and lands the CI lane that then verifies R0b and R0c; R0b/R0c
|
||||
merge next in either order; R0d follows R0c (shares
|
||||
`evidenceContext`/`Shell`). R1 is one PR after all of R0. R2 routes are
|
||||
mutually independent. R3 follows the R2 routes it draws data from — no
|
||||
theater work starts before R0/R1 are merged and tested.
|
||||
|
||||
## Keyboard map after R0
|
||||
|
||||
| Shortcut | Action | Status |
|
||||
|---|---|---|
|
||||
| `Cmd+K` | Command palette | shipped (Wave 1) |
|
||||
| `Cmd+I` | Toggle inspector | shipped (Wave 1) |
|
||||
| `Cmd+1`..`Cmd+0` | Navigate routes | shipped (Wave 1) |
|
||||
| `Cmd+Shift+C` | Copy evidence link | R0c |
|
||||
| `j/k` / arrows | List navigation | R0d (real, via `useListNavigation`) |
|
||||
| `/` | Focus search | R0d (real where `SearchInput` is mounted) |
|
||||
| `Enter` | Open selection | R0d |
|
||||
| `Esc` | Close overlay / clear selection | shipped + R0d |
|
||||
| `?` | Keyboard help | shipped (Wave 1; overlay lists only real shortcuts) |
|
||||
|
||||
## Explicit exclusions (unchanged from ADR-0160/0162 + Wave 1)
|
||||
|
||||
- No multi-user auth, cloud, SaaS, mobile
|
||||
- No animated cognition theater, glassmorphism, neon, decorative motion
|
||||
- No force-directed / nondeterministic graph layout — ever
|
||||
- No corpus/pack mutation from the UI; mutation only through admitted
|
||||
corridors (ADR-0172 pattern)
|
||||
- No framework churn: React 18 + Vite + stdlib-HTTP backend stay
|
||||
- New dependencies limited to: `@playwright/test` (dev),
|
||||
`@tanstack/react-virtual` (runtime, ~3 kB)
|
||||
|
||||
## Risks and standing decisions
|
||||
|
||||
- **DAG layout**: hand-rolled over `dagre`/`elkjs` — determinism is doctrine,
|
||||
graphs are small (<50 nodes), and the layout is a pure function with
|
||||
golden-file tests.
|
||||
- **`versor_condition` in the journal**: investigate-first; never computed in
|
||||
the workbench layer.
|
||||
- **Vitest hang**: if R0a's timer hygiene doesn't fully resolve teardown,
|
||||
the timeout caps still convert "hangs 30 min" into "fails in seconds" —
|
||||
the CI lane is safe either way.
|
||||
- **Pipeline merge model**: the AssetOverflow pipeline auto-merges agent
|
||||
branches; the reliable gate is pre-push verification. Every brief carries
|
||||
its own verification commands for this reason.
|
||||
|
||||
## Brief pack
|
||||
|
||||
Dispatch briefs for R0a–R0d and R1 live in
|
||||
`docs/handoff/wave-R-mastery-briefs-2026-06-12.md`. R2/R3 briefs are
|
||||
authored after R0/R1 land, against the real substrate.
|
||||
Loading…
Reference in a new issue