fix: close final Scene 8 review findings
This commit is contained in:
@@ -14,6 +14,7 @@ export type PreparedAuthoringToolName =
|
||||
| "workflow.draft_workspaces.create_from_capability"
|
||||
| "workflow.draft_workspaces.add_step_from_capability"
|
||||
| "workflow.draft_workspaces.get"
|
||||
| "workflow.draft_workspaces.remove_route"
|
||||
| "workflow.draft_workspaces.validate"
|
||||
| "workflow.draft_workspaces.set_route"
|
||||
| "workflow.draft_workspaces.compile"
|
||||
|
||||
@@ -121,6 +121,9 @@ describe("PresentationRoute", () => {
|
||||
expect(within(result).getByText("missing_outcome_edge")).toBeInTheDocument();
|
||||
expect(within(result).getByText("nodes[analyze]")).toBeInTheDocument();
|
||||
expect(within(result).getByText(/missing edges for outcomes.*ok/i)).toBeInTheDocument();
|
||||
expect(within(result).getByRole("note", { name: /prepared fault injection/i })).toHaveTextContent(
|
||||
"wf draft remove-route lda_report_workflow --revision 2 --step analyze --outcome ok",
|
||||
);
|
||||
expect(screen.queryByText(/missing output projection/i)).not.toBeInTheDocument();
|
||||
}, 15000);
|
||||
|
||||
@@ -139,6 +142,16 @@ describe("PresentationRoute", () => {
|
||||
expect(within(result).getByText("0 diagnostics", { exact: true })).toBeInTheDocument();
|
||||
}, 15000);
|
||||
|
||||
it("routes Diagnose to a bounded result scrollport on narrow canvases", async () => {
|
||||
window.location.hash = "#scene/prepared-lifecycle/diagnose";
|
||||
const { PresentationRoute } = await import("./PresentationRoute.js");
|
||||
render(<PresentationRoute />);
|
||||
|
||||
const result = await screen.findByRole("region", { name: "draft validation diagnostic" });
|
||||
expect(result).toHaveAttribute("data-scrollport", "bounded-result");
|
||||
expect(result).toHaveAttribute("data-scroll-bound", "viewport-relative");
|
||||
}, 15000);
|
||||
|
||||
it("exposes an application-owned readiness signal for rehearsal capture", async () => {
|
||||
window.location.hash = "#scene/thesis/title";
|
||||
const { PresentationRoute } = await import("./PresentationRoute.js");
|
||||
|
||||
@@ -31,7 +31,7 @@ describe("AuthoringConversation", () => {
|
||||
|
||||
const log = screen.getByRole("log", { name: "prepared authoring conversation" });
|
||||
expect(log).toHaveAttribute("data-surface", "dock");
|
||||
expect(screen.getByRole("button", { name: /validate.*2 tool calls/i }))
|
||||
expect(screen.getByRole("button", { name: /validate.*3 tool calls/i }))
|
||||
.toHaveAttribute("aria-expanded", "true");
|
||||
expect(screen.getByRole("button", { name: /draft.*3 tool calls/i }))
|
||||
.toHaveAttribute("aria-expanded", "false");
|
||||
|
||||
@@ -60,6 +60,9 @@ describe("AuthoringPhaseVisual", () => {
|
||||
expect(within(result).getByText(/missing edges for outcomes.*ok/i)).toBeInTheDocument();
|
||||
expect(within(result).getByText(/cannot prove where execution goes next/i)).toBeInTheDocument();
|
||||
expect(within(result).getByText("Revision 3")).toBeInTheDocument();
|
||||
expect(within(result).getByRole("note", { name: /prepared fault injection/i })).toHaveTextContent(
|
||||
"wf draft remove-route lda_report_workflow --revision 2 --step analyze --outcome ok",
|
||||
);
|
||||
});
|
||||
|
||||
it("renders route repair as a valid revision with compact prior context", () => {
|
||||
|
||||
@@ -74,6 +74,8 @@ const ResultRoot = ({
|
||||
className={`authoring-visual authoring-result authoring-result--${kind}`}
|
||||
aria-label={label}
|
||||
data-authoring-result={kind}
|
||||
data-scrollport="bounded-result"
|
||||
data-scroll-bound="viewport-relative"
|
||||
data-presentation-surface="editorial"
|
||||
data-visual-role="primary"
|
||||
>
|
||||
@@ -152,6 +154,18 @@ const DiagnosticResult = ({ evidence }: { readonly evidence: EvidenceOf<"diagnos
|
||||
/>
|
||||
<p className="authoring-result__explanation">{evidence.diagnostic.explanation}</p>
|
||||
</div>
|
||||
<aside
|
||||
className="authoring-result__fault-injection"
|
||||
role="note"
|
||||
aria-label={evidence.faultInjection.label}
|
||||
>
|
||||
<span>{evidence.faultInjection.label}</span>
|
||||
<code>{evidence.faultInjection.command}</code>
|
||||
<p>
|
||||
Revision {evidence.faultInjection.fromRevision} was valid; this prepared edit intentionally
|
||||
produced invalid revision {evidence.faultInjection.toRevision} for diagnosis.
|
||||
</p>
|
||||
</aside>
|
||||
</ResultRoot>
|
||||
);
|
||||
|
||||
|
||||
+1
-1
@@ -190,7 +190,7 @@ describe("PreparedAuthoringLifecycleScene", () => {
|
||||
|
||||
expect(screen.getByRole("complementary", { name: /prepared authoring assistant/i }))
|
||||
.toHaveAttribute("data-phase", "diagnose");
|
||||
expect(screen.getByRole("button", { name: /validate.*2 tool calls/i }))
|
||||
expect(screen.getByRole("button", { name: /validate.*3 tool calls/i }))
|
||||
.toHaveAttribute("aria-expanded", "true");
|
||||
expect(screen.getByRole("button", { name: /draft.*3 tool calls/i }))
|
||||
.toHaveAttribute("aria-expanded", "false");
|
||||
|
||||
@@ -58,7 +58,7 @@ describe("PresentationAssistantPane", () => {
|
||||
|
||||
expect(screen.getByRole("button", { name: /artifact.*3 tool calls/i }))
|
||||
.toHaveAttribute("aria-expanded", "true");
|
||||
expect(screen.getByRole("button", { name: /validate.*2 tool calls/i }))
|
||||
expect(screen.getByRole("button", { name: /validate.*3 tool calls/i }))
|
||||
.toHaveAttribute("aria-expanded", "false");
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ describe("projectPreparedAuthoringPhase", () => {
|
||||
expect(phase.label).toBe("Discover");
|
||||
expect(phase.commands.length).toBeGreaterThanOrEqual(2);
|
||||
expect(phase.summary).toMatch(/sources|capabilities|schema/i);
|
||||
expect(phase.visual).toMatchObject({ kind: "inventory" });
|
||||
});
|
||||
|
||||
it("projects the draft phase with graph and routes", () => {
|
||||
@@ -20,7 +19,6 @@ describe("projectPreparedAuthoringPhase", () => {
|
||||
expect(phase.label).toBe("Draft");
|
||||
expect(phase.commands.length).toBeGreaterThanOrEqual(2);
|
||||
expect(phase.summary).toMatch(/graph|routes/i);
|
||||
expect(phase.visual).toMatchObject({ kind: "graph" });
|
||||
});
|
||||
|
||||
it("projects the validate phase with diagnosis and repair", () => {
|
||||
@@ -28,7 +26,6 @@ describe("projectPreparedAuthoringPhase", () => {
|
||||
expect(phase.label).toBe("Validate");
|
||||
expect(phase.commands.length).toBeGreaterThanOrEqual(2);
|
||||
expect(phase.summary).toMatch(/diagnos|repair/i);
|
||||
expect(phase.visual).toMatchObject({ kind: "repair" });
|
||||
});
|
||||
|
||||
it("projects the artifact phase with immutable ID and version", () => {
|
||||
@@ -37,7 +34,6 @@ describe("projectPreparedAuthoringPhase", () => {
|
||||
expect(phase.commands.length).toBeGreaterThanOrEqual(2);
|
||||
expect(phase.summary).toMatch(/id/i);
|
||||
expect(phase.summary).toMatch(/version/i);
|
||||
expect(phase.visual).toMatchObject({ kind: "artifact" });
|
||||
});
|
||||
|
||||
it("projects the deployment phase with bindings and validation", () => {
|
||||
@@ -45,7 +41,6 @@ describe("projectPreparedAuthoringPhase", () => {
|
||||
expect(phase.label).toBe("Deployment");
|
||||
expect(phase.commands.length).toBeGreaterThanOrEqual(2);
|
||||
expect(phase.summary).toMatch(/bind|validat/i);
|
||||
expect(phase.visual).toMatchObject({ kind: "bindings" });
|
||||
});
|
||||
|
||||
it("keeps the validation diagnostic and repair command distinct", () => {
|
||||
@@ -53,7 +48,14 @@ describe("projectPreparedAuthoringPhase", () => {
|
||||
const diagnosticCmd = phase.commands.find(
|
||||
(cmd) => cmd.result === "diagnostic" && cmd.detail?.includes("missing_outcome_edge"),
|
||||
);
|
||||
const faultInjectionCmd = phase.commands.find(
|
||||
(cmd) => cmd.title === "workflow.draft_workspaces.remove_route",
|
||||
);
|
||||
const repairCmd = phase.commands.find((cmd) => cmd.command.includes("draft set-route"));
|
||||
expect(faultInjectionCmd?.command).toBe(
|
||||
"wf draft remove-route lda_report_workflow --revision 2 --step analyze --outcome ok",
|
||||
);
|
||||
expect(faultInjectionCmd?.detail).toMatch(/prepared fault injection/i);
|
||||
expect(diagnosticCmd).toBeDefined();
|
||||
expect(repairCmd).toBeDefined();
|
||||
expect(diagnosticCmd).not.toBe(repairCmd);
|
||||
|
||||
@@ -19,7 +19,6 @@ export type AuthoringPhaseProjection = {
|
||||
readonly summary: string;
|
||||
readonly proof: readonly string[];
|
||||
readonly commands: readonly PreparedAuthoringCommand[];
|
||||
readonly visual: AuthoringPhaseVisualModel;
|
||||
};
|
||||
|
||||
export type PreparedLifecycleStepProjection = AuthoringPhaseProjection & {
|
||||
@@ -30,89 +29,6 @@ export type PreparedLifecycleStepProjection = AuthoringPhaseProjection & {
|
||||
readonly evidence: ReviewedAuthoringEvidence;
|
||||
};
|
||||
|
||||
export type AuthoringPhaseVisualModel =
|
||||
| {
|
||||
readonly kind: "inventory";
|
||||
readonly sources: readonly string[];
|
||||
readonly capability: string;
|
||||
readonly contract: string;
|
||||
}
|
||||
| {
|
||||
readonly kind: "graph";
|
||||
readonly nodes: readonly string[];
|
||||
readonly route: string;
|
||||
readonly inputBinding: string;
|
||||
}
|
||||
| {
|
||||
readonly kind: "repair";
|
||||
readonly diagnostic: string;
|
||||
readonly correction: string;
|
||||
readonly status: string;
|
||||
}
|
||||
| {
|
||||
readonly kind: "artifact";
|
||||
readonly artifactId: string;
|
||||
readonly version: number;
|
||||
readonly requiredSources: number;
|
||||
}
|
||||
| {
|
||||
readonly kind: "bindings";
|
||||
readonly deploymentId: string;
|
||||
readonly bindings: readonly { readonly requirement: string; readonly source: string }[];
|
||||
readonly status: string;
|
||||
};
|
||||
|
||||
const visualForPhase = (phase: AuthoringPhaseId): AuthoringPhaseVisualModel => {
|
||||
switch (phase) {
|
||||
case "discover":
|
||||
return {
|
||||
kind: "inventory",
|
||||
sources: ["local.lda_docs", "local.lda_report", "local.issue_board"],
|
||||
capability: "local.lda_report.analyze_documents",
|
||||
contract: "documents → analysis",
|
||||
};
|
||||
case "draft":
|
||||
return {
|
||||
kind: "graph",
|
||||
nodes: ["read_documents", "analyze"],
|
||||
route: "ok → end",
|
||||
inputBinding: "state.documents → documents",
|
||||
};
|
||||
case "validate":
|
||||
{
|
||||
const diagnostic = reviewedAuthoringEvidenceFor("diagnose");
|
||||
const repair = reviewedAuthoringEvidenceFor("repair");
|
||||
if (diagnostic.kind !== "diagnostic" || repair.kind !== "repair") {
|
||||
throw new Error("reviewed validation evidence has an unexpected shape");
|
||||
}
|
||||
return {
|
||||
kind: "repair",
|
||||
diagnostic: `${diagnostic.diagnostic.code} at ${diagnostic.diagnostic.path}: ${diagnostic.diagnostic.message}`,
|
||||
correction: repair.command,
|
||||
status: `Revision ${repair.toRevision}: ${repair.status}`,
|
||||
};
|
||||
}
|
||||
case "artifact":
|
||||
return {
|
||||
kind: "artifact",
|
||||
artifactId: "lda_report_case_study",
|
||||
version: 1,
|
||||
requiredSources: 3,
|
||||
};
|
||||
case "deployment":
|
||||
return {
|
||||
kind: "bindings",
|
||||
deploymentId: "lda_report_case_study.default",
|
||||
bindings: [
|
||||
{ requirement: "local.lda_docs", source: "local.lda_docs" },
|
||||
{ requirement: "local.lda_report", source: "local.lda_report" },
|
||||
{ requirement: "local.issue_board", source: "local.issue_board" },
|
||||
],
|
||||
status: "Deployment valid",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Projects one phase of the prepared authoring recording for presentation.
|
||||
*
|
||||
@@ -135,7 +51,6 @@ export const projectPreparedAuthoringPhase = (
|
||||
.join(" ") || found.label,
|
||||
proof: found.proof,
|
||||
commands: found.commands,
|
||||
visual: visualForPhase(found.phase),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -154,7 +69,7 @@ export const projectPreparedLifecycleStep = (
|
||||
const evidence = reviewedAuthoringEvidenceFor(step);
|
||||
// Diagnose and repair are presentation choreography over one factual
|
||||
// recording phase; they select distinct evidence without duplicating it.
|
||||
const commandIndex = step === "repair" ? 1 : 0;
|
||||
const commandIndex = step === "repair" ? 2 : step === "diagnose" ? 1 : 0;
|
||||
const primaryCommand = phase.commands[commandIndex];
|
||||
if (primaryCommand === undefined) {
|
||||
throw new Error(
|
||||
|
||||
@@ -80,6 +80,7 @@ describe("projectPreparedAuthoring", () => {
|
||||
"workflow.draft_workspaces.create_from_capability",
|
||||
"workflow.draft_workspaces.add_step_from_capability",
|
||||
"workflow.draft_workspaces.get",
|
||||
"workflow.draft_workspaces.remove_route",
|
||||
"workflow.draft_workspaces.validate",
|
||||
"workflow.draft_workspaces.set_route",
|
||||
"workflow.draft_workspaces.compile",
|
||||
@@ -109,6 +110,7 @@ describe("projectPreparedAuthoring", () => {
|
||||
expect(commands.some((command) => command === "wf cap inspect local.lda_report.analyze_documents")).toBe(true);
|
||||
expect(commands.some((command) => command === "wf schema")).toBe(true);
|
||||
expect(commands.some((command) => command.startsWith("wf draft add-step lda_report_workflow"))).toBe(true);
|
||||
expect(commands.some((command) => command === "wf draft remove-route lda_report_workflow --revision 2 --step analyze --outcome ok")).toBe(true);
|
||||
expect(commands.some((command) => command === "wf draft validate lda_report_workflow")).toBe(true);
|
||||
expect(commands.some((command) => command === "wf draft set-route lda_report_workflow --revision 3 --step analyze --outcome ok --to __end__")).toBe(true);
|
||||
expect(commands.some((command) => command === "wf draft compile lda_report_workflow")).toBe(true);
|
||||
|
||||
@@ -160,12 +160,22 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
||||
beatId: "validate",
|
||||
label: "Validate",
|
||||
commands: [
|
||||
{
|
||||
title: "workflow.draft_workspaces.remove_route",
|
||||
command:
|
||||
"wf draft remove-route lda_report_workflow --revision 2 --step analyze --outcome ok",
|
||||
summary: "Prepare a validation fault injection by removing the terminal route",
|
||||
result: "success",
|
||||
detail:
|
||||
"Prepared fault injection: intentionally remove analyze.ok from valid revision 2; this produces revision 3 invalid with missing_outcome_edge.",
|
||||
},
|
||||
{
|
||||
title: "workflow.draft_workspaces.validate",
|
||||
command: "wf draft validate lda_report_workflow",
|
||||
summary: "Validate the workflow draft",
|
||||
result: "diagnostic",
|
||||
detail: "missing_outcome_edge at nodes[analyze]: reachable node is missing edges for outcomes ['ok']",
|
||||
detail:
|
||||
"Revision 3 is invalid: missing_outcome_edge at nodes[analyze]: reachable node is missing edges for outcomes ['ok']",
|
||||
},
|
||||
{
|
||||
title: "workflow.draft_workspaces.set_route",
|
||||
@@ -182,7 +192,7 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
text: "Running diagnosis now. I'll bind the source and repair any issues found in the draft graph.",
|
||||
text: "Revision 2 is valid. For this prepared validation path, I'll intentionally remove analyze.ok, validate the resulting revision 3, and then repair it.",
|
||||
},
|
||||
],
|
||||
proof: [
|
||||
|
||||
@@ -34,6 +34,12 @@ describe("reviewed authoring evidence", () => {
|
||||
path: "nodes[analyze]",
|
||||
message: "reachable node is missing edges for outcomes ['ok']",
|
||||
},
|
||||
faultInjection: {
|
||||
command: "wf draft remove-route lda_report_workflow --revision 2 --step analyze --outcome ok",
|
||||
fromRevision: 2,
|
||||
toRevision: 3,
|
||||
label: "prepared fault injection",
|
||||
},
|
||||
});
|
||||
|
||||
expect(reviewedAuthoringEvidenceFor("repair")).toMatchObject({
|
||||
|
||||
@@ -33,6 +33,12 @@ export type ReviewedAuthoringEvidence =
|
||||
readonly message: string;
|
||||
readonly explanation: string;
|
||||
};
|
||||
readonly faultInjection: {
|
||||
readonly command: string;
|
||||
readonly fromRevision: 2;
|
||||
readonly toRevision: 3;
|
||||
readonly label: "prepared fault injection";
|
||||
};
|
||||
}
|
||||
| {
|
||||
readonly kind: "repair";
|
||||
@@ -107,6 +113,13 @@ const reviewedAuthoringEvidence: Readonly<
|
||||
message: "reachable node is missing edges for outcomes ['ok']",
|
||||
explanation: "The workflow cannot prove where execution goes next.",
|
||||
},
|
||||
faultInjection: {
|
||||
command:
|
||||
"wf draft remove-route lda_report_workflow --revision 2 --step analyze --outcome ok",
|
||||
fromRevision: 2,
|
||||
toRevision: 3,
|
||||
label: "prepared fault injection",
|
||||
},
|
||||
},
|
||||
repair: {
|
||||
kind: "repair",
|
||||
|
||||
@@ -183,6 +183,17 @@ describe("presentation.css", () => {
|
||||
expect(narrowRows).toContain("grid-template-columns: minmax(0, 1fr);");
|
||||
});
|
||||
|
||||
it("bounds narrow lifecycle results to a viewport-relative scrollport", () => {
|
||||
const narrowContainer = cssBlock(css, "@container presentation-canvas (max-width: 600px)") ?? "";
|
||||
const narrowResult = cssBlocks(narrowContainer, '.prepared-lifecycle-scene[data-presentation-surface="editorial"] .authoring-result')
|
||||
.find((body) => body.includes("max-height: min(34rem, 56vh);"));
|
||||
|
||||
expect(narrowResult).toContain("height: min(34rem, 56vh);");
|
||||
expect(narrowResult).toContain("max-height: min(34rem, 56vh);");
|
||||
expect(narrowResult).toContain("overflow: auto;");
|
||||
expect(narrowResult).not.toContain("max-height: 100%;");
|
||||
});
|
||||
|
||||
it("gives the prepared lifecycle rail and operation frame the primary hierarchy", () => {
|
||||
const frameRules = cssBlocks(css, '.prepared-lifecycle-scene[data-presentation-surface="editorial"] .prepared-lifecycle-scene__frame');
|
||||
const editorialFrame = frameRules.find((body) => body.includes("background: var(--authoring-paper);"));
|
||||
@@ -263,9 +274,10 @@ describe("presentation.css", () => {
|
||||
expect(narrowAssistant).toContain("max-height: min(24rem, 60vh);");
|
||||
});
|
||||
|
||||
it("does not cap lifecycle evidence on wide presentation canvases", () => {
|
||||
it("does not add a wide-canvas lifecycle evidence cap", () => {
|
||||
expect(css).not.toContain("@container presentation-canvas (min-width: 1500px)");
|
||||
expect(css).not.toContain("max-height: min(34rem, 56vh);");
|
||||
const narrowContainer = cssBlock(css, "@container presentation-canvas (max-width: 600px)") ?? "";
|
||||
expect(narrowContainer).toContain("max-height: min(34rem, 56vh);");
|
||||
});
|
||||
|
||||
it("bounds prepared conversation scrolling and recenters the agent handoff at compact stage widths", () => {
|
||||
|
||||
@@ -4007,8 +4007,8 @@
|
||||
}
|
||||
|
||||
.prepared-lifecycle-scene[data-presentation-surface="editorial"] .authoring-result {
|
||||
height: auto;
|
||||
max-height: 100%;
|
||||
height: min(34rem, 56vh);
|
||||
max-height: min(34rem, 56vh);
|
||||
overflow: auto;
|
||||
padding-inline: 0;
|
||||
}
|
||||
@@ -4229,6 +4229,30 @@
|
||||
border-inline-start: 3px solid var(--accent-amber);
|
||||
}
|
||||
|
||||
.authoring-result__fault-injection {
|
||||
display: grid;
|
||||
gap: 0.35rem;
|
||||
min-width: 0;
|
||||
padding: 0.75rem 0.9rem;
|
||||
border: 1px dashed var(--authoring-rule, var(--stage-line));
|
||||
color: var(--authoring-muted, var(--text-secondary));
|
||||
}
|
||||
|
||||
.authoring-result__fault-injection span {
|
||||
font: 700 0.64rem/1.1 var(--font-evidence);
|
||||
letter-spacing: 0.07em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.authoring-result__fault-injection code {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.authoring-result__fault-injection p {
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.authoring-result__prior {
|
||||
padding-bottom: 0.85rem;
|
||||
border-bottom: 1px solid var(--authoring-rule, var(--stage-line));
|
||||
|
||||
Reference in New Issue
Block a user