13 KiB
Scene 11 Decision Beat Compression Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Reduce Scene 11 from three navigation beats to two so the typed interrupt and operator decision remain visible while revision/cancellation is represented as an approval outcome rather than a duplicate slide.
Architecture: Keep the existing typed-human-boundary scene, its factual GuidedProductMoment, and the existing DemoApprovalActions handlers. Remove only the storyboard-level cancel beat and the presentation-only plumbing that exists solely to support that beat. The canonical interrupt contract and run facts continue to expose submitted and cancelled outcomes, and Request revision continues to resume the same run through the negative outcome branch.
Tech Stack: React 19, TypeScript, Vitest, existing storyboard hash navigation, Valibot-backed demo projections.
Global Constraints
- Scene 11 remains scene number 11 with id
typed-human-boundary. - Scene 11 must contain exactly two beats, in order:
interrupt, thenapproval. - The approval beat remains the only UI entry point for both
SubmitandRequest revision. - Keep canonical persisted outcome values
submittedandcancelled; do not rename backend or replay fields torevision_requested. - Do not change
useDemoTimeline, live RPC execution, run facts, approval handlers, or Scene 12 behavior. #scene/typed-human-boundary/cancelmust fail closed todefaultMainLocation; it must not become an alias.- Keep the single Editorial Canvas and existing hidden internal-scroll behavior.
- Do not add dependencies, a second state store, or a new transport.
Task 1: Update The Storyboard Contract
Files:
- Create:
docs/superpowers/plans/2026-07-12-scene-11-decision-beat-compression.md - Modify:
docs/current_roadmap.md - Modify:
web/apps/console/src/presentation/storyboard.ts - Test:
web/apps/console/src/presentation/storyboard.test.ts
Interfaces:
-
Produces the canonical Scene 11 beat list consumed by
nextMainLocation,locationFromHash, andSceneBody. -
The resulting beat ids are exactly
readonly ["interrupt", "approval"]. -
Step 1: Add the failing storyboard contract test
Add a test that asserts the exact beat sequence and rejects the removed route:
it("compresses Scene 11 into interrupt context and one operator decision beat", () => {
expect(findScene("typed-human-boundary")?.beats.map((beat) => beat.id)).toEqual([
"interrupt",
"approval",
]);
expect(findBeat("typed-human-boundary", "interrupt")?.caption).toMatch(/boundary|interrupt/i);
expect(findBeat("typed-human-boundary", "approval")?.caption).toMatch(/decision|resume/i);
expect(findBeat("typed-human-boundary", "cancel")).toBeUndefined();
});
Keep the existing scene-number assertions. Update any existing Scene 11 tests that still expect cancel to expect only the two-beat contract.
- Step 2: Run the focused test and verify it fails
Run:
pnpm --dir web --filter @lda/console test -- src/presentation/storyboard.test.ts
Expected: the new test fails because storyboard.ts still declares the cancel beat.
- Step 3: Remove only the redundant storyboard beat
In storyboard.ts, delete the sceneBeat("cancel", ...) entry from typed-human-boundary. Keep the interrupt caption and both beats' hidden chat configuration unchanged; the approval caption may be clarified to describe both outcomes.
Use copy that makes the decision beat cover both outcomes, for example:
sceneBeat(
"approval",
"Approval",
"The operator chooses a submitted or revision-requested outcome for the paused run.",
{ chatMode: "hidden", chatTheme: "light" },
),
Do not add a separate cancel or revision beat.
- Step 4: Update the live roadmap link
Under ## Next: Scene 8–14 Defense Recomposition, update item 4 to link the active plan:
4. **Scene 11 compression:** reduce the typed-human-boundary scene to two
beats: interrupt context and approval decision. Cancellation remains a
decision outcome rather than a near-duplicate presentation beat.
Implementation plan:
[`Scene 11 decision beat compression`](superpowers/plans/2026-07-12-scene-11-decision-beat-compression.md).
- Step 5: Run the storyboard tests and commit
Run:
pnpm --dir web --filter @lda/console test -- src/presentation/storyboard.test.ts
Expected: all storyboard tests pass. Commit the plan, roadmap link, storyboard, and tests:
git add docs/superpowers/plans/2026-07-12-scene-11-decision-beat-compression.md docs/current_roadmap.md web/apps/console/src/presentation/storyboard.ts web/apps/console/src/presentation/storyboard.test.ts
git commit -m "feat: compress Scene 11 storyboard beats"
Task 2: Remove The Stale Replay Requirement And Verify Navigation
Files:
- Modify:
web/apps/console/src/presentation/demo-beat-requirements.ts - Test:
web/apps/console/src/presentation/demo-beat-requirements.test.ts - Test:
web/apps/console/src/presentation/storyboard-navigation.test.ts
Interfaces:
-
requirementForDemoBeat("typed-human-boundary", "approval")continues to require theinterruptstage. -
No requirement exists for
typed-human-boundary/cancel. -
Step 1: Add failing navigation assertions
Extend the navigation tests with these assertions:
it("advances Scene 11 directly from interrupt to approval, then Scene 12", () => {
const interrupt = { kind: "main", sceneId: "typed-human-boundary", beatId: "interrupt", focusPath: [] } as const;
const approval = { kind: "main", sceneId: "typed-human-boundary", beatId: "approval", focusPath: [] } as const;
expect(nextMainLocation(interrupt)).toEqual(approval);
expect(nextMainLocation(approval)).toMatchObject({
kind: "main",
sceneId: "resume-output-evidence",
beatId: "resume",
});
});
it("fails closed for the removed Scene 11 cancel hash", () => {
expect(locationFromHash("#scene/typed-human-boundary/cancel")).toEqual(defaultMainLocation);
});
Update the existing demo requirement table to cover only interrupt and approval for Scene 11.
- Step 2: Run the focused tests and verify stale support is exposed
Run:
pnpm --dir web --filter @lda/console test -- src/presentation/demo-beat-requirements.test.ts src/presentation/storyboard-navigation.test.ts
Expected: the navigation test should pass after Task 1; any remaining failure should identify a stale cancel requirement or test expectation.
- Step 3: Remove the obsolete cancel requirement
Delete the "typed-human-boundary/cancel" entry from demo-beat-requirements.ts. Keep the interrupt and approval entries requiring requiredStage: "interrupt".
- Step 4: Verify and commit navigation cleanup
Run the same focused command. Expected: all tests pass, including the default fallback for the removed hash.
git add web/apps/console/src/presentation/demo-beat-requirements.ts web/apps/console/src/presentation/demo-beat-requirements.test.ts web/apps/console/src/presentation/storyboard-navigation.test.ts
git commit -m "test: enforce Scene 11 decision navigation"
Task 3: Remove Cancel-Specific Scene Rendering Plumbing
Files:
- Modify:
web/apps/console/src/presentation/DemoWorkflowScene.tsx - Test:
web/apps/console/src/presentation/DemoWorkflowScene.test.tsx - Test:
web/apps/console/src/presentation/GuidedProductMoment.test.tsx
Interfaces:
-
DemoWorkflowScenemapsapprovalto the approval layout; no rendering branch acceptscancelas a presentation beat. -
GuidedProductMomentremains the factual Scene 11 renderer and continues to expose both decision controls. -
Step 1: Add the approval-outcome regression test
In the existing approval composition test, assert both available operator outcomes remain visible:
expect(screen.getByRole("button", { name: "Submit" })).toBeEnabled();
expect(screen.getByRole("button", { name: "Request revision" })).toBeEnabled();
expect(screen.getByText(/submitted\s*\/\s*cancelled/i)).toBeInTheDocument();
Add or update the DemoWorkflowScene test to render the approval beat and assert its root has data-demo-layout="approval". Do not add a cancel render case.
- Step 2: Run the focused tests and verify the existing branch is covered
Run:
pnpm --dir web --filter @lda/console test -- src/presentation/DemoWorkflowScene.test.tsx src/presentation/GuidedProductMoment.test.tsx
- Step 3: Remove the stale
cancellayout condition
In DemoWorkflowScene.tsx, simplify:
if (beatId === "approval") return "approval";
Do not change GuidedProductMoment, DemoApprovalActions, InterruptDecisionForm, or the underlying outcome projection unless a focused test demonstrates a regression. The existing Request revision action is the intended negative outcome within the approval beat.
- Step 4: Run the focused tests and commit
Run the focused command again. Expected: all Scene 11 composition tests pass and no test references a cancel presentation beat.
git add web/apps/console/src/presentation/DemoWorkflowScene.tsx web/apps/console/src/presentation/DemoWorkflowScene.test.tsx web/apps/console/src/presentation/GuidedProductMoment.test.tsx
git commit -m "refactor: keep Scene 11 outcomes in approval beat"
Task 4: Full Verification, Visual Smoke, Review, And Archive
Files:
-
Modify:
docs/current_roadmap.md -
Move:
docs/superpowers/plans/2026-07-12-scene-11-decision-beat-compression.mdtodocs/historical/superpowers/plans/2026-07-12-scene-11-decision-beat-compression.md -
Step 1: Run the presentation verification gate
Run:
pnpm --dir web --filter @lda/console test -- src/presentation
pnpm --dir web typecheck
pnpm --dir web --filter @lda/console build
git diff --check
Expected: all presentation tests, typechecking, and the console build pass. The existing Vite chunk-size warning is acceptable; new failures are not.
- Step 2: Run direct-route visual smoke
With pnpm dev running, inspect these routes at 1280x720, 1024x768, and 1920x1080:
http://127.0.0.1:5173/present#scene/typed-human-boundary/interrupt
http://127.0.0.1:5173/present#scene/typed-human-boundary/approval
http://127.0.0.1:5173/present#scene/typed-human-boundary/cancel
Expected:
-
Interrupt shows the typed interrupt context.
-
Approval shows the decision form with Submit and Request revision; no separate cancel slide is needed.
-
The removed cancel route falls back to the default presentation location.
-
Advancing from approval reaches Scene 12 resume directly.
-
No outer document scrollbar appears.
-
Step 3: Search for stale presentation-beat references
Run:
rg -n 'sceneBeat\("cancel"|typed-human-boundary/cancel|findBeat\("typed-human-boundary", "cancel"\)|beatId === "cancel"' web/apps/console/src/presentation docs/current_roadmap.md web/README.md -g '!*.test.ts' -g '!*.test.tsx'
Expected: no matches in production/docs files. The negative-route tests intentionally retain the removed hash and findBeat assertion. Other uses of the factual persisted outcome string cancelled, runtime cancellation variables, and Request revision are valid and must remain.
- Step 4: Run independent review
Run the repository review task against the implementation commits. Fix only concrete findings related to stale navigation, incorrect Scene 11 state, approval outcome semantics, or regressions in existing routes. Do not expand this slice into the broader visual scale/color pass.
- Step 5: Archive the completed plan and close the roadmap item
After verification and review, change item 4 under ## Next: Scene 8–14 Defense Recomposition from the active wording to Completed, link the historical plan, and move the plan:
Move-Item docs/superpowers/plans/2026-07-12-scene-11-decision-beat-compression.md docs/historical/superpowers/plans/2026-07-12-scene-11-decision-beat-compression.md
git add docs/current_roadmap.md docs/historical/superpowers/plans/2026-07-12-scene-11-decision-beat-compression.md
git commit -m "docs: complete Scene 11 decision beat compression"
Self-Review Checklist
- Scene 11 has exactly
interruptandapprovalbeats. - The approval surface still exposes both
SubmitandRequest revision. - Canonical
submittedandcancelledoutcome data is unchanged. #scene/typed-human-boundary/cancelfails closed instead of aliasing approval.- Approval advances directly to Scene 12 resume.
- No live RPC, replay event, or Scene 12 behavior changed.
- No stale cancel beat references remain in presentation navigation or requirements.
- Presentation tests, typecheck, build, visual smoke, and review pass before archival.