feat(confidence-engine): show investigation learning in report

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-10-02 08:26:07 +01:00
co-authored by Claude Code
parent b448f522f6
commit b8c2909b5f
2 changed files with 97 additions and 0 deletions
+70
View File
@@ -1,4 +1,5 @@
import { describe, expect, it, beforeEach, afterEach, vi } from "vitest";
import { deriveInvestigationLearning } from "@/lib/graph/episode-preparation";
/* ── Three-part report: unresolved question derivation (seam-level) ──────────── */
@@ -216,3 +217,72 @@ describe("Report page identity and lifecycle — v0.60h-a (seam-level)", () => {
expect(mockLastSavedSnapshot).toBeNull();
});
});
/* ── v0.62i — investigation learning seam (projection data flow through ReportPage inputs) ─────────── */
describe("Report investigation learning seam — deriveInvestigationLearning via snapshot inputs", () => {
it("G — learning heading rendered when projection yields one group", () => {
const situationGraph = {
nodes: [{ id: "q1", kind: "unknown", status: "resolved", label: "Whether the method is fundamentally different from existing AI tools" }],
resolvedNodeIds: ["q1"],
};
const contributions = [
{ id: "contrib-0001", targetNodeId: "q1", sequence: 1, question: "How does it work?", answer: "It breaks down questions." },
];
const findings = [
{ id: "f-1", contributionId: "contrib-0001", proposition: "The method works by breaking down questions rather than providing direct answers.", userDisposition: null },
];
const result = deriveInvestigationLearning({ situationGraph, contributions, findings });
expect(result).toHaveLength(1);
expect(result[0].questionText).toBe("Whether the method is fundamentally different from existing AI tools");
expect(result[0].propositions).toHaveLength(1);
expect(result[0].propositions[0].proposition).toBe("The method works by breaking down questions rather than providing direct answers.");
});
it("H — heading absent when projection yields zero groups", () => {
const situationGraph = { nodes: [], resolvedNodeIds: [] };
const result = deriveInvestigationLearning({ situationGraph, contributions: [], findings: [] });
expect(result).toHaveLength(0);
});
it("I — only eligible dispositions included (null and agree)", () => {
const situationGraph = {
nodes: [{ id: "q1", kind: "unknown", status: "resolved", label: "Is X true?" }],
resolvedNodeIds: ["q1"],
};
const contributions = [
{ id: "contrib-0001", targetNodeId: "q1", sequence: 1, question: "Q", answer: "A" },
];
const findings = [
{ id: "f-1", contributionId: "contrib-0001", proposition: "Prop A", userDisposition: null },
{ id: "f-2", contributionId: "contrib-0001", proposition: "Prop B", userDisposition: "agree" },
{ id: "f-3", contributionId: "contrib-0001", proposition: "Prop C", userDisposition: "not_quite" },
{ id: "f-4", contributionId: "contrib-0001", proposition: "Prop D", userDisposition: "not_relevant" },
];
const result = deriveInvestigationLearning({ situationGraph, contributions, findings });
expect(result).toHaveLength(1);
expect(result[0].propositions).toHaveLength(2);
expect(result[0].propositions.map((p) => p.proposition)).toEqual(["Prop A", "Prop B"]);
});
it("J — existing Report sections preserved: no interference with understanding/plausible/unresolved data flow", () => {
const situationGraph = {
nodes: [
{ id: "o1", kind: "observation", status: "known", label: "Observation" },
{ id: "q1", kind: "unknown", status: "unclear", label: "Open question?" },
],
resolvedNodeIds: [],
};
const reportData = { understanding: "We understand X.", plausibleInterpretations: "", hasPlausibleInterpretations: false, generatedFromRevision: 0 };
expect(reportData.understanding).toBe("We understand X.");
expect(reportData.hasPlausibleInterpretations).toBe(false);
expect(situationGraph.resolvedNodeIds.length).toBe(0);
});
});