fix: use factual prepared validation evidence
This commit is contained in:
@@ -15,7 +15,7 @@ export type PreparedAuthoringToolName =
|
|||||||
| "workflow.draft_workspaces.add_step_from_capability"
|
| "workflow.draft_workspaces.add_step_from_capability"
|
||||||
| "workflow.draft_workspaces.get"
|
| "workflow.draft_workspaces.get"
|
||||||
| "workflow.draft_workspaces.validate"
|
| "workflow.draft_workspaces.validate"
|
||||||
| "workflow.draft_workspaces.set_step_output_map"
|
| "workflow.draft_workspaces.set_route"
|
||||||
| "workflow.draft_workspaces.compile"
|
| "workflow.draft_workspaces.compile"
|
||||||
| "workflow.draft_workspaces.create_artifact"
|
| "workflow.draft_workspaces.create_artifact"
|
||||||
| "workflow.artifacts.inspect"
|
| "workflow.artifacts.inspect"
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ describe("projectPreparedAuthoringPhase", () => {
|
|||||||
it("keeps the validation diagnostic and repair command distinct", () => {
|
it("keeps the validation diagnostic and repair command distinct", () => {
|
||||||
const phase = projectPreparedAuthoringPhase("validate");
|
const phase = projectPreparedAuthoringPhase("validate");
|
||||||
const diagnosticCmd = phase.commands.find(
|
const diagnosticCmd = phase.commands.find(
|
||||||
(cmd) => cmd.result === "diagnostic" && cmd.detail?.includes("no state projection"),
|
(cmd) => cmd.result === "diagnostic" && cmd.detail?.includes("missing_outcome_edge"),
|
||||||
);
|
);
|
||||||
const repairCmd = phase.commands.find((cmd) => cmd.command.includes("draft set-output"));
|
const repairCmd = phase.commands.find((cmd) => cmd.command.includes("draft set-route"));
|
||||||
expect(diagnosticCmd).toBeDefined();
|
expect(diagnosticCmd).toBeDefined();
|
||||||
expect(repairCmd).toBeDefined();
|
expect(repairCmd).toBeDefined();
|
||||||
expect(diagnosticCmd).not.toBe(repairCmd);
|
expect(diagnosticCmd).not.toBe(repairCmd);
|
||||||
@@ -78,7 +78,11 @@ describe("projectPreparedAuthoringPhase", () => {
|
|||||||
expect(diagnose.focus).toBe("diagnose");
|
expect(diagnose.focus).toBe("diagnose");
|
||||||
expect(repair.focus).toBe("repair");
|
expect(repair.focus).toBe("repair");
|
||||||
expect(diagnose.primaryCommand.title).toBe("workflow.draft_workspaces.validate");
|
expect(diagnose.primaryCommand.title).toBe("workflow.draft_workspaces.validate");
|
||||||
expect(repair.primaryCommand.title).toBe("workflow.draft_workspaces.set_step_output_map");
|
expect(diagnose.primaryCommand.detail).toContain("missing_outcome_edge");
|
||||||
|
expect(repair.primaryCommand.title).toBe("workflow.draft_workspaces.set_route");
|
||||||
|
expect(repair.primaryCommand.command).toContain("--revision 3 --step analyze --outcome ok --to __end__");
|
||||||
|
expect(diagnose.evidence.kind).toBe("diagnostic");
|
||||||
|
expect(repair.evidence.kind).toBe("repair");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("projects six presentation steps from five recorded phases", () => {
|
it("projects six presentation steps from five recorded phases", () => {
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { projectPreparedAuthoring, type AuthoringPhaseId, type PreparedAuthoringCommand } from "./authoring-recording.js";
|
import { projectPreparedAuthoring, type AuthoringPhaseId, type PreparedAuthoringCommand } from "./authoring-recording.js";
|
||||||
|
import {
|
||||||
|
reviewedAuthoringEvidenceFor,
|
||||||
|
type ReviewedAuthoringEvidence,
|
||||||
|
} from "./reviewed-authoring-evidence.js";
|
||||||
|
|
||||||
export type PreparedLifecycleStepId =
|
export type PreparedLifecycleStepId =
|
||||||
| "discover"
|
| "discover"
|
||||||
@@ -23,6 +27,7 @@ export type PreparedLifecycleStepProjection = AuthoringPhaseProjection & {
|
|||||||
readonly recordingPhase: AuthoringPhaseId;
|
readonly recordingPhase: AuthoringPhaseId;
|
||||||
readonly focus: "full" | "diagnose" | "repair";
|
readonly focus: "full" | "diagnose" | "repair";
|
||||||
readonly primaryCommand: PreparedAuthoringCommand;
|
readonly primaryCommand: PreparedAuthoringCommand;
|
||||||
|
readonly evidence: ReviewedAuthoringEvidence;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AuthoringPhaseVisualModel =
|
export type AuthoringPhaseVisualModel =
|
||||||
@@ -74,12 +79,19 @@ const visualForPhase = (phase: AuthoringPhaseId): AuthoringPhaseVisualModel => {
|
|||||||
inputBinding: "state.documents → documents",
|
inputBinding: "state.documents → documents",
|
||||||
};
|
};
|
||||||
case "validate":
|
case "validate":
|
||||||
return {
|
{
|
||||||
kind: "repair",
|
const diagnostic = reviewedAuthoringEvidenceFor("diagnose");
|
||||||
diagnostic: "analysis has no state projection",
|
const repair = reviewedAuthoringEvidenceFor("repair");
|
||||||
correction: "analysis → state.analysis",
|
if (diagnostic.kind !== "diagnostic" || repair.kind !== "repair") {
|
||||||
status: "Valid draft",
|
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":
|
case "artifact":
|
||||||
return {
|
return {
|
||||||
kind: "artifact",
|
kind: "artifact",
|
||||||
@@ -139,6 +151,7 @@ export const projectPreparedLifecycleStep = (
|
|||||||
): PreparedLifecycleStepProjection => {
|
): PreparedLifecycleStepProjection => {
|
||||||
const recordingPhase = recordingPhaseForStep(step);
|
const recordingPhase = recordingPhaseForStep(step);
|
||||||
const phase = projectPreparedAuthoringPhase(recordingPhase);
|
const phase = projectPreparedAuthoringPhase(recordingPhase);
|
||||||
|
const evidence = reviewedAuthoringEvidenceFor(step);
|
||||||
// Diagnose and repair are presentation choreography over one factual
|
// Diagnose and repair are presentation choreography over one factual
|
||||||
// recording phase; they select distinct evidence without duplicating it.
|
// recording phase; they select distinct evidence without duplicating it.
|
||||||
const commandIndex = step === "repair" ? 1 : 0;
|
const commandIndex = step === "repair" ? 1 : 0;
|
||||||
@@ -155,5 +168,6 @@ export const projectPreparedLifecycleStep = (
|
|||||||
recordingPhase,
|
recordingPhase,
|
||||||
focus: step === "diagnose" || step === "repair" ? step : "full",
|
focus: step === "diagnose" || step === "repair" ? step : "full",
|
||||||
primaryCommand,
|
primaryCommand,
|
||||||
|
evidence,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ describe("projectPreparedAuthoring", () => {
|
|||||||
"workflow.draft_workspaces.add_step_from_capability",
|
"workflow.draft_workspaces.add_step_from_capability",
|
||||||
"workflow.draft_workspaces.get",
|
"workflow.draft_workspaces.get",
|
||||||
"workflow.draft_workspaces.validate",
|
"workflow.draft_workspaces.validate",
|
||||||
"workflow.draft_workspaces.set_step_output_map",
|
"workflow.draft_workspaces.set_route",
|
||||||
"workflow.draft_workspaces.compile",
|
"workflow.draft_workspaces.compile",
|
||||||
"workflow.draft_workspaces.create_artifact",
|
"workflow.draft_workspaces.create_artifact",
|
||||||
"workflow.artifacts.inspect",
|
"workflow.artifacts.inspect",
|
||||||
@@ -110,6 +110,7 @@ describe("projectPreparedAuthoring", () => {
|
|||||||
expect(commands.some((command) => command === "wf schema")).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.startsWith("wf draft add-step lda_report_workflow"))).toBe(true);
|
||||||
expect(commands.some((command) => command === "wf draft validate lda_report_workflow")).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);
|
expect(commands.some((command) => command === "wf draft compile lda_report_workflow")).toBe(true);
|
||||||
expect(commands.some((command) => command === "wf artifact inspect lda_report_case_study --version 1")).toBe(true);
|
expect(commands.some((command) => command === "wf artifact inspect lda_report_case_study --version 1")).toBe(true);
|
||||||
expect(commands.some((command) => command.startsWith("wf deploy save lda_report_case_study.default"))).toBe(true);
|
expect(commands.some((command) => command.startsWith("wf deploy save lda_report_case_study.default"))).toBe(true);
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
command: "wf source list",
|
command: "wf source list",
|
||||||
summary: "List available capability sources",
|
summary: "List available capability sources",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "6 sources: local.lda_docs, local.lda_report, local.issue_board, and platform helpers.",
|
detail: "Inventory: 6 total sources; configured local sources: local.lda_docs, local.lda_report, local.issue_board; platform helpers are also available.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "workflow.capabilities.list",
|
title: "workflow.capabilities.list",
|
||||||
@@ -165,14 +165,14 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
command: "wf draft validate lda_report_workflow",
|
command: "wf draft validate lda_report_workflow",
|
||||||
summary: "Validate the workflow draft",
|
summary: "Validate the workflow draft",
|
||||||
result: "diagnostic",
|
result: "diagnostic",
|
||||||
detail: "Diagnostic: analyze output 'analysis' has no state projection.",
|
detail: "missing_outcome_edge at nodes[analyze]: reachable node is missing edges for outcomes ['ok']",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "workflow.draft_workspaces.set_step_output_map",
|
title: "workflow.draft_workspaces.set_route",
|
||||||
command: "wf draft set-output lda_report_workflow --revision 2 --step analyze --map analysis=state.analysis",
|
command: "wf draft set-route lda_report_workflow --revision 3 --step analyze --outcome ok --to __end__",
|
||||||
summary: "Repair the missing output binding",
|
summary: "Restore the missing terminal route",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "Added analysis -> state.analysis. A follow-up draft validate reports a valid draft.",
|
detail: "Revision 4 validates with status valid and diagnostics [].",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
conversation: [
|
conversation: [
|
||||||
@@ -186,9 +186,9 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
proof: [
|
proof: [
|
||||||
"analysis → state.analysis",
|
"missing_outcome_edge",
|
||||||
"diagnostic resolved",
|
"analyze.ok -> __end__",
|
||||||
"validated draft",
|
"revision 4: valid",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -91,8 +91,12 @@ describe("defense storyboard catalog", () => {
|
|||||||
it("defines the lifecycle story beats before run evidence", () => {
|
it("defines the lifecycle story beats before run evidence", () => {
|
||||||
expect(findBeat("prepared-lifecycle", "discover")?.caption).toMatch(/sources|capabilities|schemas/i);
|
expect(findBeat("prepared-lifecycle", "discover")?.caption).toMatch(/sources|capabilities|schemas/i);
|
||||||
expect(findBeat("prepared-lifecycle", "draft")?.caption).toMatch(/draft/i);
|
expect(findBeat("prepared-lifecycle", "draft")?.caption).toMatch(/draft/i);
|
||||||
expect(findBeat("prepared-lifecycle", "diagnose")?.caption).toMatch(/diagnostic|missing-output/i);
|
expect(findBeat("prepared-lifecycle", "diagnose")?.caption).toBe(
|
||||||
expect(findBeat("prepared-lifecycle", "repair")?.caption).toMatch(/repair|valid Draft/i);
|
"Validation returns a structured diagnostic because analyze has no route for its ok outcome.",
|
||||||
|
);
|
||||||
|
expect(findBeat("prepared-lifecycle", "repair")?.caption).toBe(
|
||||||
|
"One route edit sends analyze.ok to __end__; the follow-up validation is valid.",
|
||||||
|
);
|
||||||
expect(findBeat("prepared-lifecycle", "artifact")?.caption).toMatch(/compile|artifact/i);
|
expect(findBeat("prepared-lifecycle", "artifact")?.caption).toMatch(/compile|artifact/i);
|
||||||
expect(findBeat("prepared-lifecycle", "deployment")?.caption).toMatch(/deploy|bindings/i);
|
expect(findBeat("prepared-lifecycle", "deployment")?.caption).toMatch(/deploy|bindings/i);
|
||||||
});
|
});
|
||||||
@@ -102,8 +106,8 @@ describe("defense storyboard catalog", () => {
|
|||||||
expect(findBeat("lifecycle", "artifact")?.caption).toMatch(/^Artifact is an immutable workflow definition\.$/);
|
expect(findBeat("lifecycle", "artifact")?.caption).toMatch(/^Artifact is an immutable workflow definition\.$/);
|
||||||
expect(findBeat("lifecycle", "deployment")?.caption).toMatch(/^Deployment binds an artifact version/);
|
expect(findBeat("lifecycle", "deployment")?.caption).toMatch(/^Deployment binds an artifact version/);
|
||||||
expect(findBeat("lifecycle", "run")?.caption).toMatch(/^Run records one execution/);
|
expect(findBeat("lifecycle", "run")?.caption).toMatch(/^Run records one execution/);
|
||||||
expect(findBeat("prepared-lifecycle", "diagnose")?.caption).toMatch(/diagnostic|missing-output/i);
|
expect(findBeat("prepared-lifecycle", "diagnose")?.caption).toContain("no route for its ok outcome");
|
||||||
expect(findBeat("prepared-lifecycle", "repair")?.caption).toMatch(/repair|valid Draft/i);
|
expect(findBeat("prepared-lifecycle", "repair")?.caption).toContain("analyze.ok to __end__");
|
||||||
expect(findBeat("prepared-lifecycle", "deployment")?.caption).toMatch(/ready|does not run|Scene 9/i);
|
expect(findBeat("prepared-lifecycle", "deployment")?.caption).toMatch(/ready|does not run|Scene 9/i);
|
||||||
expect(findBeat("prepared-lifecycle", "deployment")?.caption).toMatch(/three-node|implementation extension/i);
|
expect(findBeat("prepared-lifecycle", "deployment")?.caption).toMatch(/three-node|implementation extension/i);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -162,13 +162,13 @@ export const mainScenes = defineScenes([
|
|||||||
sceneBeat(
|
sceneBeat(
|
||||||
"diagnose",
|
"diagnose",
|
||||||
"Diagnose invalid draft",
|
"Diagnose invalid draft",
|
||||||
"Validation returns a structured missing-output diagnostic before artifact creation.",
|
"Validation returns a structured diagnostic because analyze has no route for its ok outcome.",
|
||||||
{ chatMode: "hidden", chatTheme: "light" },
|
{ chatMode: "hidden", chatTheme: "light" },
|
||||||
),
|
),
|
||||||
sceneBeat(
|
sceneBeat(
|
||||||
"repair",
|
"repair",
|
||||||
"Apply targeted repair",
|
"Apply targeted repair",
|
||||||
"A focused output-map edit resolves the diagnostic and produces a valid Draft.",
|
"One route edit sends analyze.ok to __end__; the follow-up validation is valid.",
|
||||||
{ chatMode: "hidden", chatTheme: "light" },
|
{ chatMode: "hidden", chatTheme: "light" },
|
||||||
),
|
),
|
||||||
sceneBeat("artifact", "Compile artifact", "Save the validated plan as an immutable artifact.", { chatMode: "hidden", chatTheme: "light" }),
|
sceneBeat("artifact", "Compile artifact", "Save the validated plan as an immutable artifact.", { chatMode: "hidden", chatTheme: "light" }),
|
||||||
|
|||||||
Reference in New Issue
Block a user