test(confidence-engine): preserve deep investigation episode state

This commit is contained in:
2026-10-05 07:54:17 +01:00
parent 90649c0495
commit ca284d9c04
2 changed files with 123 additions and 25 deletions
+77 -24
View File
@@ -170,7 +170,7 @@ function _extractReasoningState(result) {
/**
* Run one live experiment through the real updateCase() production path.
*/
async function runLiveExperiment({ graph, previousQuestion, answer }) {
async function runLiveExperiment({ graph, previousQuestion, answer, findings = [] }) {
const baseUrl = assertRequiredEnv("OLLAMA_BASE_URL");
const model = assertRequiredEnv("OLLAMA_MODEL");
@@ -207,7 +207,50 @@ async function runLiveExperiment({ graph, previousQuestion, answer }) {
);
const endToEndElapsedMs = Date.now() - endToEndStartedAt;
return extractLiveExperimentCheckpoint(result, { graph, answer });
// ── accumulated state for longitudinal multi-episode use ───
const updatedGraph = result?.updatedSituationGraph ?? null;
const postEpisodeFs = Array.isArray(result?.findings) ? [...result.findings] : [];
return {
/* ── CU narrative (UNAVAILABLE — synthesis is a separate seam from updateCase()) ─── */
currentUnderstanding: "UNAVAILABLE",
/* ── updatedSituationGraph (NEW for longitudinal state feeding) ─── */
updatedSituationGraph: updatedGraph,
/* ── postEpisodeFindings (NEW — accumulated Findings exposed for Episode N+1) ─── */
postEpisodeFindings: postEpisodeFs,
/* ── graph checkpoint (from production result) ─── */
graphCheckpoint: updatedGraph
? {
nodeCount: updatedGraph.nodes?.length ?? 0,
edgeCount: updatedGraph.edges?.length ?? 0,
resolvedNodeIds: updatedGraph.resolvedNodeIds ?? [],
}
: { nodeCount: 0, edgeCount: 0, resolvedNodeIds: [] },
/* ── findings checkpoint (count from accumulated Findings) ─── */
findingsCheckpoint: {
total: postEpisodeFs.length,
eligible: "UNAVAILABLE",
},
/* ── Timing ─── */
modelElapsedMs: result?.modelElapsedMs !== undefined ? result.modelElapsedMs : null,
endToEndElapsedMs: result?.endToEndElapsedMs !== undefined ? result.endToEndElapsedMs : null,
providerGenerateCalls: result != null && result.providerGenerateCalls != null ? result.providerGenerateCalls : 0,
modelName: result?.modelName || null,
/* ── answer meaning (from production result) ─── */
userSupportedMeaning: result?.proposal?.answerMeaning?.userSupportedMeaning ?? null,
possibleInference: result?.proposal?.answerMeaning?.possibleInference ?? null,
/* ── helper internals (for diagnostic / test verification) ─── */
selectedQuestion: result?.proposal?.selectedQuestion ?? null,
behaviourSelection: result?.behaviourSelection ?? null,
reasoningState: _extractReasoningState(result),
};
}
/**
@@ -225,7 +268,7 @@ async function runLiveExperiment({ graph, previousQuestion, answer }) {
* - currentUnderstanding from the synthesis result
* - findingsCheckpoint with accurate post-episode accumulated findings count
*/
async function composeDeepInvestigationCheckpoint({ situationGraph, previousQuestion, answer }) {
async function composeDeepInvestigationCheckpoint({ situationGraph, previousQuestion, answer, findings = [] }) {
dotenv.config({ path: ".env.local" });
const baseUrl = assertRequiredEnv("OLLAMA_BASE_URL");
@@ -267,16 +310,11 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues
/* ── Step 2: Current Understanding synthesis (mirrors production synthesizeFn) ─── */
const updatedGraph = episodeResult.updatedSituationGraph;
const accumulatedFindings = episodeResult.appendedFindings ?? [];
// Collect accumulated findings from the episode result for accurate counting
let postEpisodeFindings = Array.isArray(accumulatedFindings) ? [...accumulatedFindings] : [];
// Derive eligible count via the same filter the production seam uses
const { filterEligibleFindings } = await import("../../lib/graph/current-understanding-synthesis.js");
const eligibleCount = postEpisodeFindings.length > 0
? filterEligibleFindings(postEpisodeFindings).length
: 0;
// Accumulate prior findings + newly appended Findings for CU synthesis
const priorFindings = Array.isArray(findings) ? [...findings] : [];
const accumulatedEpisodes = episodeResult.appendedFindings ?? [];
const postEpisodeFindings = [...priorFindings, ...accumulatedEpisodes];
let currentUnderstanding = null;
if (episodeResult.success && updatedGraph) {
@@ -291,31 +329,46 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues
currentUnderstanding = synthesized?.currentUnderstanding ?? null;
}
// Consistent graphCheckpoint for both success and failure paths
const graphCheckpoint = updatedGraph
? {
nodeCount: updatedGraph.nodes?.length ?? 0,
edgeCount: updatedGraph.edges?.length ?? 0,
resolvedNodeIds: updatedGraph.resolvedNodeIds ?? [],
}
: { nodeCount: 0, edgeCount: 0, resolvedNodeIds: [] };
// Accurate post-episode accumulated findings count
const { filterEligibleFindings } = await import("../../lib/graph/current-understanding-synthesis.js");
const eligibleCount = postEpisodeFindings.length > 0
? filterEligibleFindings(postEpisodeFindings).length
: 0;
return {
/* ── CU synthesis result (NEW — mirrors production synthesizeFn) ─── */
/* ── CU synthesis result (mirrors production synthesizeFn) ─── */
currentUnderstanding,
/* ── Accurate post-episode findings count (FIX — uses actual accumulated Findings, not graph nodes) ─── */
/* ── updatedSituationGraph (NEW — for longitudinal Episode N+1 state feeding) ─── */
updatedSituationGraph: updatedGraph,
/* ── postEpisodeFindings (NEW — accumulated Findings for Episode N+1) ─── */
postEpisodeFindings: postEpisodeFindings,
/* ── Accurate post-episode accumulated findings count ─── */
findingsCheckpoint: {
total: postEpisodeFindings.length,
eligible: eligibleCount,
},
/* ── Timing (mirrors extractLiveExperimentCheckpoint) ─── */
/* ── graph checkpoint (from production result) ─── */
graphCheckpoint,
/* ── Timing ─── */
modelElapsedMs,
endToEndElapsedMs,
providerGenerateCalls,
modelName: episodeResult.modelName ?? null,
/* ── Graph checkpoint (from production result) ─── */
graphCheckpoint: updatedGraph
? {
nodeCount: updatedGraph.nodes?.length ?? 0,
edgeCount: updatedGraph.edges?.length ?? 0,
resolvedNodeIds: updatedGraph.resolvedNodeIds ?? [],
}
: null,
/* ── Answer meaning (from production result) ─── */
userSupportedMeaning: episodeResult?.proposal?.answerMeaning?.userSupportedMeaning ?? null,
possibleInference: episodeResult?.proposal?.answerMeaning?.possibleInference ?? null,