fix(evidence)!: reject missing recorded inventory and capture facts

BREAKING CHANGE: Inventory Evidence must explicitly report integrity_contradictions, and browser capture Evidence must report every resolved budget. Caller input defaults remain supported; stored observations are never filled with inferred defaults.
This commit is contained in:
morluto committed 2026-10-15 03:43:29 +08:00
1 parent fc789d19ff
commit a9588be4eb
6 files changed
+85 -30

No files matched your search

@@ -73,6 +73,7 @@ const inventory = (digit: string) => {
occurrences,
edges,
provenance: [],
integrity_contradictions: integrityContradictions,
coverage: { scope: "root", status: "complete" },
limitations: [],
});
+17 -1
View File
@@ -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,
+1 -1
View File
@@ -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()),
});
+17
View File
@@ -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", () => {
+2 -2
View File
@@ -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),
+47 -26
View File
@@ -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
>;