1236 lines
41 KiB
JavaScript
1236 lines
41 KiB
JavaScript
/**
|
|
* Deterministic verification of the focused-deconstruct experiment helper.
|
|
*
|
|
* Zero live calls. Uses injected fake provider for complete isolation.
|
|
*/
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import { buildFocusedDeconstructPrompt, validateFocusedDeconstructSchema } from "@/lib/graph/focused-investigation.js";
|
|
import { runLiveFocusedDeconstructExperiment, runLiveFocusedPromptExperiment, runLiveFocusedFrontierPromptExperiment, runLiveFocusedObservationFrontierPromptExperiment, runLiveFocusedRelationshipFrontierPromptExperiment, runLiveFocusedAssumptionFrontierPromptExperiment, runLiveFocusedObservationAssumptionFrontierPromptExperiment } from "./live-focused-deconstruct-experiment-helper.mjs";
|
|
|
|
// Minimum env for the helper's OLLAMA_MODEL guard (never contacts a real model)
|
|
process.env.OLLAMA_MODEL = "test-model";
|
|
|
|
// ── env-loading verification ───────────────────────────────────────────
|
|
|
|
describe("environment loading", () => {
|
|
it("helper loads .env.local before any function executes", async () => {
|
|
// The helper already ran dotenv.config({ path: ".env.local" }) at import time.
|
|
// If OLLAMA_MODEL was configured in .env.local, the module-level guard would see it.
|
|
// If not, the test below explicitly sets it — so this test validates the chain works.
|
|
// We verify by confirming no unhandled "not set in environment" error propagates
|
|
// when we invoke through the helper with a safe injected provider.
|
|
const fakeResult = makeValidResult({ targetNodeId: "env-verify-node" });
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedDeconstructExperiment({
|
|
...params,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.targetNodeId).toBe(params.targetNodeId);
|
|
});
|
|
});
|
|
|
|
// ── fixture ────────────────────────────────────────────────────────────
|
|
|
|
const params = {
|
|
targetNodeId: "test-node-01",
|
|
targetLabel: "Team capability constraints on task handoff boundaries",
|
|
targetDescription:
|
|
"The extent to which current skill levels and bandwidth dictate the limit of delegable tasks.",
|
|
centralStatement:
|
|
"A business owner seeks to delegate routine operational tasks but lacks clarity on scope.",
|
|
question: "What was the comparable state before capability constraints?",
|
|
answer: "She handles weekly supplier payments herself without checking for six months.",
|
|
};
|
|
|
|
const suppliedPrompt = "EXACT_PROMPT_CONTENT_BYTE_IDENTICAL";
|
|
|
|
// ── fake provider builder ──────────────────────────────────────────────
|
|
|
|
function makeFakeProvider(result) {
|
|
const calls = [];
|
|
return {
|
|
generateReconstruction: async (prompt, model) => {
|
|
calls.push({ prompt, model });
|
|
if (result instanceof Error) throw result;
|
|
return result;
|
|
},
|
|
getCalls: () => calls,
|
|
};
|
|
}
|
|
|
|
// ── valid deconstruct result fixture ───────────────────────────────────
|
|
|
|
function makeValidResult(extraFields = {}) {
|
|
return {
|
|
targetNodeId: "injected-node",
|
|
observations: ["obs-1"],
|
|
uncertainties: ["unc-1"],
|
|
assumptions: [],
|
|
relationships: [],
|
|
possibleFollowUpQuestions: ["q-1"],
|
|
...extraFields,
|
|
};
|
|
}
|
|
|
|
// ── existing API ────────────────────────────────────────────────────────
|
|
|
|
describe("runLiveFocusedDeconstructExperiment", () => {
|
|
it("produces a validated structured result through an injected fake provider", async () => {
|
|
const fakeResult = makeValidResult({ targetNodeId: "injected-node" });
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedDeconstructExperiment({
|
|
...params,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.targetNodeId).toBe(params.targetNodeId);
|
|
expect(result.observations).toEqual(fakeResult.observations);
|
|
expect(result.uncertainties).toEqual(fakeResult.uncertainties);
|
|
expect(result.assumptions).toEqual(fakeResult.assumptions);
|
|
expect(result.relationships).toEqual(fakeResult.relationships);
|
|
expect(result.possibleFollowUpQuestions).toEqual(fakeResult.possibleFollowUpQuestions);
|
|
expect(result.elapsedMs).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it("passes invalid result to schema validation and fails", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
targetNodeId: "injected-node",
|
|
// missing required fields — will fail validation
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedDeconstructExperiment({
|
|
...params,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("Focused deconstruction result did not match expected schema");
|
|
});
|
|
|
|
it("propagates provider exception without retry", async () => {
|
|
const err = new Error("network failure");
|
|
const calls = [];
|
|
const fakeProvider = {
|
|
generateReconstruction: async (prompt, model) => {
|
|
calls.push(1);
|
|
throw err;
|
|
},
|
|
};
|
|
|
|
await expect(
|
|
runLiveFocusedDeconstructExperiment({
|
|
...params,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toBe(err);
|
|
});
|
|
});
|
|
|
|
// ── new supplied-prompt API ────────────────────────────────────────────
|
|
|
|
describe("runLiveFocusedPromptExperiment", () => {
|
|
it("passes an arbitrary supplied prompt byte-for-byte to the injected provider", async () => {
|
|
const fakeResult = makeValidResult({ targetNodeId: "supplied-node" });
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
await runLiveFocusedPromptExperiment({
|
|
prompt: suppliedPrompt,
|
|
targetNodeId: "supplied-node",
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
const calls = fakeProvider.getCalls();
|
|
expect(calls.length).toBe(1);
|
|
expect(calls[0].prompt).toBe(suppliedPrompt);
|
|
});
|
|
|
|
it("returns the same structured result shape as existing API", async () => {
|
|
const fakeResult = makeValidResult({ targetNodeId: "supplied-node" });
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedPromptExperiment({
|
|
prompt: suppliedPrompt,
|
|
targetNodeId: "supplied-node",
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.targetNodeId).toBe("supplied-node");
|
|
expect(result.observations).toEqual(fakeResult.observations);
|
|
expect(result.uncertainties).toEqual(fakeResult.uncertainties);
|
|
expect(result.assumptions).toEqual(fakeResult.assumptions);
|
|
expect(result.relationships).toEqual(fakeResult.relationships);
|
|
expect(result.possibleFollowUpQuestions).toEqual(fakeResult.possibleFollowUpQuestions);
|
|
expect(result.elapsedMs).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it("passes invalid result to schema validation and fails", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
targetNodeId: "supplied-node",
|
|
// missing required fields — will fail validation
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedPromptExperiment({
|
|
prompt: suppliedPrompt,
|
|
targetNodeId: "supplied-node",
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("Focused deconstruction result did not match expected schema");
|
|
});
|
|
|
|
it("propagates provider exception without retry", async () => {
|
|
const err = new Error("network failure");
|
|
const calls = [];
|
|
const fakeProvider = {
|
|
generateReconstruction: async (prompt, model) => {
|
|
calls.push(1);
|
|
throw err;
|
|
},
|
|
};
|
|
|
|
await expect(
|
|
runLiveFocusedPromptExperiment({
|
|
prompt: suppliedPrompt,
|
|
targetNodeId: "supplied-node",
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toBe(err);
|
|
});
|
|
});
|
|
|
|
// ── frontier runner (EXP37 minimal two-field contract) ─────────────────
|
|
|
|
const FRONTIER_PROMPT = "EXACT_FRONTIER_TEST_PROMPT_BYTE_IDENTICAL";
|
|
|
|
function makeMinimalFrontierResult() {
|
|
return {
|
|
uncertainties: ["What is still unknown?"],
|
|
possibleFollowUpQuestions: ["What happened in the failed cases?"],
|
|
};
|
|
}
|
|
|
|
describe("runLiveFocusedFrontierPromptExperiment", () => {
|
|
it("passes prompt byte-for-byte to the injected provider", async () => {
|
|
const fakeResult = makeMinimalFrontierResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
await runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
const calls = fakeProvider.getCalls();
|
|
expect(calls.length).toBe(1);
|
|
expect(calls[0].prompt).toBe(FRONTIER_PROMPT);
|
|
});
|
|
|
|
it("accepts valid minimal result", async () => {
|
|
const fakeResult = makeMinimalFrontierResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.uncertainties).toEqual(["What is still unknown?"]);
|
|
expect(result.possibleFollowUpQuestions).toEqual(["What happened in the failed cases?"]);
|
|
expect(result.elapsedMs).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it("rejects empty uncertainties array", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
uncertainties: [],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects uncertainties array with two elements", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
uncertainties: ["one", "two"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects missing uncertainties", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must be an array");
|
|
});
|
|
|
|
it("rejects empty possibleFollowUpQuestions array", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: [],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
it("rejects possibleFollowUpQuestions array with two elements", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["q1", "q2"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
it("rejects missing possibleFollowUpQuestions", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
uncertainties: ["one uncertainty"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must be an array");
|
|
});
|
|
|
|
it("propagates provider exception without retry", async () => {
|
|
const err = new Error("provider failure");
|
|
const calls = [];
|
|
const fakeProvider = {
|
|
generateReconstruction: async (prompt, model) => {
|
|
calls.push(1);
|
|
throw err;
|
|
},
|
|
};
|
|
|
|
await expect(
|
|
runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toBe(err);
|
|
});
|
|
|
|
it("does not require full-deconstruction fields", async () => {
|
|
const fakeResult = makeMinimalFrontierResult();
|
|
// No targetNodeId, observations, assumptions, or relationships present
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect("targetNodeId" in result).toBe(false);
|
|
expect("observations" in result).toBe(false);
|
|
expect("assumptions" in result).toBe(false);
|
|
expect("relationships" in result).toBe(false);
|
|
});
|
|
});
|
|
|
|
// ── observation-frontier runner (EXP38 three-field contract) ─────────────
|
|
|
|
const OBSERVATION_FRONTIER_TEST_PROMPT = "OBSERVATION FRONTIER TEST PROMPT";
|
|
|
|
function makeObservationFrontierResult() {
|
|
return {
|
|
observations: [
|
|
"She handles weekly supplier payments herself.",
|
|
"Failed or unusual payments come back to the owner.",
|
|
],
|
|
uncertainties: ["What is different about the failed or unusual payments?"],
|
|
possibleFollowUpQuestions: [
|
|
"What is different about the failed or unusual payments that means they come back to you?",
|
|
],
|
|
};
|
|
}
|
|
|
|
describe("runLiveFocusedObservationFrontierPromptExperiment", () => {
|
|
it("passes prompt byte-for-byte to the injected provider", async () => {
|
|
const fakeResult = makeObservationFrontierResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
await runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
const calls = fakeProvider.getCalls();
|
|
expect(calls.length).toBe(1);
|
|
expect(calls[0].prompt).toBe(OBSERVATION_FRONTIER_TEST_PROMPT);
|
|
});
|
|
|
|
it("accepts valid three-field result", async () => {
|
|
const fakeResult = makeObservationFrontierResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.observations).toEqual(fakeResult.observations);
|
|
expect(result.uncertainties).toEqual(fakeResult.uncertainties);
|
|
expect(result.possibleFollowUpQuestions).toEqual(fakeResult.possibleFollowUpQuestions);
|
|
expect(result.elapsedMs).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it("rejects empty observations array", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("observations must contain at least one element");
|
|
});
|
|
|
|
it("rejects non-string observation element", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["valid", "also valid", 123],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("observations[2] must be a non-empty string");
|
|
});
|
|
|
|
it("rejects zero uncertainties", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["obs-1"],
|
|
uncertainties: [],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects two uncertainties", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["obs-1"],
|
|
uncertainties: ["one", "two"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects zero possibleFollowUpQuestions", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["obs-1"],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: [],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
it("rejects two possibleFollowUpQuestions", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["obs-1"],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["q1", "q2"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
it("does not require assumptions, relationships, or targetNodeId", async () => {
|
|
const result = makeObservationFrontierResult();
|
|
// Ensure no extra fields
|
|
delete result.assumptions;
|
|
delete result.relationships;
|
|
delete result.targetNodeId;
|
|
|
|
const fakeProvider = makeFakeProvider(result);
|
|
|
|
const run = await runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(run.success).toBe(true);
|
|
});
|
|
|
|
it("propagates provider exception without retry", async () => {
|
|
const err = new Error("provider failure");
|
|
const calls = [];
|
|
const fakeProvider = {
|
|
generateReconstruction: async (prompt, model) => {
|
|
calls.push(1);
|
|
throw err;
|
|
},
|
|
};
|
|
|
|
await expect(
|
|
runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toBe(err);
|
|
});
|
|
});
|
|
|
|
// ── relationship-frontier runner (EXP44 three-field contract with relationships) ─────────────
|
|
|
|
const RELATIONSHIP_FRONTIER_TEST_PROMPT = "RELATIONSHIP FRONTIER TEST PROMPT";
|
|
|
|
function makeRelationshipFrontierResult() {
|
|
return {
|
|
relationships: [
|
|
"She handles weekly supplier payments herself.",
|
|
"Failed or unusual payments come back to the owner.",
|
|
],
|
|
uncertainties: ["What is different about the failed or unusual payments?"],
|
|
possibleFollowUpQuestions: [
|
|
"What is different about the failed or unusual payments that means they come back to you?",
|
|
],
|
|
};
|
|
}
|
|
|
|
describe("runLiveFocusedRelationshipFrontierPromptExperiment", () => {
|
|
it("passes prompt byte-for-byte to the injected provider", async () => {
|
|
const fakeResult = makeRelationshipFrontierResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
await runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
const calls = fakeProvider.getCalls();
|
|
expect(calls.length).toBe(1);
|
|
expect(calls[0].prompt).toBe(RELATIONSHIP_FRONTIER_TEST_PROMPT);
|
|
});
|
|
|
|
it("accepts valid relationship-frontier result", async () => {
|
|
const fakeResult = makeRelationshipFrontierResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.relationships).toEqual(fakeResult.relationships);
|
|
expect(result.uncertainties).toEqual(fakeResult.uncertainties);
|
|
expect(result.possibleFollowUpQuestions).toEqual(fakeResult.possibleFollowUpQuestions);
|
|
expect(result.elapsedMs).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it("rejects empty relationships array", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
relationships: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("relationships must contain at least one element");
|
|
});
|
|
|
|
it("rejects non-string relationship element", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
relationships: ["valid", 123],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("relationships[1] must be a non-empty string");
|
|
});
|
|
|
|
it("rejects zero uncertainties", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
relationships: ["rel-1"],
|
|
uncertainties: [],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects two uncertainties", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
relationships: ["rel-1"],
|
|
uncertainties: ["one", "two"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects zero possibleFollowUpQuestions", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
relationships: ["rel-1"],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: [],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
it("rejects two possibleFollowUpQuestions", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
relationships: ["rel-1"],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["q1", "q2"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
it("does not require observations, assumptions, or targetNodeId", async () => {
|
|
const result = makeRelationshipFrontierResult();
|
|
// Ensure no extra fields
|
|
delete result.observations;
|
|
delete result.assumptions;
|
|
delete result.targetNodeId;
|
|
|
|
const fakeProvider = makeFakeProvider(result);
|
|
|
|
const run = await runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(run.success).toBe(true);
|
|
});
|
|
|
|
it("propagates provider exception without retry", async () => {
|
|
const err = new Error("provider failure");
|
|
const calls = [];
|
|
const fakeProvider = {
|
|
generateReconstruction: async (prompt, model) => {
|
|
calls.push(1);
|
|
throw err;
|
|
},
|
|
};
|
|
|
|
await expect(
|
|
runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toBe(err);
|
|
});
|
|
});
|
|
|
|
// ── assumption-frontier runner (EXP45) ─────────────────────────────────
|
|
|
|
const ASSUMPTION_FRONTIER_TEST_PROMPT = "ASSUMPTION FRONTIER TEST PROMPT";
|
|
|
|
function makeAssumptionFrontierResultWithNoAssumptions() {
|
|
return {
|
|
assumptions: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
};
|
|
}
|
|
|
|
function makeAssumptionFrontierResultWithOneAssumption() {
|
|
return {
|
|
assumptions: ["one genuinely attributable assumption"],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
};
|
|
}
|
|
|
|
describe("runLiveFocusedAssumptionFrontierPromptExperiment", () => {
|
|
it("passes prompt byte-for-byte to the injected provider", async () => {
|
|
const fakeResult = makeAssumptionFrontierResultWithOneAssumption();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
await runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
const calls = fakeProvider.getCalls();
|
|
expect(calls.length).toBe(1);
|
|
expect(calls[0].prompt).toBe(ASSUMPTION_FRONTIER_TEST_PROMPT);
|
|
});
|
|
|
|
it("accepts valid result with no assumptions", async () => {
|
|
const fakeResult = makeAssumptionFrontierResultWithNoAssumptions();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.assumptions).toEqual([]);
|
|
expect(result.uncertainties).toEqual(["one uncertainty"]);
|
|
expect(result.possibleFollowUpQuestions).toEqual(["one question"]);
|
|
});
|
|
|
|
it("accepts valid result with one assumption", async () => {
|
|
const fakeResult = makeAssumptionFrontierResultWithOneAssumption();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.assumptions).toEqual(["one genuinely attributable assumption"]);
|
|
expect(result.uncertainties).toEqual(["one uncertainty"]);
|
|
expect(result.possibleFollowUpQuestions).toEqual(["one question"]);
|
|
});
|
|
|
|
it("rejects empty string assumption element", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
assumptions: ["", "valid"],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("assumptions[0] must be a non-empty string");
|
|
});
|
|
|
|
it("rejects non-string assumption element", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
assumptions: [123],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("assumptions[0] must be a non-empty string");
|
|
});
|
|
|
|
it("rejects zero uncertainties", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
assumptions: [],
|
|
uncertainties: [],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects multiple uncertainties", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
assumptions: [],
|
|
uncertainties: ["one", "two"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects zero possibleFollowUpQuestions", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
assumptions: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: [],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
it("rejects multiple possibleFollowUpQuestions", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
assumptions: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["q1", "q2"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
it("does not require observations, relationships, or targetNodeId", async () => {
|
|
const result = makeAssumptionFrontierResultWithNoAssumptions();
|
|
delete result.observations;
|
|
delete result.relationships;
|
|
delete result.targetNodeId;
|
|
|
|
const fakeProvider = makeFakeProvider(result);
|
|
|
|
const run = await runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(run.success).toBe(true);
|
|
});
|
|
|
|
it("propagates provider exception without retry", async () => {
|
|
const err = new Error("provider failure");
|
|
const calls = [];
|
|
const fakeProvider = {
|
|
generateReconstruction: async (prompt, model) => {
|
|
calls.push(1);
|
|
throw err;
|
|
},
|
|
};
|
|
|
|
await expect(
|
|
runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toBe(err);
|
|
});
|
|
});
|
|
|
|
// ── observation+assumption-frontier runner (EXP46) ─────────────────────
|
|
|
|
const OBS_ASSUMP_FRONTIER_TEST_PROMPT = "OBSERVATION ASSUMPTION FRONTIER TEST PROMPT";
|
|
|
|
function makeObservationAssumptionFrontierResultWithEmptyAssumptions() {
|
|
return {
|
|
observations: ["one directly supported observation"],
|
|
assumptions: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
};
|
|
}
|
|
|
|
function makeObservationAssumptionFrontierResultWithOneAssumption() {
|
|
return {
|
|
observations: ["one directly supported observation"],
|
|
assumptions: ["one assumption"],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
};
|
|
}
|
|
|
|
describe("runLiveFocusedObservationAssumptionFrontierPromptExperiment", () => {
|
|
it("passes prompt byte-for-byte to the injected provider", async () => {
|
|
const fakeResult = makeObservationAssumptionFrontierResultWithEmptyAssumptions();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
await runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
const calls = fakeProvider.getCalls();
|
|
expect(calls.length).toBe(1);
|
|
expect(calls[0].prompt).toBe(OBS_ASSUMP_FRONTIER_TEST_PROMPT);
|
|
});
|
|
|
|
// ── Valid with empty assumptions ──
|
|
|
|
it("accepts valid result with empty assumptions", async () => {
|
|
const fakeResult = makeObservationAssumptionFrontierResultWithEmptyAssumptions();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.observations).toEqual(["one directly supported observation"]);
|
|
expect(result.assumptions).toEqual([]);
|
|
expect(result.uncertainties).toEqual(["one uncertainty"]);
|
|
expect(result.possibleFollowUpQuestions).toEqual(["one question"]);
|
|
});
|
|
|
|
// ── Valid with one assumption ──
|
|
|
|
it("accepts valid result with one assumption", async () => {
|
|
const fakeResult = makeObservationAssumptionFrontierResultWithOneAssumption();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.observations).toEqual(["one directly supported observation"]);
|
|
expect(result.assumptions).toEqual(["one assumption"]);
|
|
expect(result.uncertainties).toEqual(["one uncertainty"]);
|
|
expect(result.possibleFollowUpQuestions).toEqual(["one question"]);
|
|
});
|
|
|
|
// ── Reject invalid observations ──
|
|
|
|
it("rejects empty observations array", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: [],
|
|
assumptions: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("observations must contain at least one element");
|
|
});
|
|
|
|
it("rejects empty-string observation item", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: [""],
|
|
assumptions: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("observations[0] must be a non-empty string");
|
|
});
|
|
|
|
it("rejects non-string observation item", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: [123],
|
|
assumptions: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("observations[0] must be a non-empty string");
|
|
});
|
|
|
|
// ── Reject invalid assumptions ──
|
|
|
|
it("rejects empty-string assumption item", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["one observation"],
|
|
assumptions: [""],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("assumptions[0] must be a non-empty string");
|
|
});
|
|
|
|
it("rejects non-string assumption item", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["one observation"],
|
|
assumptions: [null],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("assumptions[0] must be a non-empty string");
|
|
});
|
|
|
|
it("accepts empty assumptions array as valid", async () => {
|
|
const fakeResult = makeObservationAssumptionFrontierResultWithEmptyAssumptions();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
// ── Reject invalid frontier cardinality ──
|
|
|
|
it("rejects zero uncertainties", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["obs-1"],
|
|
assumptions: [],
|
|
uncertainties: [],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects multiple uncertainties", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["obs-1"],
|
|
assumptions: [],
|
|
uncertainties: ["one", "two"],
|
|
possibleFollowUpQuestions: ["one question"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("uncertainties must contain exactly one element");
|
|
});
|
|
|
|
it("rejects zero possibleFollowUpQuestions", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["obs-1"],
|
|
assumptions: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: [],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
it("rejects multiple possibleFollowUpQuestions", async () => {
|
|
const fakeProvider = makeFakeProvider({
|
|
observations: ["obs-1"],
|
|
assumptions: [],
|
|
uncertainties: ["one uncertainty"],
|
|
possibleFollowUpQuestions: ["q1", "q2"],
|
|
});
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toThrow("possibleFollowUpQuestions must contain exactly one element");
|
|
});
|
|
|
|
// ── Other fields not required ──
|
|
|
|
it("does not require relationships or targetNodeId", async () => {
|
|
const result = makeObservationAssumptionFrontierResultWithEmptyAssumptions();
|
|
delete result.targetNodeId;
|
|
|
|
const fakeProvider = makeFakeProvider(result);
|
|
|
|
const run = await runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(run.success).toBe(true);
|
|
});
|
|
|
|
// ── Existing APIs remain green ──
|
|
|
|
it("existing API runLiveFocusedDeconstructExperiment remains callable", async () => {
|
|
const fakeResult = makeValidResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedDeconstructExperiment({
|
|
...params,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
it("existing API runLiveFocusedFrontierPromptExperiment remains callable", async () => {
|
|
const fakeResult = makeMinimalFrontierResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedFrontierPromptExperiment({
|
|
prompt: FRONTIER_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
it("existing API runLiveFocusedObservationFrontierPromptExperiment remains callable", async () => {
|
|
const fakeResult = makeObservationFrontierResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedObservationFrontierPromptExperiment({
|
|
prompt: OBSERVATION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
it("existing API runLiveFocusedRelationshipFrontierPromptExperiment remains callable", async () => {
|
|
const fakeResult = makeRelationshipFrontierResult();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedRelationshipFrontierPromptExperiment({
|
|
prompt: RELATIONSHIP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
it("existing API runLiveFocusedAssumptionFrontierPromptExperiment remains callable", async () => {
|
|
const fakeResult = makeAssumptionFrontierResultWithOneAssumption();
|
|
const fakeProvider = makeFakeProvider(fakeResult);
|
|
|
|
const result = await runLiveFocusedAssumptionFrontierPromptExperiment({
|
|
prompt: ASSUMPTION_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
// ── Provider error propagates directly ──
|
|
|
|
it("propagates provider exception without retry", async () => {
|
|
const err = new Error("provider failure");
|
|
const calls = [];
|
|
const fakeProvider = {
|
|
generateReconstruction: async (prompt, model) => {
|
|
calls.push(1);
|
|
throw err;
|
|
},
|
|
};
|
|
|
|
await expect(
|
|
runLiveFocusedObservationAssumptionFrontierPromptExperiment({
|
|
prompt: OBS_ASSUMP_FRONTIER_TEST_PROMPT,
|
|
provider: fakeProvider,
|
|
})
|
|
).rejects.toBe(err);
|
|
});
|
|
}); |