test(confidence-engine): preserve focused investigation evidence seam
This commit is contained in:
@@ -311,8 +311,8 @@ assert(helperSrc.includes("resolvedNodeIds.add(targetNodeId)") || helperSrc.incl
|
||||
// E5. Post-episode graph feeds CU synthesis: verified by composeDeepInvestigationCheckpoint's Step 2
|
||||
assert(helperSrc.includes("synthesizeCurrentUnderstanding"), "helper invokes synthesizeCurrentUnderstanding for CU synthesis");
|
||||
|
||||
// E6. Prior + appended Findings accumulated exactly once for CU synthesis
|
||||
assert(helperSrc.includes("postEpisodeFindings = [...priorFindings, ...accumulatedEpisodes]"), "findings accumulation: prior + appended concatenated exactly once");
|
||||
// E6. Prior + derived from Contribution + appended Findings accumulated exactly once for CU synthesis
|
||||
assert(helperSrc.includes("postEpisodeFindings = [...priorFindings, ...newFindingsFromContributions, ...accumulatedEpisodes]") || helperSrc.includes("postEpisodeFindings : [...priorFindings, ...newFindingsFromContributions, ...accumulatedEpisodes]"), "findings accumulation: prior + derived from Contribution + appended concatenated exactly once");
|
||||
|
||||
// E7. Next graph returned via updatedSituationGraph in checkpoint object
|
||||
assert(helperSrc.includes("updatedSituationGraph: updatedGraph") || helperSrc.includes("updatedSituationGraph : updatedGraph"), "updatedSituationGraph returned in checkpoint output");
|
||||
@@ -323,5 +323,39 @@ assert(helperSrc.includes("postEpisodeFindings: postEpisodeFindings"), "postEpis
|
||||
// E9. Provider-call accounting preserved (existing behavior)
|
||||
const extractResult = extractLiveExperimentCheckpoint(successResult(123, 456), successParams);
|
||||
assert(extractResult.providerGenerateCalls === 1, "providerGenerateCalls preserved from extraction path");
|
||||
|
||||
// ---- CONTRIBUTION SEAM VERIFICATION (Iteration 4) ──────────────────────
|
||||
console.log("\n=== CONTRIBUTION SEAM VERIFICATION ===\n");
|
||||
|
||||
// C1. composeDeepInvestigationCheckpoint accepts contributions parameter (defaults to [])
|
||||
assert(composeDeepInvestigationCheckpoint.length >= 1, "composeDeepInvestigationCheckpoint accepts at least 1 param (contributions default)");
|
||||
|
||||
// C2. Production parity: helper derives Contribution from answer when not supplied
|
||||
assert(helperSrc.includes("_deriveContributionFromAnswer"), "helper has _deriveContributionFromAnswer (mirrors production appendFocusedContribution)");
|
||||
|
||||
// C3. Contribution carries targetNodeId matching focused target
|
||||
assert(helperSrc.includes("targetNodeId: targetNodeId") || helperSrc.includes("targetNodeId : targetNodeId"), "Contribution derives targetNodeId from focused target");
|
||||
|
||||
// C4. Contribution fields match production shape
|
||||
assert(helperSrc.includes("observations:") && helperSrc.includes("answer:"), "Contribution includes observations and answer fields (production shape)");
|
||||
|
||||
// C5. deriveFindingsFromContributions is used to derive Findings from new Contribution (same production helper)
|
||||
assert(helperSrc.includes("deriveFindingsFromContributions"), "helper reuses produce deriveFindingsFromContributions for Finding derivation");
|
||||
|
||||
// C6. Effective contributions passed to prepareCompletedEpisode (not empty array)
|
||||
assert(helperSrc.includes("contributions: effectiveContributions") || helperSrc.includes("contributions : effectiveContributions"), "helper passes effectiveContributions to prepareCompletedEpisode (not empty)");
|
||||
|
||||
// C7. Post-episode graph feeds CU synthesis
|
||||
assert(helperSrc.includes("synthesizeCurrentUnderstanding"), "CU synthesis receives updated graph for full accumulated findings");
|
||||
|
||||
// C8. postEpisodeFindings includes prior + derived from new Contribution + appended episodes (exactly-once)
|
||||
assert(helperSrc.includes("newFindingsFromContributions"), "postEpisodeFindings includes newly derived Findings from Contribution");
|
||||
|
||||
// C9. next Contributions returned in checkpoint for longitudinal Episode N+1 state feeding
|
||||
assert(helperSrc.includes("postEpisodeContributions: effectiveContributions") || helperSrc.includes("postEpisodeContributions : effectiveContributions"), "postEpisodeContributions returned in checkpoint");
|
||||
|
||||
// C10. Source code verifies contributions parameter default behavior (empty array)
|
||||
assert(helperSrc.includes("contributions = []"), "contributions defaults to empty array when not supplied");
|
||||
|
||||
console.log("\n--- Total failures: " + failures + " ---\n");
|
||||
process.exit(failures > 0 ? 1 : 0);
|
||||
@@ -18,6 +18,9 @@
|
||||
const dotenv = require("dotenv");
|
||||
dotenv.config({ path: ".env.local" });
|
||||
|
||||
// Re-export production helper for apparatus use — avoids fabricating Finding propositions.
|
||||
const { deriveFindingsFromContributions } = require("../../lib/graph/finding-helpers.js");
|
||||
|
||||
function assertRequiredEnv(name) {
|
||||
const value = process.env[name];
|
||||
if (!value) {
|
||||
@@ -268,7 +271,25 @@ async function runLiveExperiment({ graph, previousQuestion, answer, findings = [
|
||||
* - currentUnderstanding from the synthesis result
|
||||
* - findingsCheckpoint with accurate post-episode accumulated findings count
|
||||
*/
|
||||
async function composeDeepInvestigationCheckpoint({ situationGraph, previousQuestion, answer, findings = [], targetNodeId, episodeMode }) {
|
||||
/**
|
||||
* Deterministically derive a canonical Contribution from the fixed answer
|
||||
* when the caller does not supply one. Mirrors production appendFocusedContribution
|
||||
* shape: id, targetNodeId, question, answer, sequence, observations, etc.
|
||||
*/
|
||||
function _deriveContributionFromAnswer({ answer, previousQuestion, targetNodeId, sequence }) {
|
||||
return {
|
||||
id: `contrib-ep-${String(sequence).padStart(4, "0")}`,
|
||||
targetNodeId: targetNodeId ?? null,
|
||||
question: previousQuestion ?? "",
|
||||
answer: answer ?? "",
|
||||
sequence: sequence,
|
||||
observations: [answer],
|
||||
uncertainties: [],
|
||||
possibleFollowUpQuestions: [],
|
||||
};
|
||||
}
|
||||
|
||||
async function composeDeepInvestigationCheckpoint({ situationGraph, previousQuestion, answer, findings = [], contributions = [], targetNodeId, episodeMode }) {
|
||||
dotenv.config({ path: ".env.local" });
|
||||
|
||||
const baseUrl = assertRequiredEnv("OLLAMA_BASE_URL");
|
||||
@@ -306,6 +327,19 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues
|
||||
let episodeResult;
|
||||
|
||||
/* ── Production-equivalent focused-episode seam: targetNodeId triggers the same path as executeEpisodeDone → handleEpisodeMode ─── */
|
||||
|
||||
// Derive a canonical Contribution from the fixed answer when none supplied.
|
||||
// Mirrors production appendFocusedContribution: user answer → canonical Contribution
|
||||
const effectiveContributions = contributions.length > 0 ? [...contributions] : [];
|
||||
let newFindingsFromContributions = [];
|
||||
if (effectiveContributions.length === 0 && answer && targetNodeId) {
|
||||
const contribSeq = effectiveContributions.length + 1;
|
||||
const derivedContrib = _deriveContributionFromAnswer({ answer, previousQuestion, targetNodeId, sequence: contribSeq });
|
||||
effectiveContributions.push(derivedContrib);
|
||||
// Derive canonical Findings from the Contribution (production seam)
|
||||
newFindingsFromContributions = deriveFindingsFromContributions([derivedContrib]).findings;
|
||||
}
|
||||
|
||||
if (episodeMode === true && targetNodeId) {
|
||||
// Mirrors produceEpisodeAwareGraph: prepareCompletedEpisode → reconsiderCompletedEpisode → applyValidatedProposal
|
||||
const { prepareCompletedEpisode } = await import("../../lib/graph/episode-preparation.js");
|
||||
@@ -314,7 +348,7 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues
|
||||
const prepared = prepareCompletedEpisode({
|
||||
situationGraph,
|
||||
targetNodeId,
|
||||
contributions: [], // no focused contributions in checkpoint helper (mirrors production when called without explicit contributions)
|
||||
contributions: effectiveContributions,
|
||||
findings,
|
||||
});
|
||||
|
||||
@@ -365,10 +399,10 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues
|
||||
/* ── Step 2: Current Understanding synthesis (mirrors production synthesizeFn) ─── */
|
||||
const updatedGraph = episodeResult.updatedSituationGraph;
|
||||
|
||||
// Accumulate prior findings + newly appended Findings for CU synthesis
|
||||
// Accumulate prior findings + newly derived Findings (from new Contribution) for CU synthesis
|
||||
const priorFindings = Array.isArray(findings) ? [...findings] : [];
|
||||
const accumulatedEpisodes = episodeResult.appendedFindings ?? [];
|
||||
const postEpisodeFindings = [...priorFindings, ...accumulatedEpisodes];
|
||||
const postEpisodeFindings = [...priorFindings, ...newFindingsFromContributions, ...accumulatedEpisodes];
|
||||
|
||||
let currentUnderstanding = null;
|
||||
if (episodeResult.success && updatedGraph) {
|
||||
@@ -405,6 +439,9 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues
|
||||
/* ── updatedSituationGraph (NEW — for longitudinal Episode N+1 state feeding) ─── */
|
||||
updatedSituationGraph: updatedGraph,
|
||||
|
||||
/* ── postEpisodeContributions (NEW — accumulated Contributions for longitudinal tracking) ─── */
|
||||
postEpisodeContributions: effectiveContributions,
|
||||
|
||||
/* ── postEpisodeFindings (NEW — accumulated Findings for Episode N+1) ─── */
|
||||
postEpisodeFindings: postEpisodeFindings,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user