From fb49df87aa605caf46c567cfa26b8a5b09adbd46 Mon Sep 17 00:00:00 2001 From: robbond Date: Sat, 5 Sep 2026 12:39:17 +0100 Subject: [PATCH] feat(confidence-engine): expose initial reconstruction evidence --- docs/current-handoff.md | 7 ++++++ lib/graph/orchestrator.js | 1 + tests/app/api/cases-start-route.test.js | 30 ++++++++++++++++++++++++- tests/graph/orchestrator.test.js | 4 +++- 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/docs/current-handoff.md b/docs/current-handoff.md index 556b4fa..9c4af26 100644 --- a/docs/current-handoff.md +++ b/docs/current-handoff.md @@ -19,6 +19,13 @@ - Targeted deterministic suite passed; live v0.5 semantic/reliability validation remains pending. - 502 structured-output reliability remains a separate unresolved issue. +## Initial reconstruction observability + +- Successful `/api/cases/start` responses now expose the validated initial `reconstruction`, the exact object used by `buildInitialGraph()`. +- Semantic experiments can compare `reconstruction.relationships` directly with projected `e-rel-*` SituationGraph edges; this is observability only and does not change reasoning semantics. +- Owning deterministic tests pass. Ten broader orchestrator failures were observed and classified as unrelated to this increment, but were not proven pre-existing because non-mutating baseline execution was blocked by the existing Vitest apparatus. +- No live validation has been rerun against this observability boundary. Next restart point: exactly one production-default `/api/cases/start` call using the fixed manufacturing scenario, comparing reconstruction relationship E directly with its projected graph edge. + ## Current product architecture Three distinct routes, not a single page: diff --git a/lib/graph/orchestrator.js b/lib/graph/orchestrator.js index e93ae35..054a214 100644 --- a/lib/graph/orchestrator.js +++ b/lib/graph/orchestrator.js @@ -496,6 +496,7 @@ export async function startCase(body, dependencies = {}) { return { success: true, summary: analysis.reconstruction?.summary ?? null, + reconstruction: analysis.reconstruction, situationGraph, selectedQuestion, diagnostics: buildDiagnostics({ diff --git a/tests/app/api/cases-start-route.test.js b/tests/app/api/cases-start-route.test.js index 2a639df..3d4b202 100644 --- a/tests/app/api/cases-start-route.test.js +++ b/tests/app/api/cases-start-route.test.js @@ -33,9 +33,33 @@ describe("app/api/cases/start route", () => { }); it("returns 200 on success", async () => { + const reconstruction = { + summary: "Validated reconstruction summary", + relationships: [ + { + id: "r1", + fromId: "u-intervention", + toId: "u-problem", + relationship: "depends_on", + description: "The intervention depends on the unresolved problem.", + confidence: "high", + }, + ], + }; mockStartCase.mockResolvedValue({ success: true, - situationGraph: { nodes: [{ id: "n1" }], edges: [] }, + reconstruction, + situationGraph: { + nodes: [{ id: "n1" }], + edges: [ + { + id: "e-unrelated", + fromNodeId: "n1", + toNodeId: "n1", + relationship: "supports", + }, + ], + }, selectedQuestion: null, diagnostics: {}, }); @@ -50,6 +74,10 @@ describe("app/api/cases/start route", () => { ); expect(response.status).toBe(200); + await expect(response.json()).resolves.toMatchObject({ + success: true, + reconstruction, + }); }); it("returns 400 for invalid request input", async () => { diff --git a/tests/graph/orchestrator.test.js b/tests/graph/orchestrator.test.js index feab265..202d562 100644 --- a/tests/graph/orchestrator.test.js +++ b/tests/graph/orchestrator.test.js @@ -371,12 +371,14 @@ describe("lib/graph/orchestrator startCase", () => { }); it("builds a valid graph on successful analysis", async () => { - mockAnalyseScenario.mockResolvedValue(makeAnalysisResult()); + const analysis = makeAnalysisResult(); + mockAnalyseScenario.mockResolvedValue(analysis); const { startCase } = await import("@/lib/graph/orchestrator.js"); const result = await startCase({ scenario: "Scenario text" }); expect(result.success).toBe(true); + expect(result.reconstruction).toBe(analysis.reconstruction); expect(result.situationGraph.centralStatement).toBe("Scenario text"); expect(result.situationGraph.currentSummary).toContain("Nodes:"); expect(result.diagnostics).toMatchObject({