// EvidenceRecord schema tests. // // Two positive fixtures (one per real-source prototype: distilled_facts // + contract_analyses) and three negative fixtures pinning the // non-negotiable invariants the spec demands: // - every record must trace to a source (provenance) // - schema_version must match — silent v1/v2 drift is the worst kind // - required identity fields (run_id) cannot be missing // // Run with: bun test auditor/schemas/distillation/evidence_record.test.ts import { test, expect } from "bun:test"; import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { validateEvidenceRecord, EVIDENCE_SCHEMA_VERSION } from "./evidence_record"; const FIXTURE_DIR = resolve(import.meta.dir, "fixtures"); function loadFixture(name: string): unknown { return JSON.parse(readFileSync(resolve(FIXTURE_DIR, name), "utf8")); } test("EVIDENCE_SCHEMA_VERSION is 1 — bump deliberately, never silently", () => { expect(EVIDENCE_SCHEMA_VERSION).toBe(1); }); test("positive: distilled_fact materialized record validates", () => { const r = validateEvidenceRecord(loadFixture("evidence_positive_distilled_fact.json")); if (!r.valid) console.error("unexpected errors:", r.errors); expect(r.valid).toBe(true); if (r.valid) { expect(r.value.run_id).toBe("cae21289"); expect(r.value.model_role).toBe("extractor"); expect(r.value.provenance.source_file).toBe("data/_kb/distilled_facts.jsonl"); } }); test("positive: contract_analysis materialized record validates with retrieval + observer fields", () => { const r = validateEvidenceRecord(loadFixture("evidence_positive_contract_analysis.json")); if (!r.valid) console.error("unexpected errors:", r.errors); expect(r.valid).toBe(true); if (r.valid) { expect(r.value.observer_verdict).toBe("reject"); expect(r.value.observer_confidence).toBe(95); expect(r.value.retrieved_context?.matrix_corpora?.length).toBe(4); expect(r.value.failure_markers).toContain("observer_rejected"); } }); test("negative: missing run_id is rejected with a specific error", () => { const r = validateEvidenceRecord(loadFixture("evidence_negative_no_run_id.json")); expect(r.valid).toBe(false); if (!r.valid) { expect(r.errors.some(e => e.includes("run_id"))).toBe(true); } }); test("negative: schema_version mismatch is rejected (silent v1/v2 drift guard)", () => { const r = validateEvidenceRecord(loadFixture("evidence_negative_bad_schema_version.json")); expect(r.valid).toBe(false); if (!r.valid) { expect(r.errors.some(e => e.includes("schema_version"))).toBe(true); } }); test("negative: bad provenance (non-sha256 sig_hash, non-ISO timestamp) is rejected", () => { const r = validateEvidenceRecord(loadFixture("evidence_negative_bad_provenance.json")); expect(r.valid).toBe(false); if (!r.valid) { // Must catch BOTH the sig_hash AND the recorded_at — comprehensive // error reporting is part of the contract. expect(r.errors.some(e => e.includes("sig_hash"))).toBe(true); expect(r.errors.some(e => e.includes("recorded_at"))).toBe(true); } }); test("negative: non-object input is rejected with clear error", () => { const r = validateEvidenceRecord("not an object"); expect(r.valid).toBe(false); if (!r.valid) { expect(r.errors[0]).toContain("expected object"); } }); test("negative: human_override with invalid decision is rejected", () => { const fixture = loadFixture("evidence_positive_distilled_fact.json") as Record; fixture.human_override = { overrider: "test-user", decision: "maybe", // invalid — must be accept|reject|needs_review reason: "test", overridden_at: "2026-04-26T22:30:00.000Z", }; const r = validateEvidenceRecord(fixture); expect(r.valid).toBe(false); if (!r.valid) { expect(r.errors.some(e => e.includes("human_override.decision"))).toBe(true); } }); test("positive: human_override = null is allowed (explicitly no override)", () => { const fixture = loadFixture("evidence_positive_distilled_fact.json") as Record; fixture.human_override = null; const r = validateEvidenceRecord(fixture); expect(r.valid).toBe(true); }); test("negative: observer_confidence outside [0, 100] is rejected", () => { const fixture = loadFixture("evidence_positive_contract_analysis.json") as Record; fixture.observer_confidence = 150; const r = validateEvidenceRecord(fixture); expect(r.valid).toBe(false); if (!r.valid) { expect(r.errors.some(e => e.includes("observer_confidence"))).toBe(true); } });