From 44db12d9c0ae447a2abcc59445c1aedcc8f31dd4 Mon Sep 17 00:00:00 2001 From: robbond Date: Wed, 7 Oct 2026 07:25:52 +0100 Subject: [PATCH] test(confidence-engine): forward deep provider schemas --- ...date-experiment-helper-checkpoint.test.cjs | 52 +++++++++++++++++++ tests/graph/live-update-experiment-helper.cjs | 12 ++--- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/tests/graph/live-update-experiment-helper-checkpoint.test.cjs b/tests/graph/live-update-experiment-helper-checkpoint.test.cjs index ea95891..676b790 100644 --- a/tests/graph/live-update-experiment-helper-checkpoint.test.cjs +++ b/tests/graph/live-update-experiment-helper-checkpoint.test.cjs @@ -410,6 +410,58 @@ assert(helperSrc.includes("updatedSituationGraph: updatedGraph"), "next graph re // D12. Next Contributions/Findings returned for Episode N+1 assert(helperSrc.includes("postEpisodeContributions") && helperSrc.includes("postEpisodeFindings"), "next Contributions and Findings returned for longitudinal tracking"); +// ---- WRAPPER FORWARDING VERIFICATION (Iteration 3 — NEW) ────────────── +// These assertions verify that the timedProvider wrapper correctly forwards +// all provider arguments (prompt, modelName, outputSchema) to the underlying provider. + +// W1. Both runLiveExperiment and composeDeepInvestigationCheckpoint timedProviders forward a third argument +const timingWrapperMatches = helperSrc.match(/async generateReconstruction\(prompt,\s*modelName,\s*outputSchema\)/g); +assert(timingWrapperMatches !== null && timingWrapperMatches.length === 2, "exactly two timedProvider wrappers forward outputSchema (3-param signature)"); + +// W2. Both wrappers invoke the underlying provider with the forwarded third argument +const forwardCallMatches = helperSrc.match(/await provider\.generateReconstruction\(prompt,\s*modelName,\s*outputSchema\)/g); +assert(forwardCallMatches !== null && forwardCallMatches.length === 2, "exactly two timedProvider invocations forward all three arguments"); + +// W3. focusedDeconstruct receives timedProvider (not raw provider) +assert(helperSrc.includes("provider: timedProvider") || helperSrc.includes("provider : timedProvider"), "focusedDeconstruct receives timedProvider (wrapped) not raw provider"); + +// W4. No manual compensation increment for focusedDeconstruction exists +assert(!helperSrc.includes("focusedDeconstruct now uses the same provider") && !helperSrc.includes("focused_deconstruct now uses the same provider"), "no manual compensation increment present in helper source"); + +// W5. synthesizeCurrentUnderstanding receives timedProvider (not raw provider) +const synthSection = helperSrc.substring(helperSrc.indexOf("synthesizeCurrentUnderstanding")); +assert(synthSection.includes("provider: timedProvider") || synthSection.includes("provider : timedProvider"), "CU synthesis receives timedProvider in composeDeepInvestigationCheckpoint"); + +// W6. focused deconstruction schema assertion — focusedDeconstructJsonSchema is passed as 3rd arg +const focusedDeconstructImport = helperSrc.indexOf('import("../../lib/graph/focused-investigation.js")'); +const focusedCallStart = helperSrc.indexOf("focusedDeconstruct(", focusedDeconstructImport); +// W6. focused deconstruction uses focusedDeconstructJsonSchema (verified in production module) +const fiModuleSrc = readFileSync("./lib/graph/focused-investigation.js", "utf8"); +assert(fiModuleSrc.includes("export const focusedDeconstructJsonSchema") && fiModuleSrc.includes("generateReconstruction"), "focused deconstruction schema exported and used in production module"); + +// W7. CU synthesis schema — synthesizeCurrentUnderstanding passes synthesisOutputSchema as 3rd arg +const synthModuleSrc = readFileSync("./lib/graph/current-understanding-synthesis.js", "utf8"); +assert(synthModuleSrc.includes("generateReconstruction") && synthModuleSrc.includes("synthesisOutputSchema"), "CU synthesis source uses synthesisOutputSchema in provider call"); + +// ---- APPARATUS CORRECTION VERIFICATION ────────────────────────────── +// These assertions verify the apparatus is correct after the fix: +// - All three calls (focusedDeconstruct, CU synthesis) use timedProvider +// - No manual counter compensation exists +// - Schema forwarding is complete in both wrappers + +// AC1. Verify focusedDeconstruct receives timedProvider in the non-episode path too +const updateCasePath = helperSrc.substring( + helperSrc.indexOf("else {"), + helperSrc.indexOf("const endToEndElapsedMs") +); +assert(updateCasePath.includes("provider: timedProvider") || updateCasePath.includes("provider : timedProvider"), "non-episode updateCase path uses timedProvider"); + +// AC2. Compose function still callable (state continuity preserved) +assert(typeof composeDeepInvestigationCheckpoint === "function", "composeDeepInvestigationCheckpoint remains callable (state continuity)"); + +// AC3. The helper structure is intact — no production code was rewritten +assert(helperSrc.includes("const provider = getProvider()") && helperSrc.includes("const timedProvider = {"), "helper still creates both raw provider and timedWrapper (architecture preserved)"); + // ---- CU SYNTHESIS OBSERVABILITY (Batch 3 Iteration 1) ───────────────────── console.log("\n=== CU SYNTHESIS OBSERVABILITY ===\n"); diff --git a/tests/graph/live-update-experiment-helper.cjs b/tests/graph/live-update-experiment-helper.cjs index 160f30b..446fb04 100644 --- a/tests/graph/live-update-experiment-helper.cjs +++ b/tests/graph/live-update-experiment-helper.cjs @@ -194,10 +194,10 @@ async function runLiveExperiment({ graph, previousQuestion, answer, findings = [ let providerGenerateCalls = 0; const timedProvider = { - async generateReconstruction(prompt, modelName) { + async generateReconstruction(prompt, modelName, outputSchema) { providerGenerateCalls++; const startedAt = Date.now(); - const response = await provider.generateReconstruction(prompt, modelName); + const response = await provider.generateReconstruction(prompt, modelName, outputSchema); modelElapsedMs = Date.now() - startedAt; return response; }, @@ -299,10 +299,10 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues let providerGenerateCalls = 0; const timedProvider = { - async generateReconstruction(prompt, modelName) { + async generateReconstruction(prompt, modelName, outputSchema) { providerGenerateCalls++; const startedAt = Date.now(); - const response = await provider.generateReconstruction(prompt, modelName); + const response = await provider.generateReconstruction(prompt, modelName, outputSchema); modelElapsedMs = Date.now() - startedAt; return response; }, @@ -332,7 +332,7 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues // Call production-focused deconstruct — exactly one provider generation const focused = await focusedDeconstruct({ - provider, + provider: timedProvider, modelName: model, targetNodeId, targetLabel, @@ -342,8 +342,6 @@ async function composeDeepInvestigationCheckpoint({ situationGraph, previousQues answer, }); - providerGenerateCalls++; // focusedDeconstruct now uses the same provider (1 call) - if (!focused.success) { throw new Error(`focusedDeconstruct failed for episode ${contribSeq}: ${JSON.stringify(focused.errors)}`); }