# Scene 10 Factual Graph and Proof Layout 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 the prepared workflow demo factual and readable by removing misleading proof labels, replacing the hand-positioned graph with a large dark Dagre/React Flow sequence graph, showing real input files, and placing the live/replay action inside the reusable operation receipt. **Architecture:** Keep the presentation-specific proof projection separate from the generic console graph. The presentation graph will provide the factual ten-node story subset and raw workflow edges without coordinates, call the existing `buildWorkflowGraph` Dagre layout with a horizontal layout option, and render the resulting model in a dark presentation wrapper with React Flow pan/zoom. Generic fact cards remain reusable; Scene 10 owns only composition and demo-specific controls through explicit slots. **Tech Stack:** React 19, TypeScript, Vitest, `@xyflow/react`, `@dagrejs/dagre`, existing presentation CSS, existing `DemoTimelineController` and live/replay target status. ## Global Constraints - Keep the graph in the existing dark demo surface; do not reintroduce presentation-wide theme switching. - Do not display `Current`, `Current interrupt`, `Queued`, `Completed`, or a current-node legend in the workflow graph. - Do not display `x plan nodes` or `x trace frames` proof chips anywhere in the graph. - Do not display `comment: none` in the output panel. The resume decision remains the authoritative place for the operator comment. - Keep the presentation graph to the intended 10-node story graph: include the real `revision_requested` workflow step, omit only the terminal `end_cancelled` node, and show cancellation as the labeled branch into `revision_requested`. - Use the existing Dagre and React Flow dependencies. Do not add a graph library or hand-author layout coordinates. - Do not change the generic `/console` graph behavior while borrowing its node dimensions, labels, Dagre layout, and connector conventions. - Do not stage or modify the existing user edit in `web/apps/console/src/presentation/authoring/Scene8ChatEntry.tsx`. - Use `pnpm --dir web --filter @lda/console test`, `pnpm --dir web --filter @lda/console build`, and `pnpm --dir web typecheck` for verification. ## File Map **Existing files to modify:** - `web/apps/console/src/presentation/demo-run-facts.ts` — clarify the no-output message without changing the persisted/output schema. - `web/apps/console/src/presentation/RunFactsPanel.tsx` — remove the misleading output comment row and trace-frame count while preserving actual fact rows. - `web/apps/console/src/presentation/RunFactsPanel.test.tsx` — lock the new output and trace wording. - `web/apps/console/src/presentation/demo-run-facts.test.ts` — update the no-output projection expectation. - `web/apps/console/src/graph/graph-model.ts` — add optional Dagre direction and dimension options while preserving the current console defaults. - `web/apps/console/src/graph/graph-model.test.ts` — prove default top-down layout is unchanged and horizontal layout is available. - `web/apps/console/src/presentation/workflow-graph-data.ts` — replace coordinate-bearing presentation nodes with the raw 10-node presentation plan and labeled edges. - `web/apps/console/src/presentation/WorkflowGraphStage.tsx` — consume the shared graph model, remove current-node labels/state styling, and configure a large horizontal React Flow viewport. - `web/apps/console/src/presentation/WorkflowGraphStage.test.tsx` — test the 10-node graph, labels, absence of current markers, and graph controls. - `web/apps/console/src/presentation/presentation.css` — style the dark graph surface, readable nodes, edge labels, viewport height, and controls. - `web/apps/console/src/presentation/RunInputFacts` callers and tests — replace the compact input summary in the demo with the file browser. - `web/apps/console/src/presentation/OperationBlock.tsx` — add a generic footer slot to the expanded operation variant. - `web/apps/console/src/presentation/OperationBlock.test.tsx` — test footer rendering and receipt stability. - `web/apps/console/src/presentation/DemoRunLaunchControl.tsx` — add a compact rendering variant without changing launch semantics. - `web/apps/console/src/presentation/DemoRunLaunchControl.test.tsx` — test compact status/action rendering. - `web/apps/console/src/presentation/DemoWorkflowScene.tsx` — wire the factual panels, graph, input browser, and compact launch footer. - `web/apps/console/src/presentation/DemoWorkflowScene.test.tsx` — test the Scene 10 composition and launch placement. - `web/apps/console/src/presentation/GuidedProductMoment.tsx` and its tests — remove output comment presentation if the guided output path renders the same reusable facts component. - `web/apps/console/src/presentation/styles/demo-workflow.css` — tune Scene 10 grid heights and scroll containment after the graph/input changes. **New files:** - `web/apps/console/src/presentation/RunInputFileBrowser.tsx` — small factual file-list surface backed only by projected input paths. - `web/apps/console/src/presentation/RunInputFileBrowser.test.tsx` — semantic and content tests for the file browser. **Documentation:** - `docs/current_roadmap.md` — link this active plan under the Scene 8–14 recomposition work. Move the plan to `docs/historical/superpowers/plans/` and update the link only after implementation is complete. - `web/README.md` — update only if the final graph/input/launch behavior changes the documented presentation rehearsal path. --- ### Task 1: Remove Misleading Output and Trace Claims **Files:** - Modify: `web/apps/console/src/presentation/demo-run-facts.ts:190-209` - Modify: `web/apps/console/src/presentation/RunFactsPanel.tsx:87-180` - Test: `web/apps/console/src/presentation/demo-run-facts.test.ts` - Test: `web/apps/console/src/presentation/RunFactsPanel.test.tsx` **Interfaces:** - Preserve `RunFactsOutput` and `RunFactsTrace` types so live and replay projections remain unchanged. - Preserve `facts.output.output.comment` in the projected data for raw evidence and future consumers; only remove it from this audience-facing panel. - [ ] **Step 1: Write failing tests for the audience wording.** Add assertions that: ```tsx it("does not render a null output comment as a fake fact", () => { render(); expect(screen.queryByText("Comment")).not.toBeInTheDocument(); expect(screen.queryByText("none")).not.toBeInTheDocument(); }); it("does not summarize trace evidence with a frame count", () => { render(); expect(screen.getByRole("heading", { name: "Recorded execution trace" })).toBeInTheDocument(); expect(screen.queryByText(/trace frames.*captured/i)).not.toBeInTheDocument(); }); ``` Update the projection test to expect the clearer no-output message: ```ts expect(facts.output.message).toBe("No report output has been produced for this run."); ``` - [ ] **Step 2: Run the focused tests and verify they fail for the old UI.** Run: ```text pnpm --dir web --filter @lda/console test -- src/presentation/RunFactsPanel.test.tsx src/presentation/demo-run-facts.test.ts ``` Expected: FAIL because the current panel renders `Comment`, `none`, `Trace frames`, and the old no-output message. - [ ] **Step 3: Implement the smallest factual change.** Change the output projection message to `No report output has been produced for this run.`. Remove the output `Comment` `
/
` pair from `RunOutputFacts`. Change the trace heading to `Recorded execution trace` and the empty state to `No trace entries recorded for this view.`. Do not replace the output comment with the resume comment. - [ ] **Step 4: Run the focused tests.** Run the command from Step 2. Expected: all focused fact-panel and projection tests pass. - [ ] **Step 5: Commit the factual cleanup.** ```text git add web/apps/console/src/presentation/demo-run-facts.ts web/apps/console/src/presentation/demo-run-facts.test.ts web/apps/console/src/presentation/RunFactsPanel.tsx web/apps/console/src/presentation/RunFactsPanel.test.tsx git commit -m "fix: keep demo run facts strictly factual" ``` ### Task 2: Make Dagre Layout Direction Configurable **Files:** - Modify: `web/apps/console/src/graph/graph-model.ts` - Test: `web/apps/console/src/graph/graph-model.test.ts` **Interfaces:** Add an optional second parameter without changing existing callers: ```ts export type WorkflowGraphLayoutOptions = { readonly direction?: "TB" | "LR"; readonly nodeWidth?: number; readonly nodeHeight?: number; readonly nodesep?: number; readonly ranksep?: number; }; export const buildWorkflowGraph = ( plan: { nodes: ReadonlyArray>; edges: ReadonlyArray> }, options: WorkflowGraphLayoutOptions = {}, ): WorkflowGraphModel => { /* existing model projection with configurable Dagre graph */ }; ``` - [ ] **Step 1: Add tests for default preservation and horizontal layout.** Prove that: ```ts const defaultModel = buildWorkflowGraph(plan); expect(defaultModel.nodes.find((node) => node.id === "read")?.position.y).toBeLessThan( defaultModel.nodes.find((node) => node.id === "end")?.position.y ?? 0, ); const horizontalModel = buildWorkflowGraph(plan, { direction: "LR", nodeWidth: 190, nodeHeight: 72, nodesep: 55, ranksep: 100, }); expect(horizontalModel.nodes.find((node) => node.id === "read")?.position.x).toBeLessThan( horizontalModel.nodes.find((node) => node.id === "end")?.position.x ?? 0, ); ``` Also assert edge labels remain unchanged. - [ ] **Step 2: Run the graph-model tests and verify the new test fails.** Run: ```text pnpm --dir web --filter @lda/console test -- src/graph/graph-model.test.ts ``` Expected: FAIL because `buildWorkflowGraph` does not accept layout options. - [ ] **Step 3: Implement the options with console-safe defaults.** Use `direction ?? "TB"`, `nodeWidth ?? 180`, `nodeHeight ?? 60`, `nodesep ?? 50`, and `ranksep ?? 80` when configuring Dagre. Use the selected dimensions both when registering nodes and when translating Dagre centers to top-left positions. - [ ] **Step 4: Run graph tests and the existing console graph tests.** Run: ```text pnpm --dir web --filter @lda/console test -- src/graph/graph-model.test.ts src/graph/WorkflowGraph.test.tsx ``` Expected: all tests pass and default `/console` graph behavior remains unchanged. - [ ] **Step 5: Commit the layout seam.** ```text git add web/apps/console/src/graph/graph-model.ts web/apps/console/src/graph/graph-model.test.ts git commit -m "feat: support horizontal workflow graph layout" ``` ### Task 3: Replace Hand-Positioned Presentation Graph Data **Files:** - Modify: `web/apps/console/src/presentation/workflow-graph-data.ts` - Test: `web/apps/console/src/presentation/WorkflowGraphStage.test.tsx` - Test: `web/apps/console/src/presentation/DemoWorkflowScene.test.tsx` **Interfaces:** Replace `PresentationNode.x`, `PresentationNode.y`, `PresentationHandle`, and manual `presentationEdges` handles with a raw plan shape consumed by `buildWorkflowGraph`: ```ts export const presentationWorkflowPlan = { nodes: [ { id: "reset_board", type: "node", node: "local.issue_board.reset_issue_board", label: "Reset issue board" }, { id: "read_docs", type: "node", node: "local.lda_docs.read_documents", label: "Read documents" }, { id: "analyze", type: "node", node: "local.lda_report.analyze_documents", label: "Analyze documents" }, { id: "build_report", type: "node", node: "local.lda_report.build_report", label: "Build report" }, { id: "draft_issues", type: "node", node: "local.lda_report.create_issue_drafts", label: "Draft issues" }, { id: "review_issues", type: "interrupt", kind: "issue_review" }, { id: "create_issues", type: "node", node: "local.issue_board.create_issues", label: "Create issues" }, { id: "finalise", type: "node", node: "local.lda_report.finalise_report", label: "Finalise report" }, { id: "revision_requested", type: "node", node: "local.lda_report.record_revision_request", label: "Revision requested" }, { id: "end_completed", type: "end", outcome: "completed" }, ], edges: [ { from: "reset_board", to: "read_docs", outcome: "ok" }, { from: "read_docs", to: "analyze", outcome: "ok" }, { from: "analyze", to: "build_report", outcome: "ok" }, { from: "build_report", to: "draft_issues", outcome: "ok" }, { from: "draft_issues", to: "review_issues", outcome: "ok" }, { from: "review_issues", to: "create_issues", outcome: "submitted" }, { from: "create_issues", to: "finalise", outcome: "ok" }, { from: "finalise", to: "end_completed", outcome: "completed" }, { from: "review_issues", to: "revision_requested", outcome: "cancelled" }, ], } as const; ``` The final raw plan must match the ten selected nodes and exact node references from `examples/lda_report_workflow/workflow.plan.json`. It must not contain layout coordinates. The canonical `end_cancelled` terminal is intentionally omitted from this presentation abstraction; the `cancelled` edge into `revision_requested` remains visible and factual. Add an optional `label` override to `buildWorkflowGraph` so the presentation can use readable labels while preserving the exact `nodeRef` beneath each node. The generic console graph must retain its existing fallback labels and defaults. - [ ] **Step 1: Add a data-level test for the visual plan.** Assert the exact ten node ids, the branch edge labels, and the absence of `x`/`y` fields. Keep this test independent of React Flow. - [ ] **Step 2: Run the focused data and graph tests.** Run: ```text pnpm --dir web --filter @lda/console test -- src/presentation/WorkflowGraphStage.test.tsx src/presentation/DemoWorkflowScene.test.tsx ``` Expected: FAIL once the tests reference the raw plan and the old coordinate-based implementation remains. - [ ] **Step 3: Replace coordinate consumers with `buildWorkflowGraph`.** In `WorkflowGraphStage`, build the model with: ```ts buildWorkflowGraph(presentationWorkflowPlan, { direction: "LR", nodeWidth: 190, nodeHeight: 72, nodesep: 55, ranksep: 100, }); ``` Use model-provided positions and edge labels. Do not calculate presentation coordinates or handle positions in the component. - [ ] **Step 4: Verify the graph model is now the source of coordinates.** Run the focused tests again and assert the rendered graph includes all ten visual nodes, `submitted` and `cancelled` edge labels, and no current-state text. - [ ] **Step 5: Commit the graph data migration and renderer together.** ```text git add web/apps/console/src/presentation/workflow-graph-data.ts web/apps/console/src/presentation/WorkflowGraphStage.tsx web/apps/console/src/presentation/WorkflowGraphStage.test.tsx web/apps/console/src/presentation/DemoWorkflowScene.test.tsx git commit -m "refactor: drive presentation graph from dagre model" ``` Tasks 3 and 4 form one visible slice. Do not leave the presentation graph on a half-migrated coordinate/data model between commits; commit the raw-plan migration and dark renderer together after the renderer tests pass. ### Task 4: Render the Large Dark Sequence Graph **Files:** - Modify: `web/apps/console/src/presentation/WorkflowGraphStage.tsx` - Modify: `web/apps/console/src/presentation/presentation.css` - Test: `web/apps/console/src/presentation/WorkflowGraphStage.test.tsx` **Interfaces:** Keep `WorkflowGraphStage` selectable and pan/zoomable. `execution` may continue to control active edge emphasis, but it must not create a visible current node, state label, or state legend. - [ ] **Step 1: Add failing assertions for graph presentation contracts.** Assert that the rendered graph: ```tsx expect(screen.getByRole("group", { name: "workflow graph" })).toHaveAttribute( "data-graph-direction", "horizontal", ); expect(screen.queryByText("Current")).not.toBeInTheDocument(); expect(screen.queryByText("Queued")).not.toBeInTheDocument(); expect(screen.queryByText("Completed")).not.toBeInTheDocument(); expect(screen.getByText("submitted")).toBeInTheDocument(); expect(screen.getByText("cancelled")).toBeInTheDocument(); ``` Include an assertion that the React Flow controls are present and the graph wrapper has the dark presentation data attribute/class. - [ ] **Step 2: Run the focused graph tests.** Expected: FAIL because the current component renders state labels, a state legend, coordinate-based nodes, and proof count chips. - [ ] **Step 3: Implement the dark sequence renderer.** Use the shared graph model’s `kind`, `label`, and `nodeRef` fields. Render rectangular dark nodes with the same information hierarchy as `/console`: a readable label, a smaller node reference, top/bottom handles, and labeled default edges. Use an amber border for the interrupt node and muted terminal styling for end nodes; do not add novel diamond/hexagon shapes in this slice. Remove `stateLabelFor`, the current-state legend, and the visual `Current`/`Queued`/`Completed` node states. Remove `planLabel` and `traceLabel` from `WorkflowGraphProof`; retain only factual run identity and evidence availability if those are still needed on full graph beats. Set the graph surface to a readable large viewport rather than fitting ten nodes into a tiny card: ```css .workflow-graph-stage[data-graph-direction="horizontal"] { min-height: 24rem; } .workflow-graph-stage[data-graph-direction="horizontal"] .react-flow__node { width: 11.875rem; min-height: 4.5rem; } .workflow-graph-stage[data-graph-direction="horizontal"] .react-flow__edge-text { paint-order: stroke; stroke: var(--stage-surface); stroke-width: 0.4rem; stroke-linejoin: round; } ``` Keep `panOnDrag`, `zoomOnScroll`, `zoomOnPinch`, and visible `Controls`. Use a non-tiny initial zoom or bounded fit-view options so the first view is readable while the full sequence remains reachable by pan/zoom. - [ ] **Step 4: Run focused tests, typecheck, and build.** ```text pnpm --dir web --filter @lda/console test -- src/presentation/WorkflowGraphStage.test.tsx src/presentation/DemoWorkflowScene.test.tsx pnpm --dir web typecheck pnpm --dir web --filter @lda/console build ``` Expected: all commands pass; only the existing Vite chunk-size warning may remain. - [ ] **Step 5: Commit the dark graph pass.** ```text git add web/apps/console/src/presentation/WorkflowGraphStage.tsx web/apps/console/src/presentation/presentation.css web/apps/console/src/presentation/WorkflowGraphStage.test.tsx git commit -m "feat: enlarge dark presentation workflow graph" ``` ### Task 5: Add the Factual Input File Browser **Files:** - Create: `web/apps/console/src/presentation/RunInputFileBrowser.tsx` - Test: `web/apps/console/src/presentation/RunInputFileBrowser.test.tsx` - Modify: `web/apps/console/src/presentation/DemoWorkflowScene.tsx` - Test: `web/apps/console/src/presentation/DemoWorkflowScene.test.tsx` - Modify: `web/apps/console/src/presentation/styles/demo-workflow.css` **Interfaces:** ```ts type RunInputFileBrowserProps = { readonly selectedDocuments: ReadonlyArray; readonly boardPath: string; }; export const RunInputFileBrowser = (props: RunInputFileBrowserProps): JSX.Element; ``` - [ ] **Step 1: Add tests for the file-browser facts.** Assert that the component renders a labelled `docs/` file list, every exact selected document path, a selected/read marker, and the exact board path. Assert it does not invent file sizes, previews, timestamps, or content. - [ ] **Step 2: Run the new test and verify it fails.** ```text pnpm --dir web --filter @lda/console test -- src/presentation/RunInputFileBrowser.test.tsx ``` Expected: FAIL because the component does not exist. - [ ] **Step 3: Implement the lightweight browser.** Render a compact dark surface with: - a header showing `docs/` and `selected for this run`; - one row per `selectedDocuments` entry with a file icon, exact path, and selected marker; - a separate destination row for the exact `boardPath`, labelled `workflow output`; - no fabricated file metadata or content. Use an accessible list and stable `data-file-path` attributes for tests. Keep rows vertically scrollable only when the available stage height requires it. - [ ] **Step 4: Replace the input summary on the input beat.** Render `RunInputFileBrowser` from `facts.input.selectedDocuments` and `facts.input.boardPath`. Leave `RunInputFacts` available for other contexts unless tests show it is no longer used. - [ ] **Step 5: Run focused tests and capture the input route.** ```text pnpm --dir web --filter @lda/console test -- src/presentation/RunInputFileBrowser.test.tsx src/presentation/DemoWorkflowScene.test.tsx ``` Capture `http://127.0.0.1:5173/present#scene/run-from-deployment/input` at 1280x720 and 1024x768. The file rows must remain readable without overlapping the continuity rail or graph. - [ ] **Step 6: Commit the input browser.** ```text git add web/apps/console/src/presentation/RunInputFileBrowser.tsx web/apps/console/src/presentation/RunInputFileBrowser.test.tsx 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: show prepared workflow input files" ``` ### Task 6: Put Live/Replay Launch Inside the Operation Block **Files:** - Modify: `web/apps/console/src/presentation/OperationBlock.tsx` - Test: `web/apps/console/src/presentation/OperationBlock.test.tsx` - Modify: `web/apps/console/src/presentation/DemoRunLaunchControl.tsx` - Test: `web/apps/console/src/presentation/DemoRunLaunchControl.test.tsx` - Modify: `web/apps/console/src/presentation/DemoWorkflowScene.tsx` - Test: `web/apps/console/src/presentation/DemoWorkflowScene.test.tsx` - Modify: `web/apps/console/src/presentation/styles/demo-workflow.css` **Interfaces:** Add a generic React slot to the expanded operation block: ```tsx type OperationBlockProps = { readonly event: DemoEvent; readonly variant: OperationVariant; readonly openEvidence: () => void; readonly footer?: ReactNode; }; ``` Add `variant?: "default" | "compact"` to `DemoRunLaunchControlProps`. The compact variant changes presentation only; it must preserve `runPreparedWorkflow`, retry, disabled, and target-status semantics. - [ ] **Step 1: Add failing tests for the slot and compact control.** Test that: ```tsx render( launch control} />, ); expect(screen.getByText("launch control")).toBeInTheDocument(); ``` Also test that the compact control renders its status and actions in one compact region and still calls `runPreparedWorkflow("live")` or `runPreparedWorkflow("replay")` correctly. - [ ] **Step 2: Run focused tests and verify the old behavior fails the new assertions.** ```text pnpm --dir web --filter @lda/console test -- src/presentation/OperationBlock.test.tsx src/presentation/DemoRunLaunchControl.test.tsx ``` Expected: FAIL because `OperationBlock` has no footer slot and the launch control is a full-width top-level banner. - [ ] **Step 3: Implement the generic footer and compact control.** Render the optional footer after the evidence action inside the expanded operation block. Do not import target health, timeline, or RPC types into `OperationBlock`. For compact launch styling, use one horizontal status/action row with concise copy. The primary action remains the only prominent button; retry remains secondary. Remove the top-level launch control render from `DemoWorkflowScene` and pass it as the operation footer only on the `operation` beat. - [ ] **Step 4: Verify composition and responsive behavior.** Assert the Scene 10 operation route has one operation block containing the launch control, no separate top-level launch banner, and no duplicate launch buttons. Capture: - `http://127.0.0.1:5173/present#scene/run-from-deployment/operation` - `http://127.0.0.1:5173/present#scene/typed-human-boundary/approval` at 1280x720 and 1024x768. The operation receipt must remain readable and the control must not push the graph or input content below the viewport. - [ ] **Step 5: Run the full verification gate.** ```text pnpm --dir web --filter @lda/console test pnpm --dir web typecheck pnpm --dir web --filter @lda/console build git diff --check ``` Expected: all console tests pass, typecheck/build pass, and only the existing Vite chunk-size warning remains. - [ ] **Step 6: Commit the operation composition.** ```text git add web/apps/console/src/presentation/OperationBlock.tsx web/apps/console/src/presentation/OperationBlock.test.tsx web/apps/console/src/presentation/DemoRunLaunchControl.tsx web/apps/console/src/presentation/DemoRunLaunchControl.test.tsx 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 "refactor: compose demo launch inside operation proof" ``` ### Task 7: Integrate, Review, and Archive the Plan **Files:** - Modify: `web/apps/console/src/presentation/GuidedProductMoment.tsx` - Test: `web/apps/console/src/presentation/GuidedProductMoment.test.tsx` - Modify: `web/apps/console/src/presentation/PresentationRoute.test.tsx` - Modify: `docs/current_roadmap.md` - Move: `docs/superpowers/plans/2026-07-12-scene-10-factual-graph-and-proof-layout.md` to `docs/historical/superpowers/plans/2026-07-12-scene-10-factual-graph-and-proof-layout.md` - [ ] **Step 1: Run the complete presentation route matrix.** Verify direct hashes for operation, input, graph, interrupt, approval, resume, output, and trace. Confirm: - the graph is dark, horizontal, readable, and pan/zoomable; - no graph contains current-state labels or misleading count chips; - output does not display a null comment; - resume displays the actual decision comment when present; - trace displays actual rows or an honest empty state; - input displays the selected files and board destination; - live/replay launch appears inside the operation proof only. - [ ] **Step 2: Run review and fix real findings.** Run the repository’s standards/spec review against the slice. Treat warnings about unused coordinate types, stale proof labels, duplicate launch controls, and missing narrow-canvas coverage as actionable. Do not expand this slice into chat redesign or broad story-flow changes. - [ ] **Step 3: Update live documentation.** Mark the roadmap item complete only after browser smoke and verification pass. Update `web/README.md` if its presentation route or launch instructions became stale. Move this plan to `docs/historical/superpowers/plans/` and update all live links to the historical path. - [ ] **Step 4: Verify the final worktree boundary.** Run: ```text git status --short git diff --check ``` Expected: only the pre-existing user edit in `web/apps/console/src/presentation/authoring/Scene8ChatEntry.tsx` may remain unstaged; no `.visual-smoke/` files or active plan files should be staged in the final implementation commit. ## Self-Review Checklist - [x] Factual output handling is separate from resume-decision handling. - [x] Trace frame counts are removed from the graph and dedicated trace heading. - [x] Graph coordinates come from Dagre; no hand-authored `x`/`y` values remain in presentation graph data. - [x] The graph uses the existing React Flow interaction model and dark presentation surface. - [x] Horizontal layout is an opt-in graph-model capability, so `/console` keeps its existing top-down behavior. - [x] The intended presentation graph remains ten nodes; cancellation is an edge outcome. - [x] The input browser displays only projected paths and does not fabricate file metadata. - [x] OperationBlock remains generic through a React footer slot. - [x] Live/replay execution behavior remains in `DemoRunLaunchControl` and existing controller seams. - [x] The user’s unrelated Scene 8 edit is explicitly protected. ## Execution Handoff Plan complete and saved to `docs/superpowers/plans/2026-07-12-scene-10-factual-graph-and-proof-layout.md`. Execute it one task at a time, committing each independently and checking the browser after Tasks 4, 5, and 6.