# Demo Climax Craft Pass 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:** Make Scenes 9 and 10 read as one clear product demonstration: an agent-facing request becomes a persisted workflow run, reaches a typed human interrupt, resumes, and leaves inspectable evidence. **Architecture:** Keep the prepared replay, JSON-RPC evidence, and existing graph components unchanged. Add a thin presentation model that describes each demo beat, then render that model through small visual components inside `DemoWorkflowScene`. This is a presentation craft pass, not a new console feature, transport, agent driver, or runtime workflow. **Tech Stack:** React, TypeScript, Vitest, Testing Library, Motion, existing `@lda/console` presentation CSS, prepared replay data. ## Global Constraints - Do not add live backend dependencies; `/present` must remain replay-first. - Do not replace React Flow or the existing `WorkflowGraphStage` in this slice. - Do not change workflow runtime, RPC schemas, demo recording format, or `examples/lda_report_workflow`. - Keep Scene 9 and Scene 10 routes and beat ids stable: - `workflow-demo`: `operation`, `graph`, `interrupt` - `interrupt-evidence`: `approval`, `resume`, `output`, `trace` - Prefer small presentation components over growing `DemoWorkflowScene.tsx` into a large conditional file. - Add comments around any non-obvious layout or evidence-projection logic. - Keep browser zoom overflow compatible with the current hidden-scroll stage behavior. --- ## File Structure - Modify `web/apps/console/src/presentation/demo-workflow-model.ts` - Add the presentation-only beat lens that gives each demo beat a headline, proof label, active phase, and presenter-facing summary. - Modify `web/apps/console/src/presentation/demo-workflow-model.test.ts` - Cover every Scene 9/10 beat id and the graph execution continuity. - Create `web/apps/console/src/presentation/DemoContinuityRail.tsx` - Render the product story spine: agent request -> workflow run -> human boundary -> persisted evidence. - Create `web/apps/console/src/presentation/DemoContinuityRail.test.tsx` - Verify labels, active phase, and compact proof text. - Create `web/apps/console/src/presentation/DemoOutcomePanel.tsx` - Render beat-specific proof for approval, resume, output, and trace without inventing data. - Create `web/apps/console/src/presentation/DemoOutcomePanel.test.tsx` - Verify typed interrupt language, submitted/cancelled outcomes, persisted run continuity, output/evidence copy. - Modify `web/apps/console/src/presentation/DemoWorkflowScene.tsx` - Compose continuity rail, graph, operation block, contract preview, and outcome panel. - Modify `web/apps/console/src/presentation/DemoWorkflowScene.test.tsx` - Pin Scene 9/10 choreography and guard against losing the graph/contract/evidence. - Modify `web/apps/console/src/presentation/styles/demo-workflow.css` - Add layout and responsive styling for the continuity rail and outcome panel. - Modify `web/README.md` - Update Presentation Mode docs with the new demo-climax behavior. - Modify `docs/current_roadmap.md` - Mark the presentation craft pass as completed after implementation and link this plan under `historical/`. - Move this plan to `docs/historical/superpowers/plans/2026-07-08-demo-climax-craft-pass.md` after implementation. --- ### Task 1: Add A Demo Beat Lens **Files:** - Modify: `web/apps/console/src/presentation/demo-workflow-model.ts` - Modify: `web/apps/console/src/presentation/demo-workflow-model.test.ts` **Interfaces:** - Consumes: demo beat ids from `storyboard.ts`. - Produces: - `type DemoClimaxPhase = "agent" | "run" | "interrupt" | "resume" | "evidence"` - `type DemoBeatLens` - `demoBeatLensForBeat(beatId: string): DemoBeatLens` - [ ] **Step 1: Write failing tests for the beat lens** In `web/apps/console/src/presentation/demo-workflow-model.test.ts`, add these imports: ```ts import { demoBeatLensForBeat, graphExecutionForBeat, projectInterruptContract, projectOperationPresentation, } from "./demo-workflow-model.js"; ``` If the file already imports some of these symbols, merge the imports instead of duplicating them. Add this test block: ```ts describe("demo beat lens", () => { it("defines a product-story phase for every Scene 9 and Scene 10 beat", () => { const beatIds = ["operation", "graph", "interrupt", "approval", "resume", "output", "trace"]; expect(beatIds.map((beatId) => demoBeatLensForBeat(beatId).phase)).toEqual([ "agent", "run", "interrupt", "interrupt", "resume", "evidence", "evidence", ]); }); it("uses stable audience-facing labels for the demo climax", () => { expect(demoBeatLensForBeat("operation")).toMatchObject({ eyebrow: "Agent handoff", headline: "Request becomes a workflow run", proofLabel: "workflow.runs.start", }); expect(demoBeatLensForBeat("approval")).toMatchObject({ eyebrow: "Typed human boundary", headline: "The run waits for an explicit resume decision", proofLabel: "issue_review", }); expect(demoBeatLensForBeat("trace")).toMatchObject({ eyebrow: "Evidence remains", headline: "The result can still be inspected after the demo", proofLabel: "trace frames", }); }); it("keeps graph execution continuity across the interrupt and resume beats", () => { expect(graphExecutionForBeat("approval")).toEqual(graphExecutionForBeat("interrupt")); expect(graphExecutionForBeat("resume")).toMatchObject({ completedNodeIds: ["read_docs", "build_report", "review_issues"], currentNodeId: "create_issues", }); expect(graphExecutionForBeat("trace")).toMatchObject({ currentNodeId: "end_completed", }); }); }); ``` - [ ] **Step 2: Run the tests and verify they fail** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/demo-workflow-model.test.ts ``` Expected: fail with `demoBeatLensForBeat` not exported. - [ ] **Step 3: Implement the beat lens** In `web/apps/console/src/presentation/demo-workflow-model.ts`, add these exports after `GraphExecutionPresentation`: ```ts export type DemoClimaxPhase = "agent" | "run" | "interrupt" | "resume" | "evidence"; export type DemoBeatLens = { readonly phase: DemoClimaxPhase; readonly eyebrow: string; readonly headline: string; readonly proofLabel: string; readonly speakerLine: string; }; const demoBeatLensByBeat: Readonly> = { operation: { phase: "agent", eyebrow: "Agent handoff", headline: "Request becomes a workflow run", proofLabel: "workflow.runs.start", speakerLine: "The AI-facing layer does not own execution; it asks lda.chat to start a durable workflow run.", }, graph: { phase: "run", eyebrow: "Durable graph", headline: "The product owns the reusable workflow shape", proofLabel: "typed graph", speakerLine: "The graph is the reusable automation boundary, not a one-off transcript of tool calls.", }, interrupt: { phase: "interrupt", eyebrow: "Typed pause", headline: "Execution stops at a declared human boundary", proofLabel: "issue_review", speakerLine: "The runtime exposes what decision is needed before any mutation continues.", }, approval: { phase: "interrupt", eyebrow: "Typed human boundary", headline: "The run waits for an explicit resume decision", proofLabel: "issue_review", speakerLine: "The operator answers a schema-backed request; the run remains persisted while waiting.", }, resume: { phase: "resume", eyebrow: "Same run resumes", headline: "The approved payload continues the persisted run", proofLabel: "workflow.runs.resume", speakerLine: "Resume is not a restart; it continues the stopped run with a validated payload.", }, output: { phase: "evidence", eyebrow: "Workflow output", headline: "The workflow produces artifacts outside the chat", proofLabel: "report + issues", speakerLine: "The result is inspectable product state: a report and issue-board changes.", }, trace: { phase: "evidence", eyebrow: "Evidence remains", headline: "The result can still be inspected after the demo", proofLabel: "trace frames", speakerLine: "Trace and protocol evidence keep the demo auditable after the live moment is over.", }, }; /** * Presentation-only copy for the demo climax. This intentionally stays separate * from replay evidence parsing so changing speaker framing cannot mutate the * canonical run recording. */ export const demoBeatLensForBeat = (beatId: string): DemoBeatLens => demoBeatLensByBeat[beatId] ?? { phase: "run", eyebrow: "Workflow", headline: "Workflow state", proofLabel: beatId, speakerLine: "This beat is not part of the prepared demo climax.", }; ``` - [ ] **Step 4: Run the tests and verify they pass** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/demo-workflow-model.test.ts ``` Expected: all tests in the file pass. - [ ] **Step 5: Commit Task 1** ```powershell git add web/apps/console/src/presentation/demo-workflow-model.ts web/apps/console/src/presentation/demo-workflow-model.test.ts git commit -m "feat: model demo climax beats" ``` --- ### Task 2: Add The Demo Continuity Rail **Files:** - Create: `web/apps/console/src/presentation/DemoContinuityRail.tsx` - Create: `web/apps/console/src/presentation/DemoContinuityRail.test.tsx` - Modify: `web/apps/console/src/presentation/styles/demo-workflow.css` **Interfaces:** - Consumes: `DemoBeatLens` from Task 1. - Produces: - `DemoContinuityRail({ lens }: { readonly lens: DemoBeatLens })` - [ ] **Step 1: Write the failing component tests** Create `web/apps/console/src/presentation/DemoContinuityRail.test.tsx`: ```tsx import { cleanup, render, screen, within } from "@testing-library/react"; import { afterEach, describe, expect, it } from "vitest"; import { demoBeatLensForBeat } from "./demo-workflow-model.js"; import { DemoContinuityRail } from "./DemoContinuityRail.js"; afterEach(() => cleanup()); describe("DemoContinuityRail", () => { it("renders the four-step product story spine", () => { render(); const rail = screen.getByLabelText("demo continuity"); expect(within(rail).getByText("Agent request")).toBeInTheDocument(); expect(within(rail).getByText("Workflow run")).toBeInTheDocument(); expect(within(rail).getByText("Human boundary")).toBeInTheDocument(); expect(within(rail).getByText("Evidence")).toBeInTheDocument(); }); it("marks the current phase and shows the current proof label", () => { render(); expect(screen.getByText("workflow.runs.resume")).toBeInTheDocument(); expect(screen.getByText("Human boundary").closest("[data-active]")).toHaveAttribute( "data-active", "false", ); expect(screen.getByText("Evidence").closest("[data-active]")).toHaveAttribute( "data-active", "false", ); expect(screen.getByText("Workflow run").closest("[data-active]")).toHaveAttribute( "data-completed", "true", ); }); }); ``` - [ ] **Step 2: Run the tests and verify they fail** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DemoContinuityRail.test.tsx ``` Expected: fail because `DemoContinuityRail.tsx` does not exist. - [ ] **Step 3: Implement `DemoContinuityRail`** Create `web/apps/console/src/presentation/DemoContinuityRail.tsx`: ```tsx import type { DemoBeatLens, DemoClimaxPhase } from "./demo-workflow-model.js"; type DemoContinuityRailProps = { readonly lens: DemoBeatLens; }; type RailStep = { readonly phase: DemoClimaxPhase; readonly label: string; readonly detail: string; }; const railSteps: ReadonlyArray = [ { phase: "agent", label: "Agent request", detail: "thin interface" }, { phase: "run", label: "Workflow run", detail: "typed runtime" }, { phase: "interrupt", label: "Human boundary", detail: "schema-backed" }, { phase: "evidence", label: "Evidence", detail: "traceable output" }, ]; const phaseOrder: ReadonlyArray = [ "agent", "run", "interrupt", "resume", "evidence", ]; const normalizedPhase = (phase: DemoClimaxPhase): DemoClimaxPhase => phase === "resume" ? "interrupt" : phase; export const DemoContinuityRail = ({ lens }: DemoContinuityRailProps) => { const currentPhase = normalizedPhase(lens.phase); const currentIndex = phaseOrder.indexOf(lens.phase); return (
{lens.eyebrow} {lens.headline} {lens.proofLabel}
    {railSteps.map((step) => { const stepIndex = phaseOrder.indexOf(step.phase); const active = step.phase === currentPhase; const completed = stepIndex < currentIndex; return (
  1. {step.label} {step.detail}
  2. ); })}
); }; ``` - [ ] **Step 4: Add rail CSS** Append these selectors near the other demo workflow stage selectors in `web/apps/console/src/presentation/styles/demo-workflow.css`: ```css .demo-continuity-rail { display: grid; grid-template-columns: minmax(16rem, 0.72fr) minmax(0, 1fr); gap: 0.9rem; align-items: stretch; flex: 0 0 auto; margin-bottom: 0.65rem; } .demo-continuity-rail__proof { display: grid; gap: 0.2rem; border: 1px solid oklch(0.72 0.17 195 / 0.34); border-radius: 0.75rem; padding: 0.65rem 0.8rem; background: oklch(0.12 0.022 250 / 0.82); } .demo-continuity-rail__proof span { color: var(--accent-cyan); font: 700 0.62rem/1 var(--font-mono, monospace); letter-spacing: 0.11em; text-transform: uppercase; } .demo-continuity-rail__proof strong { color: var(--text-primary); font-size: 0.92rem; line-height: 1.15; } .demo-continuity-rail__proof code { color: var(--text-secondary); font: 600 0.68rem/1.2 var(--font-mono, monospace); } .demo-continuity-rail__steps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.45rem; margin: 0; padding: 0; list-style: none; } .demo-continuity-rail__steps li { display: grid; align-content: center; gap: 0.18rem; min-width: 0; border: 1px solid var(--stage-line); border-radius: 0.65rem; padding: 0.55rem 0.65rem; background: oklch(0.135 0.022 250 / 0.72); color: var(--text-muted); } .demo-continuity-rail__steps li[data-completed="true"] { border-color: oklch(0.72 0.17 195 / 0.36); color: var(--text-secondary); } .demo-continuity-rail__steps li[data-active="true"] { border-color: var(--accent-cyan); background: oklch(0.18 0.052 210 / 0.92); color: var(--text-primary); } .demo-continuity-rail__steps span { overflow: hidden; font: 700 0.74rem/1.1 var(--font-interface, sans-serif); text-overflow: ellipsis; white-space: nowrap; } .demo-continuity-rail__steps small { color: color-mix(in oklch, currentColor 70%, transparent); font: 600 0.6rem/1.1 var(--font-mono, monospace); } @container presentation-canvas (max-width: 1050px) { .demo-continuity-rail { grid-template-columns: minmax(0, 1fr); } } ``` - [ ] **Step 5: Run the tests and verify they pass** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DemoContinuityRail.test.tsx ``` Expected: all tests pass. - [ ] **Step 6: Commit Task 2** ```powershell git add web/apps/console/src/presentation/DemoContinuityRail.tsx web/apps/console/src/presentation/DemoContinuityRail.test.tsx web/apps/console/src/presentation/styles/demo-workflow.css git commit -m "feat: add demo continuity rail" ``` --- ### Task 3: Add Scene 10 Outcome Proof **Files:** - Create: `web/apps/console/src/presentation/DemoOutcomePanel.tsx` - Create: `web/apps/console/src/presentation/DemoOutcomePanel.test.tsx` - Modify: `web/apps/console/src/presentation/styles/demo-workflow.css` **Interfaces:** - Consumes: - `DemoBeatLens` - `OperationPresentation | null` - `InterruptContractPresentation | null` - Produces: - `DemoOutcomePanel({ beatId, lens, operation, contract })` - [ ] **Step 1: Write the failing component tests** Create `web/apps/console/src/presentation/DemoOutcomePanel.test.tsx`: ```tsx import { cleanup, render, screen } from "@testing-library/react"; import { afterEach, describe, expect, it } from "vitest"; import { demoBeatLensForBeat, type InterruptContractPresentation, type OperationPresentation, } from "./demo-workflow-model.js"; import { DemoOutcomePanel } from "./DemoOutcomePanel.js"; afterEach(() => cleanup()); const operation: OperationPresentation = { operation: "workflow.runs.resume", status: "completed", durationMs: 42, command: "uv run wf run resume run_recorded_lda_report", deploymentId: "lda_report_workflow.default", runId: "run_recorded_lda_report", interruptKind: null, }; const contract: InterruptContractPresentation = { kind: "issue_review", outcomes: ["submitted", "cancelled"], resumeSchema: { type: "object" }, runId: "run_recorded_lda_report", }; describe("DemoOutcomePanel", () => { it("explains the approval beat as a schema-backed decision", () => { render( , ); expect(screen.getByLabelText("demo outcome proof")).toHaveTextContent("schema-backed"); expect(screen.getByText("submitted / cancelled")).toBeInTheDocument(); expect(screen.getByText("run_recorded_lda_report")).toBeInTheDocument(); }); it("explains resume as same-run continuation", () => { render( , ); expect(screen.getByText("Same persisted run")).toBeInTheDocument(); expect(screen.getByText("workflow.runs.resume")).toBeInTheDocument(); expect(screen.getByText("completed")).toBeInTheDocument(); }); it("explains output and trace without pretending to run live services", () => { const { rerender } = render( , ); expect(screen.getByText("Report markdown")).toBeInTheDocument(); expect(screen.getByText("Issue board changes")).toBeInTheDocument(); rerender( , ); expect(screen.getByText("Trace frames")).toBeInTheDocument(); expect(screen.getByText("Protocol evidence")).toBeInTheDocument(); }); }); ``` - [ ] **Step 2: Run the tests and verify they fail** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DemoOutcomePanel.test.tsx ``` Expected: fail because `DemoOutcomePanel.tsx` does not exist. - [ ] **Step 3: Implement `DemoOutcomePanel`** Create `web/apps/console/src/presentation/DemoOutcomePanel.tsx`: ```tsx import type { DemoBeatLens, InterruptContractPresentation, OperationPresentation, } from "./demo-workflow-model.js"; type DemoOutcomePanelProps = { readonly beatId: string; readonly lens: DemoBeatLens; readonly operation: OperationPresentation | null; readonly contract: InterruptContractPresentation | null; }; const outcomesText = (contract: InterruptContractPresentation | null): string => contract?.outcomes.join(" / ") ?? "submitted / cancelled"; export const DemoOutcomePanel = ({ beatId, lens, operation, contract, }: DemoOutcomePanelProps) => { const runId = operation?.runId ?? contract?.runId ?? "run unavailable"; if (beatId === "approval") { return ( ); } if (beatId === "resume") { return ( ); } if (beatId === "output") { return ( ); } return ( ); }; ``` - [ ] **Step 4: Add outcome panel CSS** Append near the interrupt contract selectors in `web/apps/console/src/presentation/styles/demo-workflow.css`: ```css .demo-outcome-panel { display: grid; gap: 0.65rem; align-content: start; border: 1px solid oklch(0.76 0.18 70 / 0.38); border-radius: 0.85rem; padding: 0.85rem; background: linear-gradient(145deg, oklch(0.76 0.18 70 / 0.08), transparent 55%), oklch(0.13 0.025 250 / 0.9); color: var(--text-primary); } .demo-outcome-panel > span { color: var(--accent-amber); font: 700 0.62rem/1 var(--font-mono, monospace); letter-spacing: 0.11em; text-transform: uppercase; } .demo-outcome-panel > strong { font-size: 1rem; line-height: 1.18; } .demo-outcome-panel dl { display: grid; gap: 0.45rem; margin: 0; } .demo-outcome-panel dt { color: var(--text-muted); font: 700 0.58rem/1 var(--font-mono, monospace); letter-spacing: 0.08em; text-transform: uppercase; } .demo-outcome-panel dd { margin: 0.2rem 0 0; color: var(--text-secondary); font-size: 0.78rem; } .demo-outcome-panel ul { display: grid; gap: 0.5rem; margin: 0; padding: 0; list-style: none; } .demo-outcome-panel li { border: 1px solid var(--stage-line); border-radius: 0.65rem; padding: 0.6rem; background: oklch(0.11 0.022 250 / 0.72); } .demo-outcome-panel b { display: block; margin-bottom: 0.25rem; } .demo-outcome-panel small { color: var(--text-secondary); } ``` - [ ] **Step 5: Run tests and verify they pass** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DemoOutcomePanel.test.tsx ``` Expected: all tests pass. - [ ] **Step 6: Commit Task 3** ```powershell git add web/apps/console/src/presentation/DemoOutcomePanel.tsx web/apps/console/src/presentation/DemoOutcomePanel.test.tsx web/apps/console/src/presentation/styles/demo-workflow.css git commit -m "feat: add demo outcome proof panel" ``` --- ### Task 4: Compose The Rail And Outcome Panel Into Scenes 9 And 10 **Files:** - Modify: `web/apps/console/src/presentation/DemoWorkflowScene.tsx` - Modify: `web/apps/console/src/presentation/DemoWorkflowScene.test.tsx` - Modify: `web/apps/console/src/presentation/styles/demo-workflow.css` **Interfaces:** - Consumes: - `demoBeatLensForBeat(beatId)` - `DemoContinuityRail` - `DemoOutcomePanel` - existing `OperationBlock`, `WorkflowGraphStage`, `InterruptContractPreview` - Produces: Scene 9/10 route compositions with a stable continuity rail and beat-specific outcome proof. - [ ] **Step 1: Write failing integration tests** In `web/apps/console/src/presentation/DemoWorkflowScene.test.tsx`, add these tests inside the existing `describe("DemoWorkflowScene", ...)`: ```tsx it("shows the continuity rail across Scene 9 operation, graph, and interrupt beats", () => { const { unmount } = renderBeat("operation"); expect(screen.getByLabelText("demo continuity")).toHaveTextContent("Request becomes a workflow run"); expect(screen.getByLabelText("demo continuity")).toHaveTextContent("workflow.runs.start"); unmount(); const graph = renderBeat("graph"); expect(screen.getByLabelText("demo continuity")).toHaveTextContent("The product owns the reusable workflow shape"); graph.unmount(); renderBeat("interrupt"); expect(screen.getByLabelText("demo continuity")).toHaveTextContent("Execution stops at a declared human boundary"); }); it("adds outcome proof to approval, resume, output, and trace beats", () => { const approval = renderBeat("approval", "interrupt-evidence"); expect(screen.getByLabelText("demo outcome proof")).toHaveTextContent("schema-backed"); approval.unmount(); const resume = renderBeat("resume", "interrupt-evidence"); expect(screen.getByLabelText("demo outcome proof")).toHaveTextContent("Same persisted run"); resume.unmount(); const output = renderBeat("output", "interrupt-evidence"); expect(screen.getByLabelText("demo outcome proof")).toHaveTextContent("Report markdown"); output.unmount(); renderBeat("trace", "interrupt-evidence"); expect(screen.getByLabelText("demo outcome proof")).toHaveTextContent("Trace frames"); }); ``` - [ ] **Step 2: Run tests and verify they fail** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DemoWorkflowScene.test.tsx ``` Expected: fail because `demo continuity` and `demo outcome proof` are not rendered. - [ ] **Step 3: Compose the new components** In `web/apps/console/src/presentation/DemoWorkflowScene.tsx`, update imports: ```ts import { DemoContinuityRail } from "./DemoContinuityRail.js"; import { DemoOutcomePanel } from "./DemoOutcomePanel.js"; import { demoBeatLensForBeat, graphExecutionForBeat, projectInterruptContract, projectOperationPresentation, } from "./demo-workflow-model.js"; ``` Replace the current model import block with the above merged import. Inside `DemoWorkflowScene`, after `const layout = layoutForBeat(beat.id);`, add: ```ts const lens = demoBeatLensForBeat(beat.id); const currentOperation = currentEvent ? projectOperationPresentation(currentEvent) : null; const showOutcomePanel = beat.id === "approval" || beat.id === "resume" || beat.id === "output" || beat.id === "trace"; ``` After `` and before `
`, render: ```tsx ``` Inside `.demo-workflow-stage`, after the graph block and before the pending block, render: ```tsx {showOutcomePanel && ( )} ``` - [ ] **Step 4: Tune layout CSS for the combined composition** In `web/apps/console/src/presentation/styles/demo-workflow.css`, update `.demo-workflow-stage`: ```css .demo-workflow-stage { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); flex: 1 1 auto; min-height: 0; overflow: hidden; } ``` Add these layout refinements after `.demo-workflow-stage__graph:has(.interrupt-contract-preview)`: ```css .demo-workflow-stage:has(.demo-outcome-panel) { grid-template-columns: minmax(0, 1fr) minmax(15rem, 23%); gap: 0.85rem; } .demo-workflow-stage:has(.demo-outcome-panel) .demo-workflow-stage__graph { min-width: 0; } .demo-workflow-stage[data-demo-layout="approval"] { grid-template-columns: minmax(0, 1.2fr) minmax(17rem, 0.55fr); } .demo-workflow-stage[data-demo-layout="approval"] .demo-workflow-stage__graph { grid-template-columns: minmax(0, 1fr) minmax(17rem, 32%); } .demo-workflow-stage[data-demo-layout="evidence"] { grid-template-columns: minmax(0, 1fr) minmax(16rem, 24%); } @container presentation-canvas (max-width: 1050px) { .demo-workflow-stage:has(.demo-outcome-panel), .demo-workflow-stage[data-demo-layout="approval"], .demo-workflow-stage[data-demo-layout="evidence"] { grid-template-columns: minmax(0, 1fr); } } ``` If this causes visual crowding during screenshot smoke, prefer reducing `stage-caption` height and panel padding before removing the outcome panel. - [ ] **Step 5: Run tests and verify they pass** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DemoWorkflowScene.test.tsx src/presentation/DemoContinuityRail.test.tsx src/presentation/DemoOutcomePanel.test.tsx ``` Expected: all tests pass. - [ ] **Step 6: Commit Task 4** ```powershell git add web/apps/console/src/presentation/DemoWorkflowScene.tsx web/apps/console/src/presentation/DemoWorkflowScene.test.tsx web/apps/console/src/presentation/styles/demo-workflow.css git commit -m "feat: compose demo climax scenes" ``` --- ### Task 5: Verify In Browser And Update Docs **Files:** - Modify: `web/README.md` - Modify: `docs/current_roadmap.md` - Move: `docs/superpowers/plans/2026-07-08-demo-climax-craft-pass.md` to `docs/historical/superpowers/plans/2026-07-08-demo-climax-craft-pass.md` **Interfaces:** - Consumes: completed Scene 9/10 demo climax UI. - Produces: updated live roadmap and README documentation. - [ ] **Step 1: Run the focused and broad verification commands** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation pnpm --dir web --filter @lda/console typecheck pnpm --dir web --filter @lda/console build git diff --check ``` Expected: - Presentation tests pass. - Typecheck exits `0`. - Build exits `0`; the existing Vite chunk-size warning is acceptable. - `git diff --check` reports no whitespace errors. Windows LF/CRLF warnings are acceptable. - [ ] **Step 2: Capture browser smoke screenshots** With `pnpm dev` already running, use the existing Playwright CLI flow. If no browser session exists, create one: ```powershell pnpx --package @playwright/cli playwright-cli -s=demo-climax open "http://127.0.0.1:5173/present#scene/workflow-demo/operation" ``` Capture these routes at `1280x720`: ```powershell pnpx --package @playwright/cli playwright-cli -s=demo-climax resize 1280 720 pnpx --package @playwright/cli playwright-cli -s=demo-climax open "http://127.0.0.1:5173/present#scene/workflow-demo/operation" pnpx --package @playwright/cli playwright-cli -s=demo-climax screenshot --filename web/apps/console/.visual-smoke/demo-climax-09-operation.png pnpx --package @playwright/cli playwright-cli -s=demo-climax open "http://127.0.0.1:5173/present#scene/workflow-demo/interrupt" pnpx --package @playwright/cli playwright-cli -s=demo-climax screenshot --filename web/apps/console/.visual-smoke/demo-climax-09-interrupt.png pnpx --package @playwright/cli playwright-cli -s=demo-climax open "http://127.0.0.1:5173/present#scene/interrupt-evidence/approval" pnpx --package @playwright/cli playwright-cli -s=demo-climax screenshot --filename web/apps/console/.visual-smoke/demo-climax-10-approval.png pnpx --package @playwright/cli playwright-cli -s=demo-climax open "http://127.0.0.1:5173/present#scene/interrupt-evidence/output" pnpx --package @playwright/cli playwright-cli -s=demo-climax screenshot --filename web/apps/console/.visual-smoke/demo-climax-10-output.png ``` Check screenshots manually. Acceptance criteria: - Scene 9 operation beat says the request becomes a workflow run. - Scene 9 interrupt beat still shows graph and typed contract. - Scene 10 approval beat makes the human decision obvious. - Scene 10 output beat makes report/issues/trace evidence visible without relying on chat text. - No visible scrollbars at normal `1280x720`. - [ ] **Step 3: Update `web/README.md`** In the Presentation Mode section, replace the current Scene 9/10 bullet list if present, or add this paragraph after the scene deep links: ```md Scenes 9 and 10 are the demo climax. They keep a continuity rail visible while the prepared replay moves from agent handoff, to persisted workflow run, to typed human interrupt, to resume/output/evidence. The rail and outcome panel are presentation-only projections over the committed replay; they do not add live backend dependencies. ``` - [ ] **Step 4: Update `docs/current_roadmap.md`** Under `Presentation wishlist / defense readiness`, change the open craft-pass item: ```md 5. Presentation craft pass: tune motion, discussion-chip placement, Q&A modal hierarchy, evidence receipt placement, and remaining generic-slide styling after the compositions are stable. ``` to: ```md 5. Completed: demo climax craft pass made Scenes 9 and 10 read as one continuous product demonstration from agent handoff, to persisted run, to typed interrupt, to resume/output/evidence. Implementation: [`demo climax craft pass`](historical/superpowers/plans/2026-07-08-demo-climax-craft-pass.md). 6. Presentation craft pass: tune motion, discussion-chip placement, Q&A modal hierarchy, evidence receipt placement, and remaining generic-slide styling after the demo climax is stable. ``` - [ ] **Step 5: Archive the plan** Run: ```powershell Move-Item docs/superpowers/plans/2026-07-08-demo-climax-craft-pass.md docs/historical/superpowers/plans/2026-07-08-demo-climax-craft-pass.md ``` Then verify: ```powershell rg -n "demo-climax-craft-pass|Demo Climax" docs/current_roadmap.md docs/superpowers/plans docs/historical/superpowers/plans web/README.md ``` Expected: - Roadmap points to `historical/superpowers/plans/2026-07-08-demo-climax-craft-pass.md`. - Active `docs/superpowers/plans/` does not contain this completed plan after archival. - [ ] **Step 6: Commit Task 5** ```powershell git add web/README.md docs/current_roadmap.md docs/historical/superpowers/plans/2026-07-08-demo-climax-craft-pass.md git add -u docs/superpowers/plans/2026-07-08-demo-climax-craft-pass.md git commit -m "docs: record demo climax craft pass" ``` --- ## Final Verification Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation pnpm --dir web --filter @lda/console typecheck pnpm --dir web --filter @lda/console build git diff --check git status --short ``` Expected: - Presentation tests pass. - Typecheck passes. - Build passes, with only the existing Vite chunk-size warning if it appears. - `git diff --check` has no whitespace errors. - `git status --short` is clean after all commits. ## Self-Review - Spec coverage: Tasks 1-4 cover the Scene 9/10 demo climax, product-story continuity, typed interrupt proof, resume/output/evidence proof, and stable replay-first boundaries. Task 5 covers docs, roadmap, screenshots, and archival. - Placeholder scan: no placeholder markers or unspecified tests are present. - Type consistency: `DemoBeatLens`, `DemoClimaxPhase`, `demoBeatLensForBeat`, `DemoContinuityRail`, and `DemoOutcomePanel` are defined before use and imported from exact paths. - Scope check: this plan does not change runtime code, RPC transport, demo recording, React Flow architecture, chat framework, or live backend behavior.