From ef04b9e49424741f61d43a1590131d058b601fda Mon Sep 17 00:00:00 2001 From: robbond Date: Mon, 3 Aug 2026 08:50:37 +0100 Subject: [PATCH] fix: normalise reported claim evidence kind --- lib/reconstruction/compatibility.js | 12 ++++ tests/reconstruction/compatibility.test.js | 83 ++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/lib/reconstruction/compatibility.js b/lib/reconstruction/compatibility.js index efb5de2..fb665c3 100644 --- a/lib/reconstruction/compatibility.js +++ b/lib/reconstruction/compatibility.js @@ -16,6 +16,18 @@ export function normaliseAnalysisResponse(input) { normalised.evidence = normalised.evidence.map((record, index) => { if (!record || typeof record !== "object") return record; + if (record.evidenceType === "reported_claim") { + changesApplied.push({ + path: ["evidence", index, "evidenceType"], + change: "Converted reported_claim to reported_statement", + }); + + record = { + ...record, + evidenceType: "reported_statement", + }; + } + if (record.source === null) { changesApplied.push({ path: ["evidence", index, "source"], diff --git a/tests/reconstruction/compatibility.test.js b/tests/reconstruction/compatibility.test.js index 15fc5e5..36f1c80 100644 --- a/tests/reconstruction/compatibility.test.js +++ b/tests/reconstruction/compatibility.test.js @@ -71,6 +71,33 @@ describe("normaliseAnalysisResponse", () => { expect(result.changesApplied).toHaveLength(1); }); + it("normalises reported_claim evidenceType to reported_statement", () => { + const input = { + evidence: [ + { + id: "ev1", + description: "x", + evidenceType: "reported_claim", + confidence: "medium", + importance: "important", + source: "report", + }, + ], + }; + + const result = normaliseAnalysisResponse(input); + + expect(result.normalised.evidence[0].evidenceType).toBe( + "reported_statement", + ); + expect(result.changesApplied).toEqual([ + { + path: ["evidence", 0, "evidenceType"], + change: "Converted reported_claim to reported_statement", + }, + ]); + }); + it("does not invent a next question", () => { const input = { evidence: [] }; const result = normaliseAnalysisResponse(input); @@ -165,6 +192,62 @@ describe("analyseScenario compatibility", () => { expect(result.nextQuestion).toBeUndefined(); }); + it("succeeds when reported_claim is the only evidenceType mismatch", async () => { + mockGenerateReconstruction.mockResolvedValue({ + inputClassification: { + primaryType: "unexplained_change", + secondaryTypes: [], + reasoningModes: ["validate_measurement"], + classificationReason: "reason", + confidence: "medium", + }, + reconstruction: { + summary: "summary", + actors: [], + systemsOrObjects: [], + expectedStates: [], + observedStates: [], + differences: [], + knownTransitions: [], + unexplainedTransitions: [], + contradictions: [], + importantUnknowns: [], + plausibleInterpretations: [], + }, + evidence: [ + { + id: "ev1", + description: "desc", + evidenceType: "reported_claim", + attribution: null, + confidence: "medium", + importance: "important", + }, + ], + nextQuestion: { + id: "q1", + question: "What denominator?", + targets: ["observedStates"], + reason: "reason", + expectedInformationValue: "high", + reasoningMode: "validate_measurement", + }, + }); + + const { analyseScenario } = await import("@/lib/analysis.js"); + const result = await analyseScenario("Scenario text", { + promptVersion: "v0.3", + }); + + expect(result.success).toBe(true); + expect(result.compatibilityApplied).toBe(true); + expect(result.compatibilityChanges).toContainEqual({ + path: ["evidence", 0, "evidenceType"], + change: "Converted reported_claim to reported_statement", + }); + expect(result.evidence[0].evidenceType).toBe("reported_statement"); + }); + it("malformed JSON still fails", async () => { mockGenerateReconstruction.mockResolvedValue("{not valid json");