From 72fa15a509fcdd4779ad58f19d0c03d06b350747 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Mon, 26 Oct 2026 14:04:39 +0800 Subject: [PATCH] refactor(snapshots): derive workflow entries from canonical schema --- src/domain/analysisSnapshot.test.ts | 43 +++++++++++++++++++++++++++++ src/domain/analysisSnapshot.ts | 14 ++-------- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/domain/analysisSnapshot.test.ts b/src/domain/analysisSnapshot.test.ts index e72c0740a3..acaa36f435 100644 --- a/src/domain/analysisSnapshot.test.ts +++ b/src/domain/analysisSnapshot.test.ts @@ -73,6 +73,49 @@ const snapshotWithHistoricalEvidence = () => { }; }; +describe("analysis snapshot entry admission", () => { + it("preserves provider entries without profiles and requires profiles on workflow entries", () => { + const { snapshot } = snapshotWithHistoricalEvidence(); + const entry = snapshot.entries[0]; + if (entry === undefined) throw new Error("Missing fixture query"); + const providerSchema = analysisSnapshotSchema.shape.entries.element; + const workflowSchema = + analysisSnapshotSchema.shape.workflow_entries.element; + expect(providerSchema.parse(entry)).toEqual(entry); + expect(workflowSchema.safeParse(entry).success).toBe(false); + const workflow = { + ...entry, + execution: { + ...entry.execution, + analysis_profile: snapshot.binding.analysis_profile, + }, + }; + expect(workflowSchema.parse(workflow)).toEqual(workflow); + for (const schema of [providerSchema, workflowSchema]) { + expect( + schema.safeParse({ + ...workflow, + execution: { ...workflow.execution, provider: undefined }, + }).success, + ).toBe(false); + } + expect( + providerSchema.parse({ + ...workflow, + unknown_entry: true, + execution: { ...workflow.execution, unknown_execution: true }, + }), + ).toEqual(entry); + expect( + workflowSchema.parse({ + ...workflow, + unknown_entry: true, + execution: { ...workflow.execution, unknown_execution: true }, + }), + ).toEqual(workflow); + }); +}); + describe("analysis snapshot target identity", () => { it.each(RAW_ONLY_ARCHITECTURES)( "keeps %s confined to executable raw snapshots", diff --git a/src/domain/analysisSnapshot.ts b/src/domain/analysisSnapshot.ts index 5dbfffc3df..2b998ccb9a 100644 --- a/src/domain/analysisSnapshot.ts +++ b/src/domain/analysisSnapshot.ts @@ -170,19 +170,9 @@ const entrySchema = z.object({ subject: subjectSchema.nullable(), }), }); -const workflowEntrySchema = z.object({ - query_id: prefixedDigestSchema("query"), - operation: z.string().min(1), - parameters: jsonObjectSchema, - execution: z.object({ - result: jsonValueSchema, - raw_result: jsonValueSchema.nullable(), - provider: committedProviderSchema, +const workflowEntrySchema = entrySchema.extend({ + execution: entrySchema.shape.execution.extend({ analysis_profile: analysisProfileSchema, - limitations: z.array(z.string()), - relationship_coverage: relationshipCoverageSchema.nullable(), - locations: z.array(evidenceLocationSchema), - subject: subjectSchema.nullable(), }), });