refactor: remove duplicate authoring scene
This commit is contained in:
@@ -77,13 +77,13 @@ describe("PresentationRoute", () => {
|
||||
{ hash: "#scene/thesis/title", heading: "Design and Implementation of lda.chat", hasDemoChrome: false },
|
||||
{ hash: "#scene/architecture/overview", heading: "Architecture Zoom", hasDemoChrome: false },
|
||||
{ hash: "#scene/architecture/client", heading: "Architecture Zoom", hasDemoChrome: false },
|
||||
{ hash: "#scene/authoring/diagnose", heading: "Author, Validate, Repair", hasDemoChrome: false },
|
||||
{ hash: "#scene/prepared-lifecycle/diagnose", heading: "Diagnose invalid draft", hasDemoChrome: true },
|
||||
{
|
||||
hash: "#scene/agent-handoff/request",
|
||||
heading: "What should the workflow author prepare?",
|
||||
hasDemoChrome: true,
|
||||
},
|
||||
{ hash: "#scene/prepared-lifecycle/discover", heading: "Prepared Workflow Lifecycle", hasDemoChrome: true },
|
||||
{ hash: "#scene/prepared-lifecycle/discover", heading: "Discover capabilities", hasDemoChrome: true },
|
||||
{ hash: "#scene/run-from-deployment/graph", heading: "Run From Deployment", hasDemoChrome: true },
|
||||
{ hash: "#scene/typed-human-boundary/approval", heading: "Typed Human Boundary", hasDemoChrome: true },
|
||||
{ hash: "#scene/resume-output-evidence/trace", heading: "Resume, Output, Evidence", hasDemoChrome: true },
|
||||
@@ -124,8 +124,8 @@ describe("PresentationRoute", () => {
|
||||
const visualRouteContracts = [
|
||||
{ hash: "#scene/thesis/title", heading: "Design and Implementation of lda.chat", primary: "thesis opening" },
|
||||
{ hash: "#scene/lifecycle/draft", heading: "Workflow Lifecycle", primary: "workflow lifecycle rail" },
|
||||
{ hash: "#scene/authoring/diagnose", heading: "Author, Validate, Repair", primary: "agent authoring loop" },
|
||||
{ hash: "#scene/prepared-lifecycle/validate", heading: "Prepared Workflow Lifecycle", primary: "prepared workflow authoring lifecycle" },
|
||||
{ hash: "#scene/prepared-lifecycle/diagnose", heading: "Diagnose invalid draft", primary: "prepared workflow authoring lifecycle" },
|
||||
{ hash: "#scene/prepared-lifecycle/repair", heading: "Apply targeted repair", primary: "prepared workflow authoring lifecycle" },
|
||||
{ hash: "#scene/run-from-deployment/graph", heading: "Run From Deployment", primary: "workflow graph" },
|
||||
{ hash: "#scene/evaluation/findings", heading: "Evaluation", primary: "evaluation evidence board" },
|
||||
{ hash: "#scene/conclusion/conclusion", heading: "Limits and Conclusion", primary: "thesis contribution boundary" },
|
||||
@@ -192,10 +192,10 @@ describe("PresentationRoute", () => {
|
||||
render(<PresentationRoute />);
|
||||
expect(screen.getByRole("textbox", { name: /authoring request/i })).toBeInTheDocument();
|
||||
await userEvent.keyboard("{ArrowRight}");
|
||||
expect(await screen.findByLabelText("authoring phase rail")).toBeInTheDocument();
|
||||
expect(await screen.findByLabelText("prepared authoring lifecycle")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("advances Draft to Validate once and projects the edited request", async () => {
|
||||
it("advances Draft to Diagnose once and projects the edited request", async () => {
|
||||
window.location.hash = "#scene/prepared-lifecycle/draft";
|
||||
const { PresentationRoute } = await import("./PresentationRoute.js");
|
||||
render(<PresentationRoute />);
|
||||
@@ -205,10 +205,10 @@ describe("PresentationRoute", () => {
|
||||
await userEvent.type(message, "Check this edited draft request");
|
||||
await userEvent.click(screen.getByRole("button", { name: /send message/i }));
|
||||
|
||||
expect(window.location.hash).toBe("#scene/prepared-lifecycle/validate");
|
||||
expect(window.location.hash).toBe("#scene/prepared-lifecycle/diagnose");
|
||||
expect(await screen.findByText("Check this edited draft request")).toBeInTheDocument();
|
||||
expect(screen.getByRole("complementary", { name: /prepared authoring assistant/i }))
|
||||
.toHaveAttribute("data-phase", "validate");
|
||||
.toHaveAttribute("data-phase", "diagnose");
|
||||
});
|
||||
|
||||
it("advances Artifact to Deployment once and projects the edited request", async () => {
|
||||
@@ -243,8 +243,8 @@ describe("PresentationRoute", () => {
|
||||
.toBe(false);
|
||||
});
|
||||
|
||||
it("keeps Validate submission on the current beat", async () => {
|
||||
window.location.hash = "#scene/prepared-lifecycle/validate";
|
||||
it("keeps Diagnose submission on the current beat", async () => {
|
||||
window.location.hash = "#scene/prepared-lifecycle/diagnose";
|
||||
const { PresentationRoute } = await import("./PresentationRoute.js");
|
||||
render(<PresentationRoute />);
|
||||
|
||||
@@ -252,9 +252,9 @@ describe("PresentationRoute", () => {
|
||||
await userEvent.type(message, "Keep validating this draft");
|
||||
await userEvent.click(screen.getByRole("button", { name: /send message/i }));
|
||||
|
||||
expect(window.location.hash).toBe("#scene/prepared-lifecycle/validate");
|
||||
expect(window.location.hash).toBe("#scene/prepared-lifecycle/diagnose");
|
||||
expect(screen.getByRole("complementary", { name: /prepared authoring assistant/i }))
|
||||
.toHaveAttribute("data-phase", "validate");
|
||||
.toHaveAttribute("data-phase", "diagnose");
|
||||
});
|
||||
|
||||
it("renders audience progress chrome without rail or mode label", async () => {
|
||||
@@ -720,7 +720,8 @@ describe("PresentationRoute", () => {
|
||||
it.each([
|
||||
"#scene/prepared-lifecycle/discover",
|
||||
"#scene/prepared-lifecycle/draft",
|
||||
"#scene/prepared-lifecycle/validate",
|
||||
"#scene/prepared-lifecycle/diagnose",
|
||||
"#scene/prepared-lifecycle/repair",
|
||||
"#scene/prepared-lifecycle/artifact",
|
||||
"#scene/prepared-lifecycle/deployment",
|
||||
])("navigates to Scene 9 beat %s", async (hash) => {
|
||||
@@ -728,7 +729,7 @@ describe("PresentationRoute", () => {
|
||||
const { PresentationRoute } = await import("./PresentationRoute.js");
|
||||
render(<PresentationRoute />);
|
||||
|
||||
expect(await screen.findByLabelText("authoring phase rail")).toBeInTheDocument();
|
||||
expect(await screen.findByLabelText("prepared authoring lifecycle")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("navigating Scene 9 beats does not call workflow authoring RPC operations", async () => {
|
||||
@@ -739,7 +740,7 @@ describe("PresentationRoute", () => {
|
||||
const { PresentationRoute } = await import("./PresentationRoute.js");
|
||||
render(<PresentationRoute />);
|
||||
|
||||
expect(await screen.findByLabelText("authoring phase rail")).toBeInTheDocument();
|
||||
expect(await screen.findByLabelText("prepared authoring lifecycle")).toBeInTheDocument();
|
||||
const authoringCalls = mockCallOp.mock.calls.filter((c) => c[0] !== "workflow.health");
|
||||
expect(authoringCalls).toHaveLength(0);
|
||||
});
|
||||
|
||||
@@ -263,7 +263,7 @@ export const PresentationRoute = () => {
|
||||
[],
|
||||
);
|
||||
|
||||
const handleScene9Advance = useCallback(() => {
|
||||
const handlePreparedLifecycleAdvance = useCallback(() => {
|
||||
if (
|
||||
state.location.kind !== "main"
|
||||
|| state.location.sceneId !== "prepared-lifecycle"
|
||||
@@ -300,7 +300,7 @@ export const PresentationRoute = () => {
|
||||
retryHealth={targetStatusController.retryHealth}
|
||||
liveTargetReady={targetStatusController.liveTargetReady}
|
||||
jump={handleJump}
|
||||
onScene9Advance={handleScene9Advance}
|
||||
onPreparedLifecycleAdvance={handlePreparedLifecycleAdvance}
|
||||
selectNode={(nodeId) => dispatch({ type: "select_node", nodeId })}
|
||||
openEvidence={() => dispatch({ type: "set_evidence_presentation", presentation: "inspector" })}
|
||||
closeOverlay={() => dispatch({ type: "close_overlay" })}
|
||||
|
||||
@@ -28,7 +28,7 @@ type PresentationStageProps = {
|
||||
readonly retryHealth: () => void;
|
||||
readonly liveTargetReady: boolean;
|
||||
readonly jump: (location: MainLocation) => void;
|
||||
readonly onScene9Advance?: (() => void) | undefined;
|
||||
readonly onPreparedLifecycleAdvance?: (() => void) | undefined;
|
||||
readonly selectNode: (nodeId: string | null) => void;
|
||||
readonly openEvidence: () => void;
|
||||
readonly closeOverlay: () => void;
|
||||
@@ -49,7 +49,7 @@ export const PresentationStage = ({
|
||||
retryHealth,
|
||||
liveTargetReady,
|
||||
jump,
|
||||
onScene9Advance,
|
||||
onPreparedLifecycleAdvance,
|
||||
selectNode,
|
||||
openEvidence,
|
||||
closeOverlay,
|
||||
@@ -108,7 +108,7 @@ export const PresentationStage = ({
|
||||
}}
|
||||
motionDisabled={state.motionDisabled}
|
||||
approvalActions={approvalActions}
|
||||
onScene9Advance={onScene9Advance}
|
||||
onPreparedLifecycleAdvance={onPreparedLifecycleAdvance}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
|
||||
@@ -368,40 +368,14 @@ describe("SceneBody", () => {
|
||||
expect(screen.getByLabelText("positioning map")).toHaveAttribute("data-positioning-active-region", "lda");
|
||||
});
|
||||
|
||||
it("renders Scene 7 as an agent authoring loop with beat-specific emphasis", () => {
|
||||
const location: PresentationLocation = { kind: "main", sceneId: "authoring", beatId: "diagnose", focusPath: [] };
|
||||
render(
|
||||
<SceneBody
|
||||
location={location}
|
||||
demo={demo}
|
||||
selectedNodeId={null}
|
||||
selectNode={noop}
|
||||
openEvidence={noop}
|
||||
openDiscussion={noop}
|
||||
onFocusPathChange={noop}
|
||||
motionDisabled={false}
|
||||
/>,
|
||||
);
|
||||
it("renders Prepared Lifecycle with its migrated defense discussion rail", () => {
|
||||
renderSceneBodyAtMainLocation("prepared-lifecycle", "diagnose");
|
||||
|
||||
const composition = screen.getByLabelText("agent authoring loop");
|
||||
expect(composition).toHaveAttribute("data-active-stage", "diagnose");
|
||||
expect(composition).toHaveAttribute("data-presentation-surface", "editorial");
|
||||
expect(screen.getByRole("article", { name: /validate product evidence/i })).toBeInTheDocument();
|
||||
expect(screen.getByRole("region", { name: /validation repair evidence/i })).toHaveAttribute(
|
||||
"data-authoring-focus",
|
||||
"diagnose",
|
||||
);
|
||||
expect(screen.getByText("workflow.draft_workspaces.validate")).toBeInTheDocument();
|
||||
const loop = screen.getByLabelText("authoring phase loop");
|
||||
expect(loop).not.toHaveAttribute("data-readable-surface", "dark");
|
||||
expect(screen.getByText("Discover capability")).toBeInTheDocument();
|
||||
expect(screen.getByText("Author draft")).toBeInTheDocument();
|
||||
expect(screen.getByText(/operates on the mutable Draft.*external agent proposal.*Artifact, Deployment, and Run/i)).toBeInTheDocument();
|
||||
expect(screen.getByText("Validate and diagnose").closest("[data-authoring-active]")).toHaveAttribute("data-authoring-active", "true");
|
||||
expect(screen.getByText("Validate and diagnose").closest(".scene-body__authoring-node"))
|
||||
.not.toHaveAttribute("data-readable-surface", "dark");
|
||||
expect(within(loop).getByText("Repair")).toBeInTheDocument();
|
||||
expect(within(loop).getByText("Compile or save")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("prepared authoring lifecycle")).toBeInTheDocument();
|
||||
const rail = screen.getByLabelText("defense discussion topics");
|
||||
expect(within(rail).getByRole("button", { name: /Raw plan import/i })).toBeInTheDocument();
|
||||
expect(within(rail).getByRole("button", { name: /Validation and diagnostics/i })).toBeInTheDocument();
|
||||
expect(within(rail).getByRole("button", { name: /Why schemas matter/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders discussion branches as a labelled presenter rail", () => {
|
||||
@@ -427,7 +401,7 @@ describe("SceneBody", () => {
|
||||
});
|
||||
|
||||
it("gives the repair beat its own correction visual", () => {
|
||||
const location: PresentationLocation = { kind: "main", sceneId: "authoring", beatId: "repair", focusPath: [] };
|
||||
const location: PresentationLocation = { kind: "main", sceneId: "prepared-lifecycle", beatId: "repair", focusPath: [] };
|
||||
render(
|
||||
<SceneBody
|
||||
location={location}
|
||||
@@ -441,14 +415,18 @@ describe("SceneBody", () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole("region", { name: /validation repair evidence/i })).toHaveAttribute(
|
||||
"data-authoring-focus",
|
||||
expect(screen.getByRole("region", { name: "active authoring operation" })).toHaveAttribute(
|
||||
"data-authoring-step",
|
||||
"repair",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps discussion rails out of workflow proof scenes", () => {
|
||||
const location: PresentationLocation = { kind: "main", sceneId: "run-from-deployment", beatId: "graph", focusPath: [] };
|
||||
it.each([
|
||||
["run-from-deployment", "graph"],
|
||||
["typed-human-boundary", "approval"],
|
||||
["resume-output-evidence", "trace"],
|
||||
] as const)("keeps discussion rails out of %s proof scenes", (sceneId, beatId) => {
|
||||
const location: PresentationLocation = { kind: "main", sceneId, beatId, focusPath: [] };
|
||||
render(
|
||||
<SceneBody
|
||||
location={location}
|
||||
@@ -514,13 +492,13 @@ describe("SceneBody", () => {
|
||||
|
||||
it("renders Scene 9 discover beat with prepared authoring phases", () => {
|
||||
renderSceneBodyAtMainLocation("prepared-lifecycle", "discover");
|
||||
expect(screen.getByLabelText("authoring phase rail")).toBeInTheDocument();
|
||||
expect(screen.getByText("Discover")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("prepared authoring lifecycle")).toBeInTheDocument();
|
||||
expect(screen.getAllByText("Discover").length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it("renders Scene 9 artifact beat with compiled artifact evidence", () => {
|
||||
renderSceneBodyAtMainLocation("prepared-lifecycle", "artifact");
|
||||
expect(screen.getByText("Artifact")).toBeInTheDocument();
|
||||
expect(screen.getAllByText("Artifact").length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getAllByText(/lda_report_case_study/i).length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -18,9 +18,6 @@ import { ConclusionScene } from "./conclusion/ConclusionScene.js";
|
||||
import { DefenseDiscussionIndex } from "./discussion/DefenseDiscussionIndex.js";
|
||||
import { EvaluationEvidenceScene } from "./evaluation/EvaluationEvidenceScene.js";
|
||||
import { ArchitectureScene } from "./scenes/ArchitectureScene.js";
|
||||
import { AuthoringPhaseVisual } from "./authoring/AuthoringPhaseVisual.js";
|
||||
import { projectPreparedAuthoringPhase } from "./authoring/authoring-projection.js";
|
||||
import type { AuthoringPhaseId } from "./authoring/authoring-recording.js";
|
||||
import { OpeningThesisScene } from "./opening/OpeningThesisScene.js";
|
||||
import { ProblemLoopScene } from "./opening/ProblemLoopScene.js";
|
||||
|
||||
@@ -35,7 +32,7 @@ type SceneBodyProps = {
|
||||
readonly onFocusPathChange: (path: readonly string[]) => void;
|
||||
readonly motionDisabled: boolean;
|
||||
readonly approvalActions?: DemoApprovalActions | undefined;
|
||||
readonly onScene9Advance?: (() => void) | undefined;
|
||||
readonly onPreparedLifecycleAdvance?: (() => void) | undefined;
|
||||
};
|
||||
|
||||
const workflowDemoSceneIds = new Set([
|
||||
@@ -289,94 +286,19 @@ const LifecycleScene = ({ scene, beat, motionDisabled }: ChoreographyProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const authoringSteps = [
|
||||
{ id: "discover", label: "Discover capability", detail: "wf schema / cap inspect" },
|
||||
{ id: "author", label: "Author draft", detail: "wf draft create / add-step / bind" },
|
||||
{ id: "diagnose", label: "Validate and diagnose", detail: "structured diagnostics + repair hints" },
|
||||
{ id: "repair", label: "Repair", detail: "focused edit, no full rewrite" },
|
||||
{ id: "compile", label: "Compile or save", detail: "artifact / deployment / run" },
|
||||
] as const;
|
||||
|
||||
// Scene 7 uses speaker-friendly beat names; the prepared recording keeps the
|
||||
// underlying product phases (`draft` and `validate`) as its canonical IDs.
|
||||
const authoringPhaseForBeat = (beatId: string): AuthoringPhaseId => {
|
||||
if (beatId === "author") return "draft";
|
||||
if (beatId === "diagnose" || beatId === "repair") return "validate";
|
||||
return beatId as AuthoringPhaseId;
|
||||
};
|
||||
|
||||
const AuthoringScene = ({ scene, beat }: { scene: SceneDefinition; beat: SceneBeatDefinition }) => {
|
||||
const projection = projectPreparedAuthoringPhase(authoringPhaseForBeat(beat.id));
|
||||
const primaryCommand = projection.commands[0];
|
||||
// The prepared recording is the factual source for this public-operation label.
|
||||
if (!primaryCommand) throw new Error(`Authoring phase ${projection.phase} has no public operation`);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StageCaption eyebrow="Act II · implemented" title={scene.title}>
|
||||
<p>{beat.caption}</p>
|
||||
</StageCaption>
|
||||
<section
|
||||
className="scene-body__authoring-composition"
|
||||
aria-label="agent authoring loop"
|
||||
data-active-stage={beat.id}
|
||||
data-presentation-surface="editorial"
|
||||
>
|
||||
<article className="scene-body__authoring-evidence" aria-label={`${projection.label} product evidence`}>
|
||||
<header>
|
||||
<span>Public operation</span>
|
||||
<strong>{primaryCommand.title}</strong>
|
||||
<p>{projection.summary}</p>
|
||||
</header>
|
||||
<AuthoringPhaseVisual
|
||||
projection={projection}
|
||||
focus={beat.id === "diagnose" || beat.id === "repair" ? beat.id : "full"}
|
||||
/>
|
||||
</article>
|
||||
<div
|
||||
className="scene-body__authoring-loop"
|
||||
aria-label="authoring phase loop"
|
||||
>
|
||||
<div className="scene-body__authoring-loop-rail" aria-hidden="true" />
|
||||
{authoringSteps.map((step, i) => {
|
||||
const isActive = beat.id === step.id;
|
||||
const isPast = authoringSteps.findIndex((candidate) => candidate.id === beat.id) > i;
|
||||
return (
|
||||
<div
|
||||
key={step.id}
|
||||
className="scene-body__authoring-node"
|
||||
data-authoring-active={isActive}
|
||||
data-authoring-past={isPast}
|
||||
>
|
||||
<span className="scene-body__authoring-number">{i + 1}</span>
|
||||
<strong>{step.label}</strong>
|
||||
<small>{step.detail}</small>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
<p className="scene-body__evidence">{scene.evidencePointer}</p>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const assertNever = (value: never): never => {
|
||||
throw new Error(`Unexpected view: ${value}`);
|
||||
};
|
||||
|
||||
export const SceneBody = ({ location, demo, selectedNodeId, selectNode, openEvidence, openDiscussion, onFocusPathChange, motionDisabled, approvalActions, onScene9Advance }: SceneBodyProps) => {
|
||||
export const SceneBody = ({ location, demo, selectedNodeId, selectNode, openEvidence, openDiscussion, onFocusPathChange, motionDisabled, approvalActions, onPreparedLifecycleAdvance }: SceneBodyProps) => {
|
||||
const sceneId = location.kind === "main" ? location.sceneId : "positioning";
|
||||
const beatId = location.kind === "main" ? location.beatId : "landscape";
|
||||
const scene = findScene(sceneId) ?? findScene("thesis")!;
|
||||
const beat = findBeat(sceneId, beatId) ?? scene.beats[0]!;
|
||||
|
||||
// The questions beat owns the full discussion index. Workflow demo scenes
|
||||
// keep the product proof uncluttered; their discussion topics remain
|
||||
// available from the global presenter controls.
|
||||
const isWorkflowDemoScene = workflowDemoSceneIds.has(scene.id);
|
||||
const showDiscussionRail = !(scene.id === "conclusion" && beat.id === "questions")
|
||||
&& !isWorkflowDemoScene;
|
||||
&& (!isWorkflowDemoScene || scene.id === "prepared-lifecycle");
|
||||
const discussionLinks = showDiscussionRail ? <DiscussionLinks sceneId={scene.id} openDiscussion={openDiscussion} /> : null;
|
||||
const content = (() => {
|
||||
switch (scene.view) {
|
||||
@@ -401,12 +323,10 @@ export const SceneBody = ({ location, demo, selectedNodeId, selectNode, openEvid
|
||||
motionDisabled={motionDisabled}
|
||||
/>
|
||||
);
|
||||
case "authoring":
|
||||
return <AuthoringScene scene={scene} beat={beat} />;
|
||||
case "agent":
|
||||
return <AgentHandoffScene scene={scene} beat={beat} />;
|
||||
case "demo-lifecycle":
|
||||
return <PreparedAuthoringLifecycleScene scene={scene} beat={beat} onAdvance={onScene9Advance} />;
|
||||
case "demo-lifecycle":
|
||||
return <PreparedAuthoringLifecycleScene scene={scene} beat={beat} onAdvance={onPreparedLifecycleAdvance} />;
|
||||
case "demo":
|
||||
return (
|
||||
<DemoWorkflowScene
|
||||
|
||||
@@ -52,7 +52,7 @@ describe("isDemoChromeScene", () => {
|
||||
expect(isDemoChromeScene(sceneId)).toBe(true);
|
||||
}
|
||||
|
||||
for (const sceneId of ["thesis", "architecture", "authoring", "evaluation", "conclusion"] as const) {
|
||||
for (const sceneId of ["thesis", "architecture", "lifecycle", "evaluation", "conclusion"] as const) {
|
||||
expect(isDemoChromeScene(sceneId)).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -237,7 +237,7 @@ describe("presentationReducer", () => {
|
||||
it("derives a receipt from beat metadata without opening an inspector", () => {
|
||||
const state = presentationReducer(initialPresentationState, {
|
||||
type: "jump",
|
||||
location: { kind: "main", sceneId: "architecture", beatId: "node-use", focusPath: ["node-use"] },
|
||||
location: { kind: "main", sceneId: "resume-output-evidence", beatId: "trace", focusPath: [] },
|
||||
});
|
||||
expect(compositionForState(state).evidencePresentation).toBe("receipt");
|
||||
expect(state.evidencePresentationOverride).toBeNull();
|
||||
@@ -279,7 +279,7 @@ describe("presentationReducer", () => {
|
||||
it("closes the inspector and recomputes receipt state when the beat changes", () => {
|
||||
const atReceiptBeat = presentationReducer(initialPresentationState, {
|
||||
type: "jump",
|
||||
location: { kind: "main", sceneId: "architecture", beatId: "node-use", focusPath: ["node-use"] },
|
||||
location: { kind: "main", sceneId: "resume-output-evidence", beatId: "trace", focusPath: [] },
|
||||
});
|
||||
const opened = presentationReducer(atReceiptBeat, {
|
||||
type: "set_evidence_presentation",
|
||||
@@ -293,7 +293,7 @@ describe("presentationReducer", () => {
|
||||
it("does not treat a receipt as an Escape-closeable overlay", () => {
|
||||
const receipt = presentationReducer(initialPresentationState, {
|
||||
type: "jump",
|
||||
location: { kind: "main", sceneId: "authoring", beatId: "diagnose", focusPath: [] },
|
||||
location: { kind: "main", sceneId: "prepared-lifecycle", beatId: "diagnose", focusPath: [] },
|
||||
});
|
||||
expect(presentationReducer(receipt, { type: "close_overlay" })).toEqual(receipt);
|
||||
});
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
/* Presentation roots own their visual surfaces; do not inherit console cards. */
|
||||
.presentation-stage__primary > .architecture-scene,
|
||||
.presentation-stage__primary > .scene-body__authoring-composition,
|
||||
.presentation-stage__primary > .prepared-lifecycle-scene,
|
||||
.presentation-stage__primary > .opening-thesis-scene {
|
||||
margin: 0;
|
||||
@@ -38,7 +37,6 @@
|
||||
|
||||
.agent-handoff-scene[data-presentation-surface="editorial"],
|
||||
.prepared-lifecycle-scene[data-presentation-surface="editorial"],
|
||||
.scene-body__authoring-composition[data-presentation-surface="editorial"],
|
||||
.authoring-visual[data-presentation-surface="editorial"] {
|
||||
--authoring-paper: var(--color-editorial-paper, oklch(0.975 0.012 82));
|
||||
--authoring-ink: var(--color-editorial-ink, oklch(0.19 0.015 65));
|
||||
@@ -1750,215 +1748,6 @@
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.scene-body__authoring-loop {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
gap: 0.75rem;
|
||||
margin-top: 1rem;
|
||||
padding: 0.55rem 0 0.2rem;
|
||||
}
|
||||
|
||||
.scene-body__authoring-loop-rail {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
top: 2.15rem;
|
||||
left: 8%;
|
||||
right: 8%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, var(--accent-cyan), color-mix(in oklch, var(--accent-cyan) 20%, transparent));
|
||||
}
|
||||
|
||||
.scene-body__authoring-node {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
align-content: start;
|
||||
gap: 0.35rem;
|
||||
min-height: 5.8rem;
|
||||
border: 1px solid var(--authoring-rule, color-mix(in oklch, var(--authoring-muted) 32%, transparent));
|
||||
border-radius: 0.2rem;
|
||||
padding: 0.75rem;
|
||||
background: transparent;
|
||||
color: var(--authoring-ink, var(--text-primary));
|
||||
transition: opacity 180ms ease, transform 180ms ease, border-color 180ms ease;
|
||||
}
|
||||
|
||||
.scene-body__authoring-node strong {
|
||||
color: var(--authoring-ink, var(--text-primary));
|
||||
}
|
||||
|
||||
.scene-body__authoring-node[data-authoring-active="true"] {
|
||||
z-index: 2;
|
||||
transform: translateY(-0.35rem) scale(1.04);
|
||||
border-color: var(--accent-cyan);
|
||||
background: color-mix(in oklch, var(--accent-cyan) 8%, var(--authoring-paper, white));
|
||||
}
|
||||
|
||||
.scene-body__authoring-node[data-authoring-past="true"] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.scene-body__authoring-node small {
|
||||
color: var(--authoring-muted, var(--text-muted));
|
||||
font: 0.72rem/1.35 var(--font-interface);
|
||||
}
|
||||
|
||||
@media (max-width: 1050px) {
|
||||
.scene-body__authoring-loop {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.scene-body__authoring-loop-rail {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.scene-body__authoring-composition {
|
||||
display: grid;
|
||||
grid-template-rows: minmax(0, 1fr) auto;
|
||||
gap: 0.7rem;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
background: var(--authoring-paper, var(--color-editorial-paper, oklch(0.975 0.012 82)));
|
||||
color: var(--authoring-ink, var(--color-editorial-ink, oklch(0.19 0.015 65)));
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence {
|
||||
display: grid;
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--authoring-rule, color-mix(in oklch, var(--authoring-muted) 32%, transparent));
|
||||
border-radius: 0.2rem;
|
||||
padding: 1rem 1.15rem;
|
||||
background: var(--authoring-paper, var(--color-editorial-paper, oklch(0.975 0.012 82)));
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence > header {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
gap: 0.2rem 0.65rem;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence > header span {
|
||||
color: var(--authoring-muted, var(--accent-cyan));
|
||||
font: 700 0.65rem/1 var(--font-evidence);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence > header strong {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: var(--authoring-ink, var(--text-primary));
|
||||
font: 700 0.82rem/1.2 var(--font-evidence);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence > header p {
|
||||
grid-column: 1 / -1;
|
||||
margin: 0;
|
||||
color: var(--authoring-muted, var(--text-secondary));
|
||||
font: 0.82rem/1.3 var(--font-interface);
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual {
|
||||
min-height: 0;
|
||||
height: auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual--repair {
|
||||
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
||||
gap: 0.55rem 0.8rem;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-repair__diagnostic,
|
||||
.scene-body__authoring-evidence .authoring-repair__correction {
|
||||
min-height: 0;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual--inventory,
|
||||
.scene-body__authoring-evidence .authoring-visual--graph,
|
||||
.scene-body__authoring-evidence .authoring-visual--repair {
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual--graph .authoring-graph__node {
|
||||
min-width: 12rem;
|
||||
min-height: 8rem;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual--repair[data-authoring-focus="diagnose"] {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual--repair[data-authoring-focus="diagnose"] .authoring-repair__connector,
|
||||
.scene-body__authoring-evidence .authoring-visual--repair[data-authoring-focus="diagnose"] .authoring-repair__correction,
|
||||
.scene-body__authoring-evidence .authoring-visual--repair[data-authoring-focus="diagnose"] .authoring-repair__status {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual--repair[data-authoring-focus="diagnose"] .authoring-repair__diagnostic {
|
||||
grid-column: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual--repair[data-authoring-focus="repair"] {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual--repair[data-authoring-focus="repair"] .authoring-repair__diagnostic,
|
||||
.scene-body__authoring-evidence .authoring-visual--repair[data-authoring-focus="repair"] .authoring-repair__connector {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence .authoring-visual--repair[data-authoring-focus="repair"] .authoring-repair__correction {
|
||||
grid-column: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.scene-body__authoring-composition .scene-body__authoring-loop {
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
flex: 0 0 auto;
|
||||
min-height: 6.4rem;
|
||||
margin-top: 0;
|
||||
padding-top: 0.55rem;
|
||||
}
|
||||
|
||||
.scene-body__authoring-composition .scene-body__authoring-node {
|
||||
min-height: 5.8rem;
|
||||
padding: 0.55rem;
|
||||
}
|
||||
|
||||
.scene-body__authoring-evidence,
|
||||
.scene-body__authoring-node,
|
||||
.authoring-visual {
|
||||
transition: opacity 180ms ease, transform 180ms ease, border-color 180ms ease;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.scene-body__authoring-evidence,
|
||||
.scene-body__authoring-node,
|
||||
.authoring-visual {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1050px) {
|
||||
.scene-body__authoring-composition .scene-body__authoring-loop {
|
||||
grid-template-columns: repeat(5, minmax(9.5rem, 1fr));
|
||||
overflow-x: auto;
|
||||
padding-bottom: 0.35rem;
|
||||
}
|
||||
}
|
||||
|
||||
.scene-body__lifecycle-number {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -1971,19 +1760,6 @@
|
||||
font: 800 0.72rem/1 var(--font-mono, monospace);
|
||||
}
|
||||
|
||||
.scene-body__authoring-number {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1.4rem;
|
||||
height: 1.4rem;
|
||||
border-radius: 50%;
|
||||
background: oklch(0.7 0.16 195);
|
||||
color: oklch(0.12 0.025 250);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Demo lifecycle scene */
|
||||
.demo-lifecycle-scene {
|
||||
display: grid;
|
||||
@@ -3706,6 +3482,11 @@
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.presentation-stage__primary > .prepared-lifecycle-scene + .scene-body__discussion-links {
|
||||
margin-top: 0;
|
||||
padding-top: 0.3rem;
|
||||
}
|
||||
|
||||
.prepared-lifecycle-scene__rail::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
@@ -4145,10 +3926,6 @@
|
||||
}
|
||||
|
||||
@container presentation-canvas (max-width: 1050px) {
|
||||
.scene-body__authoring-composition .scene-body__authoring-evidence {
|
||||
padding: 0.75rem 0.85rem;
|
||||
}
|
||||
|
||||
.prepared-lifecycle-scene[data-presentation-surface="editorial"] {
|
||||
grid-template-columns: minmax(10.5rem, 0.28fr) minmax(0, 0.72fr);
|
||||
gap: 0.6rem;
|
||||
|
||||
@@ -191,38 +191,6 @@ export const presenterNotes = [
|
||||
"NodeUse **invokes a NodeDef handler**, reduces state, records trace, and routes the declared outcome.",
|
||||
["Thesis Workflow Core Model"],
|
||||
),
|
||||
beatNote(
|
||||
"authoring",
|
||||
"discover",
|
||||
10,
|
||||
"Before authoring, a client can discover sources, capabilities, and schemas instead of guessing at hidden interfaces.",
|
||||
["CLI documentation", "Draft authoring API", "Challenge UX findings"],
|
||||
{ qnaBranchIds: ["why-schemas", "validation-diagnostics"] },
|
||||
),
|
||||
beatNote(
|
||||
"authoring",
|
||||
"author",
|
||||
10,
|
||||
"Focused operations let an external agent change a mutable Draft while preserving a clear lifecycle boundary.",
|
||||
["CLI documentation", "Draft authoring API"],
|
||||
{ qnaBranchIds: ["raw-plan-import"] },
|
||||
),
|
||||
beatNote(
|
||||
"authoring",
|
||||
"diagnose",
|
||||
10,
|
||||
"Validation returns structured diagnostics, affected paths, repair hints, and suggested next actions.",
|
||||
["Validation and diagnostics", "Challenge UX findings"],
|
||||
{ qnaBranchIds: ["validation-diagnostics"] },
|
||||
),
|
||||
beatNote(
|
||||
"authoring",
|
||||
"repair",
|
||||
10,
|
||||
"These surfaces make invalid intermediate drafts repairable; they support a loop, but no hint guarantees success.",
|
||||
["Validation and diagnostics", "Challenge UX findings"],
|
||||
{ warning: "Do not promise that diagnostics automatically repair every workflow.", qnaBranchIds: ["validation-diagnostics"] },
|
||||
),
|
||||
beatNote(
|
||||
"agent-handoff",
|
||||
"request",
|
||||
@@ -240,23 +208,32 @@ export const presenterNotes = [
|
||||
9,
|
||||
"The later issue-review example first inspects configured local.lda_docs, report, and issue-board capabilities.",
|
||||
["examples/lda_report_workflow", "deployment inspect replay evidence"],
|
||||
{ qnaBranchIds: ["prepared-replay-boundary"] },
|
||||
{ qnaBranchIds: ["prepared-replay-boundary", "why-schemas", "validation-diagnostics"] },
|
||||
),
|
||||
beatNote(
|
||||
"prepared-lifecycle",
|
||||
"draft",
|
||||
9,
|
||||
"It creates and edits a Draft for report generation, making the proposal visible before execution.",
|
||||
["examples/lda_report_workflow", "deployment inspect replay evidence"],
|
||||
["examples/lda_report_workflow", "deployment inspect replay evidence", "CLI documentation", "Draft authoring API"],
|
||||
{ qnaBranchIds: ["raw-plan-import"] },
|
||||
),
|
||||
beatNote(
|
||||
"prepared-lifecycle",
|
||||
"validate",
|
||||
"diagnose",
|
||||
9,
|
||||
"It validates incomplete state, exposes a missing output binding, and applies a targeted repair.",
|
||||
"Validation returns structured diagnostics, affected paths, repair hints, and suggested next actions.",
|
||||
["examples/lda_report_workflow", "deployment inspect replay evidence"],
|
||||
{ qnaBranchIds: ["validation-diagnostics"] },
|
||||
),
|
||||
beatNote(
|
||||
"prepared-lifecycle",
|
||||
"repair",
|
||||
9,
|
||||
"These surfaces make invalid intermediate drafts repairable; they support a loop, but no hint guarantees success.",
|
||||
["Validation and diagnostics", "Challenge UX findings"],
|
||||
{ warning: "Do not promise that diagnostics automatically repair every workflow.", qnaBranchIds: ["validation-diagnostics"] },
|
||||
),
|
||||
beatNote(
|
||||
"prepared-lifecycle",
|
||||
"artifact",
|
||||
|
||||
@@ -146,6 +146,15 @@ describe("defense storyboard catalog", () => {
|
||||
"mcp-agent-scale",
|
||||
"not-just-scripts",
|
||||
]);
|
||||
expect(
|
||||
discussionBranches
|
||||
.filter((branch) => branch.parentSceneId === "prepared-lifecycle")
|
||||
.map((branch) => branch.id),
|
||||
).toEqual(expect.arrayContaining([
|
||||
"raw-plan-import",
|
||||
"validation-diagnostics",
|
||||
"why-schemas",
|
||||
]));
|
||||
for (const branch of discussionBranches) {
|
||||
expect(branch.title.length).toBeGreaterThan(0);
|
||||
expect(branch.summary.length).toBeGreaterThan(0);
|
||||
|
||||
Reference in New Issue
Block a user