test(confidence-engine): extract focused target input for deterministic verification
This commit is contained in:
@@ -891,6 +891,114 @@ console.log("\n=== SAVE FOCUSED INVESTIGATION EVIDENCE ===\n");
|
||||
console.log("\n=== SAVE EVIDENCE NEGATIVE TESTS COMPLETE — ALL ASSERTIONS PASSED ===\n");
|
||||
}
|
||||
|
||||
// ---- OBSERVATION: targetDescription initialization boundary (Iteration 9) ───
|
||||
// Verify that focusedInvestigationInput.targetDescription assignment is scoped inside
|
||||
// the deconstruction block and cannot escape to the return object independently.
|
||||
|
||||
console.log("\n=== TARGET DESCRIPTION BOUNDARY ===\n");
|
||||
|
||||
{
|
||||
const { writeFileSync, readFileSync, unlinkSync } = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
const helperSrc2 = readFileSync("./tests/graph/live-update-experiment-helper.cjs", "utf8");
|
||||
|
||||
// T1. targetDescription is declared with let (not const) — must be assigned later
|
||||
assert(helperSrc2.includes("let targetDescription") || helperSrc2.includes("let targetDescription "),
|
||||
"T1: targetDescription declared as mutable let");
|
||||
|
||||
// T2. Initialize to empty string before any deconstruction block
|
||||
const initIdx = helperSrc2.indexOf('targetDescription = ""');
|
||||
assert(initIdx >= 0, "T2: targetDescription initialized to \"\" before deconstruction block");
|
||||
|
||||
// T3. Target node lookup uses situationGraph.nodes.find — requires graph.nodes array with .id property
|
||||
assert(helperSrc2.includes("situationGraph.nodes.find") && helperSrc2.includes("n.id === targetNodeId"),
|
||||
"T3: target node lookup from situationGraph.nodes by id");
|
||||
|
||||
// T4. Assignment to targetDescription is ONLY inside the deconstruction condition block
|
||||
const descBlockStart = helperSrc2.indexOf('if (effectiveContributionsForTarget.length === 0 && answer && targetNodeId)');
|
||||
assert(descBlockStart >= 0, "T4: deconstruction guard condition present");
|
||||
const nextElseIdx = helperSrc2.indexOf("} else {", descBlockStart);
|
||||
const blockEnd = helperSrc2.indexOf("\n\n ", descBlockStart + 5);
|
||||
const blockContent = helperSrc2.substring(descBlockStart, Math.min(nextElseIdx > descBlockStart ? nextElseIdx : blockEnd, helperSrc2.length));
|
||||
assert(blockContent.includes("targetDescription = targetNode?.description"),
|
||||
"T4: assignment to targetDescription inside deconstruction block only");
|
||||
|
||||
// T5. Return value reads targetDescription ?? "" — never the source node directly
|
||||
assert(helperSrc2.includes("targetDescription: targetDescription ?? \"\"") || helperSrc2.includes('targetDescription: targetDescription ?? ""'),
|
||||
"T5: return reads from variable (not direct lookup)");
|
||||
|
||||
// T6. When answer is falsy, deconstruction block DOES NOT fire — targetDescription remains ""
|
||||
const guardCondition = "effectiveContributionsForTarget.length === 0 && answer && targetNodeId";
|
||||
assert(helperSrc2.includes(guardCondition), "T6: guard requires truthy answer for block entry");
|
||||
|
||||
// T7. When targetNodeId is null/undefined, deconstruction block DOES NOT fire — targetDescription remains ""
|
||||
assert(helperSrc2.includes("targetNodeId"), "T7: guard includes targetNodeId check");
|
||||
|
||||
// T8. effectiveContributionsForTarget = [] when no contributions (empty path triggers deconstruct)
|
||||
const effInitLine = helperSrc2.indexOf("effectiveContributionsForTarget = effectiveContributions");
|
||||
assert(helperSrc2.substring(effInitLine, effInitLine + 200).includes("effectiveContributions"),
|
||||
"T8: effectiveContributionsForTarget defaults to contributions (empty when no contributions)");
|
||||
|
||||
console.log("\n=== TARGET DESCRIPTION BOUNDARY OBSERVATION COMPLETE — ALL ASSERTIONS PASSED ===\n");
|
||||
}
|
||||
|
||||
// ---- EXPERIMENT 3: extractFocusedTargetInput deterministic test fixture ────
|
||||
// Deterministic pure-function test using graphUnknownNodes values from HS-03C-result.json.
|
||||
// This is a deterministic test fixture, NOT a reconstruction of the original Experiment 9 runtime graph.
|
||||
|
||||
console.log("\n=== EXTRACT FOCUSED TARGET INPUT — DETERMINISTIC TEST ===\n");
|
||||
|
||||
{
|
||||
const { extractFocusedTargetInput } = require("./live-update-experiment-helper.cjs");
|
||||
|
||||
// Test graph constructed from known HS-03C graphUnknownNodes values (deterministic fixture)
|
||||
const testGraph = {
|
||||
nodes: [
|
||||
{ id: "n2yzwlv", label: "Timeline and feasibility of recruiting two specialists within the nine-month window", description: "Timeline and feasibility of recruiting two specialists within the nine-month window", status: "unknown" },
|
||||
{ id: "n16fjvw", label: "Timeline for designing, testing, and deploying the software integration without exceeding the nine-month window", description: "Timeline for designing, testing, and deploying the software integration without exceeding the nine-month window", status: "unknown" },
|
||||
{ id: "n2bmvqz", label: "Volume and activation timeline of customer commitments needed to cover operating costs at launch", description: "Volume and activation timeline of customer commitments needed to cover operating costs at launch", status: "unknown" },
|
||||
{ id: "nb4o17s", label: "Nature and magnitude of dependencies between the three requirements that could cause cascading timeline delays", description: "Nature and magnitude of dependencies between the three requirements that could cause cascading timeline delays", status: "unknown" },
|
||||
],
|
||||
edges: [],
|
||||
};
|
||||
|
||||
const CANONICAL_DESCRIPTION = "Timeline and feasibility of recruiting two specialists within the nine-month window";
|
||||
const CANONICAL_LABEL = "Timeline and feasibility of recruiting two specialists within the nine-month window";
|
||||
|
||||
// 1. The selected node returns the exact canonical description
|
||||
const result = extractFocusedTargetInput(testGraph, "n2yzwlv");
|
||||
assert(result.targetDescription === CANONICAL_DESCRIPTION, "Assert 1: known node returns exact canonical description");
|
||||
assert(result.targetLabel === CANONICAL_LABEL, "Assert 2: known node label preserved exactly");
|
||||
|
||||
// 3. An unknown node ID returns the existing empty-string fallbacks
|
||||
const unknownResult = extractFocusedTargetInput(testGraph, "nonexistent-node-id");
|
||||
assert(unknownResult.targetDescription === "", "Assert 3a: unknown node description is empty string fallback");
|
||||
assert(unknownResult.targetLabel === "", "Assert 3b: unknown node label is empty string fallback");
|
||||
|
||||
// 4. The graph is not mutated by the extraction
|
||||
const nodesBefore = testGraph.nodes.map(n => n.id);
|
||||
extractFocusedTargetInput(testGraph, "n2yzwlv");
|
||||
extractFocusedTargetInput(testGraph, "nonexistent-node-id");
|
||||
const nodesAfter = testGraph.nodes.map(n => n.id);
|
||||
assert(JSON.stringify(nodesBefore) === JSON.stringify(nodesAfter),
|
||||
"Assert 4: graph not mutated by extraction (node ids unchanged)");
|
||||
|
||||
// 5. The focused-deconstruction branch uses the extracted function (source-pattern assertion, preserved from T3)
|
||||
const helperSrc3 = readFileSync("./tests/graph/live-update-experiment-helper.cjs", "utf8");
|
||||
assert(helperSrc3.includes("extractFocusedTargetInput(situationGraph, targetNodeId)"),
|
||||
"Assert 5: focused-deconstruction path calls extractFocusedTargetInput (extraction integration verified)");
|
||||
|
||||
// 6. Existing question/answer handling remains unchanged (source-pattern assertion from existing tests preserved)
|
||||
assert(helperSrc3.includes("previousQuestion ?? \"\"") || helperSrc3.includes("previousQuestion ?? ''"),
|
||||
"Assert 6: question handling with previousQuestion ?? fallback still present");
|
||||
assert(helperSrc3.includes('focusedInvestigationInput:') && helperSrc3.includes('answer'),
|
||||
"Assert 6b: focusedInvestigationInput field still carries answer in returned checkpoint");
|
||||
|
||||
console.log("\n=== EXTRACT FOCUSED TARGET INPUT — DETERMINISTIC TEST COMPLETE — ALL ASSERTIONS PASSED ===\n");
|
||||
}
|
||||
|
||||
// ---- SYNTHETIC TESTS WITH FAKE PROVIDER (Batch 3 Iteration 1) ────────────
|
||||
// Tests synthesizeCurrentUnderstanding directly with DI-injected fake providers.
|
||||
// Zero live calls — provider.generateReconstruction returns synchronously.
|
||||
|
||||
@@ -331,10 +331,9 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues
|
||||
/* ── Load production deconstruction seam (dynamic import to resolve ESM path aliases) ─── */
|
||||
const { focusedDeconstruct } = await import("../../lib/graph/focused-investigation.js");
|
||||
|
||||
// Extract node context for deconstruction prompt
|
||||
const targetNode = situationGraph.nodes.find(n => n.id === targetNodeId);
|
||||
const targetLabel = targetNode?.label ?? "";
|
||||
targetDescription = targetNode?.description ?? "";
|
||||
// Extract node context for deconstruction prompt (reuses pure extraction function)
|
||||
const { targetLabel, targetDescription: _td } = extractFocusedTargetInput(situationGraph, targetNodeId);
|
||||
targetDescription = _td;
|
||||
const centralStatement = situationGraph.centralStatement ?? "";
|
||||
|
||||
// Call production-focused deconstruct — exactly one provider generation
|
||||
@@ -677,4 +676,26 @@ function saveFocusedInvestigationEvidence(checkpoint, identity, metadata, output
|
||||
return { output_path: outputPath, verifiedEvidence: recovered };
|
||||
}
|
||||
|
||||
module.exports = { runLiveExperiment, extractLiveExperimentCheckpoint, _extractReasoningState, composeDeepInvestigationCheckpoint, serializeFocusedInvestigationEvidence, saveFocusedInvestigationEvidence };
|
||||
/**
|
||||
* Extract the focused-investigation target-node input (label and description)
|
||||
* from a situationGraph by node id.
|
||||
*
|
||||
* Pure function — no side effects, no I/O, no model calls.
|
||||
* Mirrors exactly the lookup and fallback semantics used inside the
|
||||
* guarded focused-deconstruction path of composeDeepInvestigationCheckpoint:
|
||||
* - situationGraph.nodes.find(n => n.id === targetNodeId)
|
||||
* - ?? "" (empty-string fallback when node not found)
|
||||
*
|
||||
* @param {object} situationGraph — SituationGraph input containing { nodes, centralStatement? }
|
||||
* @param {string} targetNodeId — id of the focused-investigation target node
|
||||
* @returns {{ targetLabel: string, targetDescription: string }}
|
||||
*/
|
||||
function extractFocusedTargetInput(situationGraph, targetNodeId) {
|
||||
const targetNode = situationGraph.nodes.find(n => n.id === targetNodeId);
|
||||
return {
|
||||
targetLabel: targetNode?.label ?? "",
|
||||
targetDescription: targetNode?.description ?? "",
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { runLiveExperiment, extractLiveExperimentCheckpoint, _extractReasoningState, composeDeepInvestigationCheckpoint, serializeFocusedInvestigationEvidence, saveFocusedInvestigationEvidence, extractFocusedTargetInput };
|
||||
|
||||
Reference in New Issue
Block a user