feat: project demo lifecycle facts
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { loadCanonicalDemoRecording } from "../demo/timeline/replay.js";
|
||||
import { initialDemoTimelineState } from "../demo/timeline/reducer.js";
|
||||
import type { DemoTimelineController } from "../demo/useDemoTimeline.js";
|
||||
import { projectDemoLifecycleFacts } from "./demo-lifecycle-facts.js";
|
||||
|
||||
const controller = (): DemoTimelineController => {
|
||||
const recording = loadCanonicalDemoRecording();
|
||||
return {
|
||||
state: {
|
||||
...initialDemoTimelineState,
|
||||
mode: "replay",
|
||||
phase: "paused",
|
||||
events: recording.events,
|
||||
appliedCount: recording.events.length,
|
||||
autoplay: false,
|
||||
},
|
||||
inFlight: false,
|
||||
interruptPayload: null,
|
||||
output: null,
|
||||
trace: null,
|
||||
missingDeploymentMessage: null,
|
||||
recordingId: recording.recordingId,
|
||||
canStart: true,
|
||||
setMode: vi.fn(),
|
||||
start: vi.fn(),
|
||||
pause: vi.fn(),
|
||||
play: vi.fn(),
|
||||
next: vi.fn(async () => {}),
|
||||
submitSelectedIssues: vi.fn(async () => {}),
|
||||
cancelReview: vi.fn(async () => {}),
|
||||
restart: vi.fn(),
|
||||
primeReplayToStage: vi.fn(),
|
||||
};
|
||||
};
|
||||
|
||||
describe("projectDemoLifecycleFacts", () => {
|
||||
it("projects prepared draft context without pretending it was runtime evidence", () => {
|
||||
const facts = projectDemoLifecycleFacts(controller());
|
||||
expect(facts.draft.label).toBe("lda report workflow");
|
||||
expect(facts.draft.source).toContain("examples/lda_report_workflow");
|
||||
expect(facts.draft.status).toBe("prepared context");
|
||||
});
|
||||
|
||||
it("projects artifact and deployment facts from deployment inspect evidence", () => {
|
||||
const facts = projectDemoLifecycleFacts(controller());
|
||||
expect(facts.artifact).toEqual({ id: "lda_report_case_study", version: 1 });
|
||||
expect(facts.deployment.id).toBe("lda_report_case_study.default");
|
||||
expect(facts.deployment.driftPolicy).toBe("block");
|
||||
expect(facts.deployment.bindings).toContainEqual(["local.lda_docs", "local.lda_docs"]);
|
||||
});
|
||||
|
||||
it("projects run readiness from the run start event", () => {
|
||||
const facts = projectDemoLifecycleFacts(controller());
|
||||
expect(facts.run.id).toBe("run_recorded_lda_report");
|
||||
expect(facts.run.status).toBe("interrupted");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
import type { DemoTimelineController } from "../demo/useDemoTimeline.js";
|
||||
|
||||
export type DemoLifecycleFacts = {
|
||||
readonly draft: {
|
||||
readonly label: string;
|
||||
readonly source: string;
|
||||
readonly status: string;
|
||||
};
|
||||
readonly artifact: {
|
||||
readonly id: string;
|
||||
readonly version: number | null;
|
||||
};
|
||||
readonly deployment: {
|
||||
readonly id: string;
|
||||
readonly driftPolicy: string;
|
||||
readonly bindings: ReadonlyArray<readonly [string, string]>;
|
||||
};
|
||||
readonly run: {
|
||||
readonly id: string | null;
|
||||
readonly status: string;
|
||||
};
|
||||
};
|
||||
|
||||
const deploymentInspect = (demo: DemoTimelineController) =>
|
||||
demo.state.events.find((event) => event.stage === "deployment_check");
|
||||
|
||||
const runStart = (demo: DemoTimelineController) =>
|
||||
demo.state.events.find((event) => event.stage === "run_start");
|
||||
|
||||
const readBindings = (value: unknown): ReadonlyArray<readonly [string, string]> => {
|
||||
if (!Array.isArray(value)) return [];
|
||||
return value.flatMap((entry) => {
|
||||
if (!Array.isArray(entry) || entry.length !== 2) return [];
|
||||
const [from, to] = entry;
|
||||
return typeof from === "string" && typeof to === "string" ? [[from, to] as const] : [];
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Presentation-only lifecycle facts. Draft context is prepared example context;
|
||||
* artifact/deployment/run facts come from replay evidence when available.
|
||||
*/
|
||||
export const projectDemoLifecycleFacts = (demo: DemoTimelineController): DemoLifecycleFacts => {
|
||||
const deployment = deploymentInspect(demo);
|
||||
const deploymentInterpreted = deployment?.interpreted as
|
||||
| {
|
||||
id?: string;
|
||||
artifactId?: string;
|
||||
artifactVersion?: number;
|
||||
driftPolicy?: string;
|
||||
bindings?: unknown;
|
||||
}
|
||||
| undefined;
|
||||
const run = runStart(demo);
|
||||
const runInterpreted = run?.interpreted as
|
||||
| { runId?: string; status?: string }
|
||||
| undefined;
|
||||
|
||||
return {
|
||||
draft: {
|
||||
label: "lda report workflow",
|
||||
source: "examples/lda_report_workflow",
|
||||
status: "prepared context",
|
||||
},
|
||||
artifact: {
|
||||
id: deploymentInterpreted?.artifactId ?? "unavailable",
|
||||
version: typeof deploymentInterpreted?.artifactVersion === "number"
|
||||
? deploymentInterpreted.artifactVersion
|
||||
: null,
|
||||
},
|
||||
deployment: {
|
||||
id: deploymentInterpreted?.id ?? "unavailable",
|
||||
driftPolicy: deploymentInterpreted?.driftPolicy ?? "unavailable",
|
||||
bindings: readBindings(deploymentInterpreted?.bindings),
|
||||
},
|
||||
run: {
|
||||
id: runInterpreted?.runId ?? run?.resultingIds.runId ?? null,
|
||||
status: runInterpreted?.status ?? "not started",
|
||||
},
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user