diff --git a/src/contracts/artifactComparisonExample.ts b/src/contracts/artifactComparisonExample.ts index 1cf1ab87d7..4b9550b1c1 100644 --- a/src/contracts/artifactComparisonExample.ts +++ b/src/contracts/artifactComparisonExample.ts @@ -73,6 +73,7 @@ const inventory = (digit: string) => { occurrences, edges, provenance: [], + integrity_contradictions: integrityContradictions, coverage: { scope: "root", status: "complete" }, limitations: [], }); diff --git a/src/domain/artifactGraph.test.ts b/src/domain/artifactGraph.test.ts index 2840223e5c..3ab8e54646 100644 --- a/src/domain/artifactGraph.test.ts +++ b/src/domain/artifactGraph.test.ts @@ -71,7 +71,7 @@ describe("artifact graph path and provenance fields", () => { expect(parsed.provenance[0]?.arguments[0]).toBe(arguments_[0]); }); - it("requires current scoped coverage and rejects the obsolete status alias", () => { + it("requires current coverage and integrity facts and rejects the obsolete status alias", () => { const inventory = { manifest: { manifest_id: `agm_${"b".repeat(64)}`, @@ -94,6 +94,22 @@ describe("artifact graph path and provenance fields", () => { expect(artifactInventoryResultSchema.safeParse(inventory).success).toBe( false, ); + const { integrity_contradictions: _facts, ...withoutIntegrityFacts } = + inventory; + const currentWithoutIntegrityFacts = { + ...withoutIntegrityFacts, + coverage: { scope: "root", status: "complete" }, + }; + expect( + artifactInventoryResultSchema.safeParse(currentWithoutIntegrityFacts) + .success, + ).toBe(false); + expect( + artifactInventoryResultSchema.safeParse({ + ...currentWithoutIntegrityFacts, + integrity_contradictions: [], + }).success, + ).toBe(true); expect( artifactInventoryResultSchema.safeParse({ ...inventory, diff --git a/src/domain/artifactGraph.ts b/src/domain/artifactGraph.ts index ef67af6311..da27ad1f72 100644 --- a/src/domain/artifactGraph.ts +++ b/src/domain/artifactGraph.ts @@ -203,7 +203,7 @@ export const artifactInventoryResultSchema = z.strictObject({ occurrences: z.array(artifactOccurrenceSchema), edges: z.array(artifactEdgeSchema), provenance: z.array(artifactCommandSchema), - integrity_contradictions: z.array(integrityContradictionSchema).default([]), + integrity_contradictions: z.array(integrityContradictionSchema), coverage: artifactInventoryCoverageSchema, limitations: z.array(z.string()), }); diff --git a/src/domain/browserScenarioCapture.test.ts b/src/domain/browserScenarioCapture.test.ts index 8c84e978be..fa1dcb743b 100644 --- a/src/domain/browserScenarioCapture.test.ts +++ b/src/domain/browserScenarioCapture.test.ts @@ -292,6 +292,7 @@ it("validates reported event limits and omission accounting", () => { }, event_families: ["network"], limits: { + ...DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS, max_total_event_allocation_bytes: 32 * 1024 * 1024, }, }, @@ -350,6 +351,22 @@ it("validates reported event limits and omission accounting", () => { }, }).success, ).toBe(false); + for (const limits of [ + {}, + { max_events: DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_events }, + ]) + expect( + browserScenarioCaptureSchema.safeParse({ + ...capture.data, + scenario: { ...capture.data.scenario, limits }, + }).success, + ).toBe(false); + expect( + browserScenarioCaptureSchema.safeParse({ + ...capture.data, + scenario: { ...capture.data.scenario, limits: undefined }, + }).success, + ).toBe(false); }); it("derives equality eligibility from exact completeness state", () => { diff --git a/src/domain/browserScenarioCapture.ts b/src/domain/browserScenarioCapture.ts index 088817c5f8..4c591342cb 100644 --- a/src/domain/browserScenarioCapture.ts +++ b/src/domain/browserScenarioCapture.ts @@ -1,6 +1,6 @@ import { z } from "zod"; import { browserNetworkContentSelectionValuesSchema } from "./browserNetworkEvidence.js"; -import { browserScenarioCaptureLimitsSchema } from "./browserScenarioCaptureLimits.js"; +import { browserScenarioCaptureLimitsValuesSchema } from "./browserScenarioCaptureLimits.js"; import { browserScenarioCompletenessSchema, @@ -26,7 +26,7 @@ export const browserScenarioCaptureSchema = z secret_references: z.array(z.string().min(1)), network_content: browserNetworkContentSelectionValuesSchema, event_families: z.array(browserScenarioEventFamilySchema), - limits: browserScenarioCaptureLimitsSchema, + limits: browserScenarioCaptureLimitsValuesSchema, }), duration_ms: z.number().int().min(0), steps: z.array(browserScenarioStepSchema).min(1), diff --git a/src/domain/browserScenarioCaptureLimits.ts b/src/domain/browserScenarioCaptureLimits.ts index 316c87ceb5..60b9d4052f 100644 --- a/src/domain/browserScenarioCaptureLimits.ts +++ b/src/domain/browserScenarioCaptureLimits.ts @@ -14,33 +14,54 @@ export const DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS = { } as const; /** Caller-selected retained-output budgets; byte values are allocation-cost estimates. */ -export const browserScenarioCaptureLimitsSchema = z.strictObject({ - max_events: positiveSafeInteger.default( - DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_events, - ), - max_event_allocation_bytes: positiveSafeInteger.default( - DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_event_allocation_bytes, - ), - max_total_event_allocation_bytes: positiveSafeInteger.default( - DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_total_event_allocation_bytes, - ), - max_network_transactions: positiveSafeInteger.default( - DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_transactions, - ), - max_network_body_bytes: positiveSafeInteger.default( - DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_body_bytes, - ), - max_network_body_allocation_bytes: positiveSafeInteger.default( - DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_body_allocation_bytes, - ), - max_network_header_allocation_bytes: positiveSafeInteger.default( - DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_header_allocation_bytes, - ), - max_network_metadata_allocation_bytes: positiveSafeInteger.default( - DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_metadata_allocation_bytes, - ), +export const browserScenarioCaptureLimitsValuesSchema = z.strictObject({ + max_events: positiveSafeInteger, + max_event_allocation_bytes: positiveSafeInteger, + max_total_event_allocation_bytes: positiveSafeInteger, + max_network_transactions: positiveSafeInteger, + max_network_body_bytes: positiveSafeInteger, + max_network_body_allocation_bytes: positiveSafeInteger, + max_network_header_allocation_bytes: positiveSafeInteger, + max_network_metadata_allocation_bytes: positiveSafeInteger, }); +/** Input budgets default omitted values; output evidence uses the values schema above. */ +export const browserScenarioCaptureLimitsSchema = + browserScenarioCaptureLimitsValuesSchema.extend({ + max_events: + browserScenarioCaptureLimitsValuesSchema.shape.max_events.default( + DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_events, + ), + max_event_allocation_bytes: + browserScenarioCaptureLimitsValuesSchema.shape.max_event_allocation_bytes.default( + DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_event_allocation_bytes, + ), + max_total_event_allocation_bytes: + browserScenarioCaptureLimitsValuesSchema.shape.max_total_event_allocation_bytes.default( + DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_total_event_allocation_bytes, + ), + max_network_transactions: + browserScenarioCaptureLimitsValuesSchema.shape.max_network_transactions.default( + DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_transactions, + ), + max_network_body_bytes: + browserScenarioCaptureLimitsValuesSchema.shape.max_network_body_bytes.default( + DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_body_bytes, + ), + max_network_body_allocation_bytes: + browserScenarioCaptureLimitsValuesSchema.shape.max_network_body_allocation_bytes.default( + DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_body_allocation_bytes, + ), + max_network_header_allocation_bytes: + browserScenarioCaptureLimitsValuesSchema.shape.max_network_header_allocation_bytes.default( + DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_header_allocation_bytes, + ), + max_network_metadata_allocation_bytes: + browserScenarioCaptureLimitsValuesSchema.shape.max_network_metadata_allocation_bytes.default( + DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS.max_network_metadata_allocation_bytes, + ), + }); + export type BrowserScenarioCaptureLimits = z.infer< - typeof browserScenarioCaptureLimitsSchema + typeof browserScenarioCaptureLimitsValuesSchema >;