import { describe, expect, it } from "vitest"; import { createEvidence } from "./evidence.js"; import { ANALYSIS_SNAPSHOT_TARGET } from "./analysisSnapshot.fixture.js"; import { createEvidenceBundle, createImmutableEvidenceBundle, NonCanonicalEvidenceBundleError, describeEvidenceBundleFailure, evidenceBundleForTarget, parseEvidenceBundle, } from "./evidenceBundle.js"; import { createResidualUnknown, recordUnknownInputSchema, updateResidualUnknown, } from "./residualUnknown.js"; const provider = { id: "fixture", name: "Fixture", version: "1" }; const targetDigest = "a".repeat(64); const foreignDigest = "b".repeat(64); describe("evidence bundle failure classification", () => { it("tags valid-shaped bundles that fail canonical ordering", () => { const records = ["first", "second"].map((label) => createEvidence(undefined, provider, { operation: "observe", parameters: { label }, result: { label }, }), ); const canonical = createEvidenceBundle(records); expect(() => parseEvidenceBundle({ ...canonical, records: [...canonical.records].reverse(), }), ).toThrow(NonCanonicalEvidenceBundleError); }); it("treats only authenticated standalone Evidence as the wrong input kind", () => { const record = createEvidence(undefined, provider, { operation: "observe", parameters: {}, result: { observed: true }, }); const single = describeEvidenceBundleFailure(record, new Error("bundle")); expect(single).toMatchObject({ kind: "single-record" }); const tampered = describeEvidenceBundleFailure( { ...record, normalized_result: { observed: false } }, new Error("bundle"), ); expect(tampered).toMatchObject({ kind: "invalid-bundle" }); }); }); const makeUnknown = ( question: string, scopeDigest: string, dependency?: string, ) => { const input = recordUnknownInputSchema.parse({ question, severity: "medium", domain: "bundle-projection", required_authority: null, required_confidence: "derived", required_environment: null, recommended_probes: [], relationships: dependency === undefined ? [] : [{ type: "depends-on", unknown_id: dependency }], }); const mutation = createEvidence(undefined, provider, { predicateType: "rea.residual-unknown-mutation", operation: "record_unknown", parameters: { domain: input.domain, severity: input.severity }, result: { action: "record", question: input.question, required_authority: input.required_authority, required_confidence: input.required_confidence, }, }); return { input, evidence: mutation, unknown: createResidualUnknown(input, mutation.evidence_id, scopeDigest), }; }; describe("evidenceBundleForTarget", () => { it("retains mutation evidence from other targets for complete revision histories", () => { const first = makeUnknown( "Target question updated elsewhere", targetDigest, ); const update = createEvidence( { ...ANALYSIS_SNAPSHOT_TARGET, sha256: foreignDigest }, provider, { predicateType: "rea.residual-unknown-mutation", operation: "update_unknown", parameters: { unknown_id: first.unknown.unknown_id, expected_revision: 1, }, result: { status: "resolved" }, }, ); const resolved = updateResidualUnknown( first.unknown, { ...first.input, unknown_id: first.unknown.unknown_id, expected_revision: 1, status: "resolved", resolution: { disposition: "withdrawn", rationale: "Withdrawn by the analyst", evidence_ids: [], }, }, update.evidence_id, ); const unrelated = makeUnknown("Unrelated foreign question", foreignDigest); const bundle = parseEvidenceBundle( createEvidenceBundle( [first.evidence, update, unrelated.evidence], [first.unknown, resolved, unrelated.unknown], ), ); const projected = evidenceBundleForTarget(bundle, targetDigest); expect(parseEvidenceBundle(projected)).toEqual( createEvidenceBundle([first.evidence, update], [first.unknown, resolved]), ); expect(evidenceBundleForTarget(projected, targetDigest)).toEqual(projected); }); it.each(["evidence", "relationship"])( "removes whole histories and their dependents when a revision requires foreign %s", (excluded) => { const first = makeUnknown( "Target history with an excluded revision", targetDigest, ); const foreign = makeUnknown("Excluded foreign context", foreignDigest); const evidence = createEvidence( { ...ANALYSIS_SNAPSHOT_TARGET, sha256: foreignDigest }, provider, { operation: "foreign_observation", parameters: {}, result: true }, ); const updated = updateResidualUnknown( first.unknown, { ...first.input, unknown_id: first.unknown.unknown_id, expected_revision: 1, status: "investigating", supporting_evidence_ids: excluded === "evidence" ? [evidence.evidence_id] : [], relationships: excluded === "relationship" ? [{ type: "related-to", unknown_id: foreign.unknown.unknown_id }] : [], resolution: null, }, first.evidence.evidence_id, ); const resolved = updateResidualUnknown( updated, { ...first.input, unknown_id: first.unknown.unknown_id, expected_revision: 2, status: "resolved", resolution: { disposition: "withdrawn", rationale: "Foreign context removed from the latest revision", evidence_ids: [], }, }, first.evidence.evidence_id, ); const child = makeUnknown( "Dependent target history", targetDigest, first.unknown.unknown_id, ); const unrelated = makeUnknown("Independent target history", targetDigest); const bundle = parseEvidenceBundle( createEvidenceBundle( [ first.evidence, foreign.evidence, evidence, child.evidence, unrelated.evidence, ], [ first.unknown, updated, resolved, foreign.unknown, child.unknown, unrelated.unknown, ], ), ); expect( parseEvidenceBundle(evidenceBundleForTarget(bundle, targetDigest)), ).toEqual( createEvidenceBundle([unrelated.evidence], [unrelated.unknown]), ); }, ); }); describe("evidenceBundleForTarget relationship pruning", () => { it("removes dependent unknowns when their foreign-scope root is excluded", () => { const foreignRoot = makeUnknown("Foreign root", foreignDigest); const child = makeUnknown( "Target child", targetDigest, foreignRoot.unknown.unknown_id, ); const grandchild = makeUnknown( "Target grandchild", targetDigest, child.unknown.unknown_id, ); const retained = makeUnknown("Independent target", targetDigest); const bundle = createEvidenceBundle( [ foreignRoot.evidence, child.evidence, grandchild.evidence, retained.evidence, ], [ foreignRoot.unknown, child.unknown, grandchild.unknown, retained.unknown, ], ); expect(evidenceBundleForTarget(bundle, targetDigest)).toEqual( createEvidenceBundle([retained.evidence], [retained.unknown]), ); }); it("projects a valid graph with more than 125,000 dependents", () => { const foreignRoot = makeUnknown("Foreign high-fan-out root", foreignDigest); const middle = makeUnknown( "Target middle depending on foreign root", targetDigest, foreignRoot.unknown.unknown_id, ); const unknowns = [foreignRoot.unknown, middle.unknown]; for (let index = 0; index < 125_000; index += 1) { const input = recordUnknownInputSchema.parse({ question: `Target child ${index}`, severity: "medium", domain: "bundle-projection", required_authority: null, required_confidence: "derived", required_environment: null, recommended_probes: [], relationships: [ { type: "depends-on", unknown_id: middle.unknown.unknown_id }, ], }); unknowns.push( createResidualUnknown(input, middle.evidence.evidence_id, targetDigest), ); } const bundle = parseEvidenceBundle( createEvidenceBundle([foreignRoot.evidence, middle.evidence], unknowns), ); expect(evidenceBundleForTarget(bundle, targetDigest)).toEqual( createEvidenceBundle([], []), ); }); }); describe("immutable serialization bundles", () => { it("authenticates sealed records while revalidating detached and malformed input", () => { const evidence = createEvidence(undefined, provider, { operation: "health", parameters: {}, result: { nested: [true] }, }); const bundle = createImmutableEvidenceBundle([evidence]); expect(parseEvidenceBundle(bundle)).toBe(bundle); expect(Object.isFrozen(bundle.records[0]?.normalized_result)).toBe(true); const detached: unknown = JSON.parse(JSON.stringify(bundle)); expect(parseEvidenceBundle(detached)).toEqual(bundle); expect(parseEvidenceBundle(detached)).not.toBe(bundle); const tampered = { ...bundle, records: [{ ...evidence, normalized_result: false }], }; expect(() => parseEvidenceBundle(Object.freeze(tampered))).toThrow(); expect(() => createImmutableEvidenceBundle(tampered.records)).toThrow(); expect(() => createImmutableEvidenceBundle([evidence, evidence])).toThrow(); }); });