core/docs/handoff/wave-R-mastery-briefs-2026-06-12.md

15 KiB
Raw Permalink Blame History

Wave R Mastery Revamp — Dispatch Briefs (R0aR0d, 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: surfacearticulation_surfacewalk_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

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 setTimeouts); 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 buildpnpm 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

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

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

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

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

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

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 " (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

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

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

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.