feat: remap demo replay beats and fix old scene ID references

This commit is contained in:
lda
2026-07-09 21:38:53 +07:00 Verified
parent f19fa25d97
commit 81c5541a61
11 changed files with 122 additions and 85 deletions
@@ -49,7 +49,7 @@ const requireSceneBeat = (sceneId: string, beatId: string) => {
const renderBeat = (
beatId: string,
sceneId = "workflow-demo",
sceneId = "run-from-deployment",
options: {
readonly openEvidence?: () => void;
readonly approvalActions?: DemoApprovalActions;
@@ -89,27 +89,24 @@ describe("DemoWorkflowScene", () => {
expect(screen.getByLabelText("workflow graph")).toBeInTheDocument();
});
it("renders the canonical typed interrupt contract", () => {
renderBeat("interrupt");
it("renders the guided interrupt contract via product moment in typed-human-boundary", () => {
renderBeat("interrupt", "typed-human-boundary");
const contract = screen.getByLabelText("typed interrupt contract");
expect(contract).toHaveTextContent("issue_review");
expect(contract).toHaveTextContent("submitted / cancelled");
expect(contract).toHaveTextContent("lda.chat Thesis And Project Readiness Report");
expect(contract).toHaveTextContent("Prepare the defense walkthrough");
expect(contract).toHaveTextContent('"type": "object"');
expect(contract).toHaveTextContent("run_recorded_lda_report");
const moment = screen.getByRole("region", { name: /current product moment/i });
expect(moment).toHaveAttribute("data-moment", "approval");
expect(screen.getByRole("group", { name: /operator resume decision/i })).toBeInTheDocument();
expect(screen.getByText("Workflow input")).toBeInTheDocument();
});
it("carries the contract into Scene 10 approval via guided product moment", () => {
renderBeat("approval", "interrupt-evidence");
renderBeat("approval", "typed-human-boundary");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "approval");
expect(screen.getByRole("group", { name: /operator resume decision/i })).toBeInTheDocument();
});
it("makes the Scene 10 approval contract the primary visual", () => {
renderBeat("approval", "interrupt-evidence");
renderBeat("approval", "typed-human-boundary");
const stage = screen.getByLabelText("demo workflow stage");
expect(stage).toHaveAttribute("data-demo-layout", "approval");
@@ -117,18 +114,18 @@ describe("DemoWorkflowScene", () => {
});
it("marks trace beat as evidence layout via guided product moment", () => {
renderBeat("trace", "interrupt-evidence");
renderBeat("trace", "resume-output-evidence");
expect(screen.getByLabelText("demo workflow stage")).toHaveAttribute("data-demo-layout", "evidence");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "trace");
});
it("renders resume and trace via guided product moment", () => {
const { unmount } = renderBeat("resume", "interrupt-evidence");
const { unmount } = renderBeat("resume", "resume-output-evidence");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "resume");
unmount();
renderBeat("trace", "interrupt-evidence");
renderBeat("trace", "resume-output-evidence");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "trace");
});
@@ -138,12 +135,12 @@ describe("DemoWorkflowScene", () => {
expect(screen.getByLabelText("workflow graph proof")).toHaveTextContent("9 workflow nodes");
unmount();
renderBeat("output", "interrupt-evidence");
renderBeat("output", "resume-output-evidence");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "output");
});
it("marks outcome-panel layouts via guided product moment", () => {
renderBeat("resume", "interrupt-evidence");
renderBeat("resume", "resume-output-evidence");
expect(screen.getByLabelText("demo workflow stage")).toHaveAttribute("data-demo-layout", "operation");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "resume");
@@ -159,16 +156,17 @@ describe("DemoWorkflowScene", () => {
expect(screen.getByLabelText("demo continuity")).toHaveTextContent("typed graph");
graph.unmount();
renderBeat("interrupt");
renderBeat("interrupt", "typed-human-boundary");
expect(screen.getByLabelText("demo continuity")).toHaveTextContent("issue_review");
});
it("uses compact graph context for interrupt-focused beats", () => {
const interrupt = renderBeat("interrupt");
expect(screen.getByLabelText("workflow graph")).toHaveAttribute("data-graph-variant", "compact");
it("renders approval and interrupt beats via guided product moment", () => {
const interrupt = renderBeat("interrupt", "typed-human-boundary");
expect(screen.queryByLabelText("workflow graph")).not.toBeInTheDocument();
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "approval");
interrupt.unmount();
renderBeat("approval", "interrupt-evidence");
renderBeat("approval", "typed-human-boundary");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "approval");
});
@@ -177,19 +175,19 @@ describe("DemoWorkflowScene", () => {
expect(screen.getByLabelText("workflow graph")).toHaveAttribute("data-graph-variant", "full");
graph.unmount();
renderBeat("output", "interrupt-evidence");
renderBeat("output", "resume-output-evidence");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "output");
});
it("keeps approval beat contract via guided product moment", () => {
renderBeat("approval", "interrupt-evidence");
renderBeat("approval", "typed-human-boundary");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "approval");
expect(screen.getByRole("group", { name: /operator resume decision/i })).toBeInTheDocument();
});
it("wires approval actions into the Scene 10 schema approval surface", () => {
renderBeat("approval", "interrupt-evidence", {
renderBeat("approval", "typed-human-boundary", {
approvalActions: {
state: "ready",
canSubmit: true,
@@ -204,31 +202,32 @@ describe("DemoWorkflowScene", () => {
});
it("shows a factual decision form for the approval beat instead of raw schema as the primary visual", () => {
renderBeat("approval", "interrupt-evidence");
renderBeat("approval", "typed-human-boundary");
expect(screen.getByRole("group", { name: /operator resume decision/i })).toBeInTheDocument();
expect(screen.getByText("Workflow input")).toBeInTheDocument();
});
it("keeps raw resume schema visible only in interrupt preview mode", () => {
renderBeat("interrupt");
expect(screen.getByText("Resume schema")).toBeInTheDocument();
it("renders interrupt decision form but no raw schema in guided product moment", () => {
renderBeat("interrupt", "typed-human-boundary");
expect(screen.queryByText("Resume schema")).not.toBeInTheDocument();
expect(screen.getByRole("group", { name: /operator resume decision/i })).toBeInTheDocument();
cleanup();
renderBeat("approval", "interrupt-evidence");
expect(screen.queryByText("Resume schema")).not.toBeInTheDocument();
renderBeat("approval", "typed-human-boundary");
expect(screen.getByRole("group", { name: /operator resume decision/i })).toBeInTheDocument();
});
it("adds guided product moment for resume, output, and trace beats", () => {
const resume = renderBeat("resume", "interrupt-evidence");
const resume = renderBeat("resume", "resume-output-evidence");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "resume");
resume.unmount();
const output = renderBeat("output", "interrupt-evidence");
const output = renderBeat("output", "resume-output-evidence");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "output");
output.unmount();
renderBeat("trace", "interrupt-evidence");
renderBeat("trace", "resume-output-evidence");
expect(screen.getByRole("region", { name: /current product moment/i })).toHaveAttribute("data-moment", "trace");
});
});
@@ -14,6 +14,7 @@ import { GuidedProductMoment } from "./GuidedProductMoment.js";
import { InterruptContractPreview } from "./InterruptContractPreview.js";
import { NodeSpotlight } from "./NodeSpotlight.js";
import { OperationBlock } from "./OperationBlock.js";
import { RunInputFacts } from "./RunFactsPanel.js";
import { StageCaption } from "./StageCaption.js";
import type { SceneBeatDefinition, SceneDefinition } from "./storyboard.js";
import { WorkflowGraphStage } from "./WorkflowGraphStage.js";
@@ -33,7 +34,7 @@ type DemoWorkflowLayout = "operation" | "graph" | "interrupt" | "approval" | "ev
const layoutForBeat = (beatId: string): DemoWorkflowLayout => {
if (beatId === "operation" || beatId === "resume") return "operation";
if (beatId === "interrupt") return "interrupt";
if (beatId === "approval") return "approval";
if (beatId === "approval" || beatId === "cancel") return "approval";
if (beatId === "trace" || beatId === "output") return "evidence";
return "graph";
};
@@ -90,7 +91,8 @@ export const DemoWorkflowScene = ({
? "preview"
: null;
const isGuidedScene10 = scene.id === "interrupt-evidence";
const isGuidedDemoMoment = scene.id === "typed-human-boundary"
|| scene.id === "resume-output-evidence";
return (
<>
@@ -101,7 +103,7 @@ export const DemoWorkflowScene = ({
<DemoContinuityRail lens={lens} />
<div className="demo-workflow-stage" data-beat={beat.id} data-demo-layout={layout} aria-label="demo workflow stage">
{isGuidedScene10 ? (
{isGuidedDemoMoment ? (
<GuidedProductMoment
beat={beat}
demo={demo}
@@ -128,6 +130,12 @@ export const DemoWorkflowScene = ({
/>
)}
{beat.id === "input" && (
<div className="demo-workflow-stage__input-facts">
<RunInputFacts facts={facts} />
</div>
)}
{showGraph && (
<div className="demo-workflow-stage__graph">
<WorkflowGraphStage
@@ -11,7 +11,7 @@ describe("OperatorChat", () => {
it("maps light chat theme to the editorial presentation surface", () => {
const state = {
...initialPresentationState,
location: { kind: "main" as const, sceneId: "workflow-demo" as const, beatId: "graph", focusPath: [] },
location: { kind: "main" as const, sceneId: "run-from-deployment" as const, beatId: "graph", focusPath: [] },
};
render(<OperatorChat state={state} />);
@@ -37,7 +37,7 @@ describe("PresentationFooter", () => {
/>,
);
const footer = screen.getByRole("contentinfo", { name: /presentation footer/i });
expect(within(footer).getByText("6 / 12")).toBeInTheDocument();
expect(within(footer).getByText("6 / 14")).toBeInTheDocument();
expect(within(footer).getByText("3 / 4")).toBeInTheDocument();
expect(within(footer).getByText(/workflow\.runs\.trace/)).toBeInTheDocument();
});
@@ -74,7 +74,7 @@ describe("PresentationRoute", () => {
});
it("shows node spotlight when a graph node is selected", async () => {
window.location.hash = "#scene/workflow-demo/graph";
window.location.hash = "#scene/run-from-deployment/graph";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
await userEvent.click(screen.getByRole("button", { name: /issue review/i }));
@@ -84,7 +84,7 @@ describe("PresentationRoute", () => {
it("can advance replay far enough to show a product operation block", async () => {
setReplayMode();
window.location.hash = "#scene/workflow-demo/operation";
window.location.hash = "#scene/run-from-deployment/operation";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
expect(await screen.findByLabelText("workflow.runs.start operation")).toBeInTheDocument();
@@ -118,7 +118,7 @@ describe("PresentationRoute", () => {
});
it("shows a receipt without auto-opening evidence on an evidence beat", async () => {
window.location.hash = "#scene/interrupt-evidence/trace";
window.location.hash = "#scene/resume-output-evidence/trace";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
expect(await screen.findByRole("button", { name: /inspect evidence/i })).toBeInTheDocument();
@@ -128,7 +128,7 @@ describe("PresentationRoute", () => {
it("opens the inspector from an explicit operation action", async () => {
setReplayMode();
const user = userEvent.setup();
window.location.hash = "#scene/workflow-demo/operation";
window.location.hash = "#scene/run-from-deployment/operation";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
await user.click(await screen.findByRole("button", { name: /view raw evidence/i }));
@@ -138,7 +138,7 @@ describe("PresentationRoute", () => {
it("closes the inspector from the explicit close action", async () => {
setReplayMode();
const user = userEvent.setup();
window.location.hash = "#scene/workflow-demo/operation";
window.location.hash = "#scene/run-from-deployment/operation";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
await user.click(await screen.findByRole("button", { name: /view raw evidence/i }));
@@ -150,7 +150,7 @@ describe("PresentationRoute", () => {
it("returns to the receipt after closing the inspector on a receipt beat", async () => {
setReplayMode();
const user = userEvent.setup();
window.location.hash = "#scene/interrupt-evidence/trace";
window.location.hash = "#scene/resume-output-evidence/trace";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
await user.click(await screen.findByRole("button", { name: /inspect evidence/i }));
@@ -188,16 +188,16 @@ describe("PresentationRoute", () => {
});
it("opens Scene 10 approval from the canonical hash", async () => {
window.location.hash = "#scene/interrupt-evidence/approval";
window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
expect(await screen.findByRole("heading", { name: /Interrupt, Resume, Evidence/i })).toBeInTheDocument();
expect(await screen.findByRole("heading", { name: /Typed Human Boundary/i })).toBeInTheDocument();
expect(screen.getByLabelText("demo workflow stage")).toHaveAttribute("data-demo-layout", "approval");
});
it("renders replay-backed approval evidence on a direct approval hash", async () => {
window.location.hash = "#scene/interrupt-evidence/approval";
window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
@@ -210,7 +210,7 @@ describe("PresentationRoute", () => {
it("chat run action advances the replay timeline when no live server is configured", async () => {
setReplayMode();
window.location.hash = "#scene/workflow-demo/operation";
window.location.hash = "#scene/run-from-deployment/operation";
const user = userEvent.setup();
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
@@ -223,7 +223,7 @@ describe("PresentationRoute", () => {
it("submits Scene 10 approval and advances to the resume beat", async () => {
const user = userEvent.setup();
setReplayMode();
window.location.hash = "#scene/interrupt-evidence/approval";
window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
@@ -234,14 +234,14 @@ describe("PresentationRoute", () => {
await user.click(submitButton);
});
expect(window.location.hash).toBe("#scene/interrupt-evidence/resume");
expect(window.location.hash).toBe("#scene/resume-output-evidence/resume");
expect(screen.getByLabelText("workflow.runs.resume operation")).toBeInTheDocument();
});
it("reopens approval controls after returning from submitted resume", async () => {
const user = userEvent.setup();
setReplayMode();
window.location.hash = "#scene/interrupt-evidence/approval";
window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
@@ -250,9 +250,9 @@ describe("PresentationRoute", () => {
await act(async () => {
await user.click(submitButton);
});
expect(window.location.hash).toBe("#scene/interrupt-evidence/resume");
expect(window.location.hash).toBe("#scene/resume-output-evidence/resume");
window.location.hash = "#scene/interrupt-evidence/approval";
window.location.hash = "#scene/typed-human-boundary/approval";
window.dispatchEvent(new HashChangeEvent("hashchange"));
expect(await screen.findByRole("button", { name: "Submit" })).toBeEnabled();
@@ -262,7 +262,7 @@ describe("PresentationRoute", () => {
it("cancels Scene 10 approval in replay without applying submitted evidence", async () => {
const user = userEvent.setup();
setReplayMode();
window.location.hash = "#scene/interrupt-evidence/approval";
window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
@@ -275,12 +275,12 @@ describe("PresentationRoute", () => {
expect(screen.queryByRole("button", { name: "Submit" })).not.toBeInTheDocument();
expect(screen.queryByRole("button", { name: "Cancel" })).not.toBeInTheDocument();
expect(window.location.hash).toBe("#scene/interrupt-evidence/approval");
expect(window.location.hash).toBe("#scene/typed-human-boundary/approval");
expect(screen.queryByLabelText("workflow.runs.resume operation")).not.toBeInTheDocument();
});
it("opens approval with enabled approval controls immediately after priming", async () => {
window.location.hash = "#scene/interrupt-evidence/approval";
window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
@@ -289,7 +289,7 @@ describe("PresentationRoute", () => {
});
it("opens resume with resume operation proof immediately after priming", async () => {
window.location.hash = "#scene/interrupt-evidence/resume";
window.location.hash = "#scene/resume-output-evidence/resume";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
@@ -120,7 +120,7 @@ export const PresentationRoute = () => {
}, [demo.state.mode, demo.primeReplayToStage, state.location]);
const isApprovalBeat = state.location.kind === "main"
&& state.location.sceneId === "interrupt-evidence"
&& state.location.sceneId === "typed-human-boundary"
&& state.location.beatId === "approval";
useEffect(() => {
@@ -148,7 +148,7 @@ export const PresentationRoute = () => {
type: "jump",
location: {
kind: "main",
sceneId: "interrupt-evidence",
sceneId: "resume-output-evidence",
beatId: "resume",
focusPath: [],
},
@@ -59,7 +59,7 @@ describe("SceneBody", () => {
});
it("renders the real workflow graph for demo scenes", () => {
const location: PresentationLocation = { kind: "main", sceneId: "workflow-demo", beatId: "graph", focusPath: [] };
const location: PresentationLocation = { kind: "main", sceneId: "run-from-deployment", beatId: "graph", focusPath: [] };
render(
<SceneBody
location={location}
@@ -16,22 +16,22 @@ describe("SceneProgress", () => {
render(<SceneProgress location={location} />);
expect(screen.getByText("6 / 12")).toBeInTheDocument();
expect(screen.getByText("6 / 14")).toBeInTheDocument();
expect(screen.getByText("3 / 4")).toBeInTheDocument();
});
it("shows scene position for workflow-demo/graph", () => {
it("shows scene position for run-from-deployment/graph", () => {
const location: MainLocation = {
kind: "main",
sceneId: "workflow-demo",
sceneId: "run-from-deployment",
beatId: "graph",
focusPath: [],
};
render(<SceneProgress location={location} />);
expect(screen.getByText("9 / 12")).toBeInTheDocument();
expect(screen.getByText("2 / 3")).toBeInTheDocument();
expect(screen.getByText("10 / 14")).toBeInTheDocument();
expect(screen.getByText("3 / 3")).toBeInTheDocument();
});
it("has an accessible label", () => {
@@ -3,13 +3,19 @@ import { requirementForDemoBeat } from "./demo-beat-requirements.js";
describe("requirementForDemoBeat", () => {
it.each([
["workflow-demo", "operation", "run_start"],
["workflow-demo", "graph", "run_start"],
["workflow-demo", "interrupt", "interrupt"],
["interrupt-evidence", "approval", "interrupt"],
["interrupt-evidence", "resume", "run_resume"],
["interrupt-evidence", "output", "run_resume"],
["interrupt-evidence", "trace", "trace_read"],
["prepared-lifecycle", "draft", "deployment_check"],
["prepared-lifecycle", "artifact", "deployment_check"],
["prepared-lifecycle", "deployment", "deployment_check"],
["prepared-lifecycle", "ready-run", "run_start"],
["run-from-deployment", "input", "run_start"],
["run-from-deployment", "operation", "run_start"],
["run-from-deployment", "graph", "run_start"],
["typed-human-boundary", "interrupt", "interrupt"],
["typed-human-boundary", "approval", "interrupt"],
["typed-human-boundary", "cancel", "interrupt"],
["resume-output-evidence", "resume", "run_resume"],
["resume-output-evidence", "output", "run_resume"],
["resume-output-evidence", "trace", "trace_read"],
] as const)("maps %s/%s to %s", (sceneId, beatId, stage) => {
expect(requirementForDemoBeat(sceneId, beatId).requiredStage).toBe(stage);
});
@@ -6,31 +6,55 @@ export type DemoBeatRequirement = {
};
const requirements: Readonly<Record<string, DemoBeatRequirement>> = {
"workflow-demo/operation": {
"prepared-lifecycle/draft": {
requiredStage: "deployment_check",
reason: "Prepared draft beat needs deployment inspect evidence for lifecycle context.",
},
"prepared-lifecycle/artifact": {
requiredStage: "deployment_check",
reason: "Artifact beat needs deployment inspect evidence.",
},
"prepared-lifecycle/deployment": {
requiredStage: "deployment_check",
reason: "Deployment beat needs configured source bindings.",
},
"prepared-lifecycle/ready-run": {
requiredStage: "run_start",
reason: "Ready-run beat needs the recorded run id and status.",
},
"run-from-deployment/input": {
requiredStage: "run_start",
reason: "Input beat needs workflow input from run start.",
},
"run-from-deployment/operation": {
requiredStage: "run_start",
reason: "Operation beat needs the recorded run start.",
},
"workflow-demo/graph": {
"run-from-deployment/graph": {
requiredStage: "run_start",
reason: "Graph beat needs the persisted run id.",
},
"workflow-demo/interrupt": {
"typed-human-boundary/interrupt": {
requiredStage: "interrupt",
reason: "Interrupt beat needs the typed review payload.",
},
"interrupt-evidence/approval": {
"typed-human-boundary/approval": {
requiredStage: "interrupt",
reason: "Approval beat needs the typed review payload before controls can act.",
},
"interrupt-evidence/resume": {
"typed-human-boundary/cancel": {
requiredStage: "interrupt",
reason: "Cancel beat needs the review payload but no submitted replay evidence.",
},
"resume-output-evidence/resume": {
requiredStage: "run_resume",
reason: "Resume beat needs the recorded resume operation.",
},
"interrupt-evidence/output": {
"resume-output-evidence/output": {
requiredStage: "run_resume",
reason: "Output beat needs the resumed run output.",
},
"interrupt-evidence/trace": {
"resume-output-evidence/trace": {
requiredStage: "trace_read",
reason: "Trace beat needs the recorded trace read.",
},
@@ -28,9 +28,9 @@ describe("presentationReducer", () => {
it("jumps to a specific scene and beat", () => {
const jumped = presentationReducer(initialPresentationState, {
type: "jump",
location: { kind: "main", sceneId: "workflow-demo", beatId: "graph", focusPath: [] },
location: { kind: "main", sceneId: "run-from-deployment", beatId: "graph", focusPath: [] },
});
expect(jumped.location).toEqual({ kind: "main", sceneId: "workflow-demo", beatId: "graph", focusPath: [] });
expect(jumped.location).toEqual({ kind: "main", sceneId: "run-from-deployment", beatId: "graph", focusPath: [] });
});
it("parses a scene hash", () => {
@@ -149,7 +149,7 @@ describe("presentationReducer", () => {
it("derives chatMode from the current beat", () => {
const state = presentationReducer(initialPresentationState, {
type: "jump",
location: { kind: "main", sceneId: "workflow-demo", beatId: "graph", focusPath: [] },
location: { kind: "main", sceneId: "run-from-deployment", beatId: "graph", focusPath: [] },
});
expect(compositionForState(state)).toMatchObject({
chatMode: "hidden",
@@ -169,7 +169,7 @@ describe("presentationReducer", () => {
it("does not reopen evidence on repeated Escape after force-close", () => {
const stateAtTrace = presentationReducer(initialPresentationState, {
type: "jump",
location: { kind: "main", sceneId: "interrupt-evidence", beatId: "trace", focusPath: [] },
location: { kind: "main", sceneId: "resume-output-evidence", beatId: "trace", focusPath: [] },
});
expect(stateAtTrace.evidencePresentationOverride).toBeNull();
@@ -248,7 +248,7 @@ describe("presentationReducer", () => {
it("returns to the beat receipt after closing an explicit inspector", () => {
const atReceiptBeat = presentationReducer(initialPresentationState, {
type: "jump",
location: { kind: "main", sceneId: "interrupt-evidence", beatId: "trace", focusPath: [] },
location: { kind: "main", sceneId: "resume-output-evidence", beatId: "trace", focusPath: [] },
});
expect(compositionForState(atReceiptBeat).evidencePresentation).toBe("receipt");
const opened = presentationReducer(atReceiptBeat, {