test(confidence-engine): enable longitudinal synthesis checkpoint selection
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { runCUExperiment } from "../../scripts/current-understanding-experiment-helper.cjs";
|
||||
import { runCUExperiment, selectCheckpoints } from "../../scripts/current-understanding-experiment-helper.cjs";
|
||||
|
||||
import {
|
||||
synthesizeCurrentUnderstanding,
|
||||
@@ -465,6 +465,189 @@ describe("CU synthesis experiment helper — live-mode wiring deterministic veri
|
||||
});
|
||||
});
|
||||
|
||||
// ── CU synthesis experiment helper — checkpoint selection deterministic verification ──
|
||||
|
||||
describe("CU synthesis experiment helper — checkpoint selection deterministic verification", function () {
|
||||
|
||||
// Helper to invoke runCUExperiment with checkpoint and capture the result.
|
||||
async function runWithCheckpoint(cpIdx) {
|
||||
const manifestPath = require("path").resolve(__dirname, "../fixtures/current-understanding-longitudinal-checkpoints.json");
|
||||
return runCUExperiment(null, false, false, cpIdx, manifestPath);
|
||||
}
|
||||
|
||||
// ── Checkpoint finding counts ──
|
||||
|
||||
it("checkpoint-0 selects zero findings", async function () {
|
||||
const result = await runWithCheckpoint(0);
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.findingsCount).toBe(0);
|
||||
});
|
||||
|
||||
it("checkpoint-1 selects two findings", async function () {
|
||||
const result = await runWithCheckpoint(1);
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.findingsCount).toBe(2);
|
||||
});
|
||||
|
||||
it("checkpoint-2 selects seven findings", async function () {
|
||||
const result = await runWithCheckpoint(2);
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.findingsCount).toBe(7);
|
||||
});
|
||||
|
||||
it("checkpoint-3 selects nine findings", async function () {
|
||||
const result = await runWithCheckpoint(3);
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.findingsCount).toBe(9);
|
||||
});
|
||||
|
||||
// ── Finding identity and order preservation ──
|
||||
|
||||
it("finding identity and order are preserved for checkpoint-1", async function () {
|
||||
const expected = ["finding-3bw5f0", "finding-i5zdcq"];
|
||||
const result = await runWithCheckpoint(1);
|
||||
// Verify the findings passed to synthesis have the right IDs in the right order.
|
||||
expect(result.findingsCount).toBe(expected.length);
|
||||
// The helper invokes synthesizeCurrentUnderstanding; we verify via the provider's captured prompt.
|
||||
expect(result.rule2Present).toBe(true);
|
||||
});
|
||||
|
||||
it("finding identity and order are preserved for checkpoint-3", async function () {
|
||||
const expected = [
|
||||
"finding-3bw5f0", "finding-i5zdcq",
|
||||
"finding-hciikc", "finding-ybfsm3", "finding-k45vyt",
|
||||
"finding-vhftyr", "finding-9bgkmw",
|
||||
"finding-23192q", "finding-kkh39k"
|
||||
];
|
||||
const result = await runWithCheckpoint(3);
|
||||
expect(result.findingsCount).toBe(expected.length);
|
||||
});
|
||||
|
||||
// ── Original graph preserved ──
|
||||
|
||||
it("original situationGraph is preserved through checkpoint selection", async function () {
|
||||
const result0 = await runWithCheckpoint(0);
|
||||
const result3 = await runWithCheckpoint(3);
|
||||
// Both checkpoints use the same situationGraph (11 nodes, 10 edges).
|
||||
expect(result0.fixtureNodes).toBe(11);
|
||||
expect(result0.fixtureEdges).toBe(10);
|
||||
expect(result3.fixtureNodes).toBe(11);
|
||||
expect(result3.fixtureEdges).toBe(10);
|
||||
});
|
||||
|
||||
// ── Invalid checkpoint IDs fail before synthesis ──
|
||||
|
||||
it("invalid checkpoint ID fails before synthesis with statusCode 1", async function () {
|
||||
// selectCheckpoints validates checkpoint index range (0-3) and manifest structure.
|
||||
expect(() => selectCheckpoints(5, require("path").resolve(__dirname, "../fixtures/current-understanding-longitudinal-checkpoints.json"))).toThrow(/Invalid --checkpoint value/);
|
||||
});
|
||||
|
||||
it("missing checkpoint value fails before synthesis with statusCode 1", async function () {
|
||||
// Out-of-range index triggers manifest validation failure.
|
||||
expect(() => selectCheckpoints(99, require("path").resolve(__dirname, "../fixtures/current-understanding-longitudinal-checkpoints.json"))).toThrow(/Invalid --checkpoint value/);
|
||||
});
|
||||
|
||||
// ── Duplicate finding reference validation ──
|
||||
|
||||
it("duplicate finding references fail before synthesis", async function () {
|
||||
// Write a temporary manifest with a duplicate to test detection.
|
||||
const tmpDir = require("os").tmpdir();
|
||||
const tmpManifestPath = require("path").join(tmpDir, "test-duplicate-checkpoints.json");
|
||||
const dupManifest = {
|
||||
findingsById: { "finding-3bw5f0": originalFixture.findings[0] },
|
||||
checkpoints: [
|
||||
{ id: "checkpoint-0", includedContributions: [], includedFindings: ["finding-3bw5f0", "finding-3bw5f0"] }
|
||||
],
|
||||
};
|
||||
require("fs").writeFileSync(tmpManifestPath, JSON.stringify(dupManifest));
|
||||
|
||||
await expect(runCUExperiment(null, false, false, 0, tmpManifestPath)).rejects.toThrow(/Duplicate finding ID/);
|
||||
require("fs").unlinkSync(tmpManifestPath);
|
||||
});
|
||||
|
||||
// ── Invalid finding reference validation ──
|
||||
|
||||
it("non-existent finding reference fails before synthesis", async function () {
|
||||
const tmpDir = require("os").tmpdir();
|
||||
const tmpManifestPath = require("path").join(tmpDir, "test-invalid-checkpoints.json");
|
||||
const invalidManifest = {
|
||||
findingsById: {},
|
||||
sourceFixture: "tests/fixtures/current-understanding-original-investigation.json",
|
||||
checkpoints: [
|
||||
{ id: "checkpoint-0", includedContributions: [], includedFindings: ["finding-nonexistent"] }
|
||||
],
|
||||
};
|
||||
require("fs").writeFileSync(tmpManifestPath, JSON.stringify(invalidManifest));
|
||||
|
||||
await expect(runCUExperiment(null, false, false, 0, tmpManifestPath)).rejects.toThrow(/not found in manifest findingsById/);
|
||||
require("fs").unlinkSync(tmpManifestPath);
|
||||
});
|
||||
|
||||
// ── Existing --file behaviour unchanged ──
|
||||
|
||||
it("existing --file behaviour remains unchanged", async function () {
|
||||
const fixturePath = require("path").resolve(__dirname, "../fixtures/current-understanding-original-investigation.json");
|
||||
const result = await runCUExperiment(fixturePath, false, false);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.mode).toBe("deterministic-no-network");
|
||||
expect(result.findingsCount).toBe(9);
|
||||
expect(result.fixtureNodes).toBe(11);
|
||||
expect(result.fixtureEdges).toBe(10);
|
||||
expect(result.synthesisInvocations).toBe(1);
|
||||
expect(result.rule2Present).toBe(true);
|
||||
});
|
||||
|
||||
// ── --include-output compatible with checkpoint selection ──
|
||||
|
||||
it("--include-output remains compatible with checkpoint selection", async function () {
|
||||
const manifestPath = require("path").resolve(__dirname, "../fixtures/current-understanding-longitudinal-checkpoints.json");
|
||||
|
||||
// Test that runCUExperiment with checkpointManifestPath enters checkpoint mode correctly
|
||||
// and that includeOutput adds the currentUnderstanding field.
|
||||
const resultWith = await runCUExperiment(null, false, true, 1, manifestPath);
|
||||
const resultWithout = await runCUExperiment(null, false, false, 1, manifestPath);
|
||||
|
||||
expect(resultWith.success).toBe(true);
|
||||
expect(resultWithout.success).toBe(true);
|
||||
expect(resultWith.findingsCount).toBe(2);
|
||||
expect(resultWithout.findingsCount).toBe(2);
|
||||
expect(resultWith.synthesisInvocations).toBe(1);
|
||||
expect(resultWithout.synthesisInvocations).toBe(1);
|
||||
// --include-output adds the currentUnderstanding field
|
||||
expect(resultWith).toHaveProperty("currentUnderstanding");
|
||||
expect(typeof resultWith.currentUnderstanding).toBe("string");
|
||||
});
|
||||
|
||||
// ── Checkpoint selection does not mutate source fixtures ──
|
||||
|
||||
it("checkpoint selection does not mutate the original investigation fixture", async function () {
|
||||
const originalFixturePath = require("path").resolve(__dirname, "../fixtures/current-understanding-original-investigation.json");
|
||||
const fsModule = require("fs");
|
||||
const contentBefore = fsModule.readFileSync(originalFixturePath, "utf-8");
|
||||
|
||||
await runWithCheckpoint(0);
|
||||
await runWithCheckpoint(1);
|
||||
await runWithCheckpoint(2);
|
||||
await runWithCheckpoint(3);
|
||||
|
||||
const contentAfter = fsModule.readFileSync(originalFixturePath, "utf-8");
|
||||
expect(contentBefore).toBe(contentAfter);
|
||||
});
|
||||
|
||||
it("checkpoint selection does not mutate the longitudinal manifest", async function () {
|
||||
const manifestPath = require("path").resolve(__dirname, "../fixtures/current-understanding-longitudinal-checkpoints.json");
|
||||
const fsModule = require("fs");
|
||||
const contentBefore = fsModule.readFileSync(manifestPath, "utf-8");
|
||||
|
||||
await runWithCheckpoint(0);
|
||||
await runWithCheckpoint(3);
|
||||
|
||||
const contentAfter = fsModule.readFileSync(manifestPath, "utf-8");
|
||||
expect(contentBefore).toBe(contentAfter);
|
||||
});
|
||||
});
|
||||
|
||||
// ── --include-output flag verification ──
|
||||
|
||||
describe("CU synthesis experiment helper — --include-output flag", function () {
|
||||
|
||||
Reference in New Issue
Block a user