feat(confidence-engine): show investigation learning in report
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { loadInvestigation, saveInvestigation } from "@/lib/storage/investigation-storage";
|
||||
import { deriveInvestigationLearning } from "@/lib/graph/episode-preparation";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function ReportPage({ params }) {
|
||||
@@ -191,6 +192,32 @@ export default function ReportPage({ params }) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* What the investigation surfaced — deterministic learning projection */}
|
||||
{(() => {
|
||||
const learning = deriveInvestigationLearning({
|
||||
situationGraph: existing?.situationGraph,
|
||||
contributions: existing?.focusedContributions ?? [],
|
||||
findings: existing?.findings ?? [],
|
||||
});
|
||||
return learning.length > 0 ? (
|
||||
<div className="mt-6 rounded-xl border-[2.5px] border-teal-300/70 bg-gradient-to-b from-teal-50/60 to-white px-8 pt-6 pb-7 shadow-sm">
|
||||
<h2 className="mb-3 text-[11px] font-bold tracking-[.18em] uppercase text-teal-700/70">
|
||||
What the investigation surfaced
|
||||
</h2>
|
||||
{learning.map((group, gi) => (
|
||||
<div key={gi} className="mt-4 space-y-2">
|
||||
<p className="text-base font-medium text-gray-800">{group.questionText}</p>
|
||||
{group.propositions.map((prop, pi) => (
|
||||
<p key={pi} className="text-base leading-relaxed text-gray-700 italic">
|
||||
{prop.proposition}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null;
|
||||
})()}
|
||||
|
||||
{/* What remains plausible — conditional */}
|
||||
{report.hasPlausibleInterpretations && report.plausibleInterpretations ? (
|
||||
<div className="mt-6 rounded-xl border-[2.5px] border-blue-300/70 bg-gradient-to-b from-blue-50/60 to-white px-8 pt-6 pb-7 shadow-sm">
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user