Files
confidence-engine/tests/graph/focused-frontier-prompt-builder.test.mjs
T

1073 lines
46 KiB
JavaScript

/**
* Deterministic verification of focused frontier prompt builders (EXP42).
* Zero live calls. No provider, no Ollama, no graph logic.
*/
import { describe, it, expect } from "vitest";
import {
buildMinimalFrontierPrompt,
buildObservationFrontierPrompt,
buildRelationshipFrontierPrompt,
buildAssumptionFrontierPrompt,
buildObservationAssumptionFrontierPrompt,
buildObservationStrictAssumptionFrontierPrompt,
} from "./focused-frontier-prompt-builder.mjs";
// ── fixtured case (single fixed dummy) ─────────────────────────────────────
const CASE = {
centralStatement:
"A business owner seeks to delegate routine operational tasks but lacks clarity on scope.",
targetLabel: "Team capability constraints on task handoff boundaries",
targetDescription:
"The extent to which current skill levels and bandwidth dictate the limit of delegable tasks.",
question: "What was the comparable state before capability constraints?",
answer: "She handles weekly supplier payments herself without checking for six months.",
};
// ── helpers ────────────────────────────────────────────────────────────────
function countOccurrences(str, sub) {
let n = 0;
let i = 0;
while ((i = str.indexOf(sub, i)) !== -1) {
n++;
i += sub.length;
}
return n;
}
// ── 1. Both builders are deterministic ─────────────────────────────────────
describe("determinism", () => {
it("buildMinimalFrontierPrompt produces byte-identical output on repeated calls", () => {
const a = buildMinimalFrontierPrompt(CASE);
const b = buildMinimalFrontierPrompt(CASE);
expect(a).toBe(b);
});
it("buildObservationFrontierPrompt produces byte-identical output on repeated calls", () => {
const a = buildObservationFrontierPrompt(CASE);
const b = buildObservationFrontierPrompt(CASE);
expect(a).toBe(b);
});
});
// ── 2. Shared case material is identical ───────────────────────────────────
describe("shared context", () => {
it("both prompts contain the exact centralStatement", () => {
const minimal = buildMinimalFrontierPrompt(CASE);
const obs = buildObservationFrontierPrompt(CASE);
expect(minimal).toContain(CASE.centralStatement);
expect(obs).toContain(CASE.centralStatement);
});
it("both prompts contain the exact targetLabel", () => {
const minimal = buildMinimalFrontierPrompt(CASE);
const obs = buildObservationFrontierPrompt(CASE);
expect(minimal).toContain(CASE.targetLabel);
expect(obs).toContain(CASE.targetLabel);
});
it("both prompts contain the exact targetDescription", () => {
const minimal = buildMinimalFrontierPrompt(CASE);
const obs = buildObservationFrontierPrompt(CASE);
expect(minimal).toContain(CASE.targetDescription);
expect(obs).toContain(CASE.targetDescription);
});
it("both prompts contain the exact question", () => {
const minimal = buildMinimalFrontierPrompt(CASE);
const obs = buildObservationFrontierPrompt(CASE);
expect(minimal).toContain(CASE.question);
expect(obs).toContain(CASE.question);
});
it("both prompts contain the exact answer", () => {
const minimal = buildMinimalFrontierPrompt(CASE);
const obs = buildObservationFrontierPrompt(CASE);
expect(minimal).toContain(CASE.answer);
expect(obs).toContain(CASE.answer);
});
});
// ── 3. Frontier rules are one shared source ────────────────────────────────
describe("shared frontier rules", () => {
const MINIMAL = buildMinimalFrontierPrompt(CASE);
const OBSERVATION = buildObservationFrontierPrompt(CASE);
it("minimal prompt contains the shared frontier rule text", () => {
// Extract a unique anchor phrase that only appears in the frontier rules block
expect(MINIMAL).toContain("Identify the single nearest thing that is still unknown because of this answer.");
});
it("observation prompt contains the shared frontier rule text", () => {
expect(OBSERVATION).toContain("Identify the single nearest thing that is still unknown because of this answer.");
});
it("the frontier rule line appears exactly once in each prompt", () => {
const anchor = "Identify the single nearest thing that is still unknown because of this answer.";
expect(countOccurrences(MINIMAL, anchor)).toBe(1);
expect(countOccurrences(OBSERVATION, anchor)).toBe(1);
});
it("both prompts share the same frontier rule text (byte-identical slice)", () => {
const extractFrontierRules = (prompt) => {
const startMarker = "Identify the single nearest thing that is still unknown because of this answer.";
const endMarker = "Use ordinary language a capable non-expert can understand immediately.";
const startIdx = prompt.indexOf(startMarker);
const endIdx = prompt.indexOf(endMarker) + endMarker.length;
return prompt.slice(startIdx, endIdx);
};
expect(extractFrontierRules(MINIMAL)).toBe(extractFrontierRules(OBSERVATION));
});
});
// ── 4. Minimal prompt contains no excluded semantic fields ─────────────────
describe("minimal prompt — exclusion check", () => {
const MINIMAL = buildMinimalFrontierPrompt(CASE);
it("does NOT mention observations (as a field)", () => {
expect(MINIMAL).not.toContain('"observations"');
expect(MINIMAL).not.toContain("observations:");
});
it("does NOT mention assumptions", () => {
expect(MINIMAL).not.toContain("assumptions");
});
it("does NOT mention relationships", () => {
expect(MINIMAL).not.toContain("relationships");
});
it("does NOT mention targetNodeId", () => {
expect(MINIMAL).not.toContain("targetNodeId");
});
});
// ── 5. Observation prompt contains only the added semantic job ─────────────
describe("observation prompt — inclusion check", () => {
const OBS = buildObservationFrontierPrompt(CASE);
it("contains observations field in required fields", () => {
expect(OBS).toContain("- observations");
});
it("does NOT mention assumptions", () => {
expect(OBS).not.toContain("assumptions");
});
it("does NOT mention relationships", () => {
expect(OBS).not.toContain("relationships");
});
it("does NOT mention targetNodeId", () => {
expect(OBS).not.toContain("targetNodeId");
});
});
// ── 6. JSON anchoring exists in both ───────────────────────────────────────
describe("JSON-only anchoring", () => {
const MINIMAL = buildMinimalFrontierPrompt(CASE);
const OBSERVATION = buildObservationFrontierPrompt(CASE);
it('both contain "Return exactly one JSON object."', () => {
expect(MINIMAL).toContain("Return exactly one JSON object.");
expect(OBSERVATION).toContain("Return exactly one JSON object.");
});
it('both contain "Return JSON only."', () => {
expect(MINIMAL).toContain("Return JSON only.");
expect(OBSERVATION).toContain("Return JSON only.");
});
it("both prohibit prose outside JSON", () => {
const proseProhibition = "Do not include prose, markdown, headings, commentary, or explanation outside the JSON object.";
expect(MINIMAL).toContain(proseProhibition);
expect(OBSERVATION).toContain(proseProhibition);
});
});
// ── 7. Exact shapes are present ────────────────────────────────────────────
describe("exact output shapes", () => {
it("minimal prompt contains the exact two-field shape", () => {
const MINIMAL = buildMinimalFrontierPrompt(CASE);
expect(MINIMAL).toContain('"uncertainties": ["one uncertainty"]');
expect(MINIMAL).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
});
it("observation prompt contains the exact three-field shape", () => {
const OBS = buildObservationFrontierPrompt(CASE);
expect(OBS).toContain('"observations": ["one or more directly supported observations"]');
expect(OBS).toContain('"uncertainties": ["one uncertainty"]');
expect(OBS).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
});
});
// ── 8. Only intended semantic workload differs ─────────────────────────────
describe("semantic workload control", () => {
const MINIMAL = buildMinimalFrontierPrompt(CASE);
const OBSERVATION = buildObservationFrontierPrompt(CASE);
it("both share identical JSON-only instruction text", () => {
expect(MINIMAL).toContain("Return exactly one JSON object.");
expect(OBSERVATION).toContain("Return exactly one JSON object.");
expect(MINIMAL).toContain("Return JSON only.");
expect(OBSERVATION).toContain("Return JSON only.");
});
it("both share identical shared context formatter output", () => {
// Both contain the same case material — verify by checking they contain
// each of the five shared fields identically.
expect(MINIMAL).toContain(CASE.centralStatement);
expect(OBSERVATION).toContain(CASE.centralStatement);
expect(MINIMAL).toContain(CASE.targetLabel);
expect(OBSERVATION).toContain(CASE.targetLabel);
expect(MINIMAL).toContain(CASE.question);
expect(OBSERVATION).toContain(CASE.question);
});
it("observation prompt alone adds the observations field", () => {
// The observation-specific text should be present only in OBS
expect(OBSERVATION).toContain("- observations");
expect(OBSERVATION).toContain('"observations": ["one or more directly supported observations"]');
expect(OBSERVATION).toContain("Do not strengthen implications into observations");
});
it("observation prompt does NOT add assumptions, relationships, or targetNodeId", () => {
expect(OBSERVATION).not.toContain("assumptions");
expect(OBSERVATION).not.toContain("relationships");
expect(OBSERVATION).not.toContain("targetNodeId");
});
});
// ── 9. Deterministic verification of relationship-frontier builder (EXP44) ─
describe("relationship frontier prompt builder — determinism", () => {
it("buildRelationshipFrontierPrompt produces byte-identical output on repeated calls", () => {
const a = buildRelationshipFrontierPrompt(CASE);
const b = buildRelationshipFrontierPrompt(CASE);
expect(a).toBe(b);
});
});
describe("relationship frontier — shared context formatter", () => {
it("shares the same centralStatement as minimal builder", () => {
const rel = buildRelationshipFrontierPrompt(CASE);
const min = buildMinimalFrontierPrompt(CASE);
expect(rel).toContain(CASE.centralStatement);
expect(min).toContain(CASE.centralStatement);
});
it("shares the same targetLabel as minimal builder", () => {
const rel = buildRelationshipFrontierPrompt(CASE);
const min = buildMinimalFrontierPrompt(CASE);
expect(rel).toContain(CASE.targetLabel);
expect(min).toContain(CASE.targetLabel);
});
it("shares the same targetDescription as minimal builder", () => {
const rel = buildRelationshipFrontierPrompt(CASE);
const min = buildMinimalFrontierPrompt(CASE);
expect(rel).toContain(CASE.targetDescription);
expect(min).toContain(CASE.targetDescription);
});
it("shares the same question as minimal builder", () => {
const rel = buildRelationshipFrontierPrompt(CASE);
const min = buildMinimalFrontierPrompt(CASE);
expect(rel).toContain(CASE.question);
expect(min).toContain(CASE.question);
});
it("shares the same answer as minimal builder", () => {
const rel = buildRelationshipFrontierPrompt(CASE);
const min = buildMinimalFrontierPrompt(CASE);
expect(rel).toContain(CASE.answer);
expect(min).toContain(CASE.answer);
});
});
describe("relationship frontier — shared frontier rules", () => {
it("contains the shared frontier rule text", () => {
const REL = buildRelationshipFrontierPrompt(CASE);
expect(REL).toContain("Identify the single nearest thing that is still unknown because of this answer.");
});
it("the frontier rule line appears exactly once", () => {
const REL = buildRelationshipFrontierPrompt(CASE);
expect(countOccurrences(REL, "Identify the single nearest thing that is still unknown because of this answer.")).toBe(1);
});
it("shares the same frontier rule text as minimal builder", () => {
const extractFrontierRules = (prompt) => {
const startMarker = "Identify the single nearest thing that is still unknown because of this answer.";
const endMarker = "Use ordinary language a capable non-expert can understand immediately.";
const startIdx = prompt.indexOf(startMarker);
const endIdx = prompt.indexOf(endMarker) + endMarker.length;
return prompt.slice(startIdx, endIdx);
};
const REL = buildRelationshipFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(extractFrontierRules(REL)).toBe(extractFrontierRules(MIN));
});
});
describe("relationship frontier — shared JSON-only instruction", () => {
it('contains "Return exactly one JSON object."', () => {
const REL = buildRelationshipFrontierPrompt(CASE);
expect(REL).toContain("Return exactly one JSON object.");
});
it('contains "Return JSON only."', () => {
const REL = buildRelationshipFrontierPrompt(CASE);
expect(REL).toContain("Return JSON only.");
});
it("prohibits prose outside JSON", () => {
const REL = buildRelationshipFrontierPrompt(CASE);
expect(REL).toContain("Do not include prose, markdown, headings, commentary, or explanation outside the JSON object.");
});
});
describe("relationship frontier — presence and absence checks", () => {
const REL = buildRelationshipFrontierPrompt(CASE);
it("contains relationships field in required fields", () => {
expect(REL).toContain("- relationships");
});
it("does NOT mention observations (as a field)", () => {
expect(REL).not.toContain('"observations"');
expect(REL).not.toContain("observations:");
});
it("does NOT mention assumptions", () => {
expect(REL).not.toContain("assumptions");
});
it("does NOT mention targetNodeId", () => {
expect(REL).not.toContain("targetNodeId");
});
});
describe("relationship frontier — exact JSON shape", () => {
const REL = buildRelationshipFrontierPrompt(CASE);
it('shows "relationships": ["one or more directly established relationships"]', () => {
expect(REL).toContain('"relationships": ["one or more directly established relationships"]');
});
it('shows "uncertainties": ["one uncertainty"]', () => {
expect(REL).toContain('"uncertainties": ["one uncertainty"]');
});
it('shows "possibleFollowUpQuestions": ["one follow-up question"]', () => {
expect(REL).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
});
});
describe("relationship frontier — relationship rule present exactly once", () => {
const REL = buildRelationshipFrontierPrompt(CASE);
it("contains the relationship rule verbatim", () => {
expect(REL).toContain("only connections that the user's answer directly establishes between items. Co-mentioned facts do not by themselves create causal, constraint, or dependency relationships.");
});
it("the relationship rule appears exactly once", () => {
const ruleText = "relationships: only connections that the user's answer directly establishes between items.";
expect(countOccurrences(REL, ruleText)).toBe(1);
});
});
// ── assumption frontier prompt builder (EXP45) ───────────────────────────
describe("assumption frontier prompt builder — determinism", () => {
it("buildAssumptionFrontierPrompt produces byte-identical output on repeated calls", () => {
const a = buildAssumptionFrontierPrompt(CASE);
const b = buildAssumptionFrontierPrompt(CASE);
expect(a).toBe(b);
});
});
describe("assumption frontier — shared context formatter", () => {
it("shares the same centralStatement as minimal builder", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(ASSUMPTION).toContain(CASE.centralStatement);
expect(MIN).toContain(CASE.centralStatement);
});
it("shares the same targetLabel as minimal builder", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(ASSUMPTION).toContain(CASE.targetLabel);
expect(MIN).toContain(CASE.targetLabel);
});
it("shares the same targetDescription as minimal builder", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(ASSUMPTION).toContain(CASE.targetDescription);
expect(MIN).toContain(CASE.targetDescription);
});
it("shares the same question as minimal builder", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(ASSUMPTION).toContain(CASE.question);
expect(MIN).toContain(CASE.question);
});
it("shares the same answer as minimal builder", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(ASSUMPTION).toContain(CASE.answer);
expect(MIN).toContain(CASE.answer);
});
});
describe("assumption frontier — shared frontier rules", () => {
it("contains the shared frontier rule text", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
expect(ASSUMPTION).toContain("Identify the single nearest thing that is still unknown because of this answer.");
});
it("the frontier rule line appears exactly once", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
expect(countOccurrences(ASSUMPTION, "Identify the single nearest thing that is still unknown because of this answer.")).toBe(1);
});
it("shares the same frontier rule text as minimal builder", () => {
const extractFrontierRules = (prompt) => {
const startMarker = "Identify the single nearest thing that is still unknown because of this answer.";
const endMarker = "Use ordinary language a capable non-expert can understand immediately.";
const startIdx = prompt.indexOf(startMarker);
const endIdx = prompt.indexOf(endMarker) + endMarker.length;
return prompt.slice(startIdx, endIdx);
};
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(extractFrontierRules(ASSUMPTION)).toBe(extractFrontierRules(MIN));
});
});
describe("assumption frontier — shared JSON-only instruction", () => {
it('contains "Return exactly one JSON object."', () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
expect(ASSUMPTION).toContain("Return exactly one JSON object.");
});
it('contains "Return JSON only."', () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
expect(ASSUMPTION).toContain("Return JSON only.");
});
it("prohibits prose outside JSON", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
expect(ASSUMPTION).toContain("Do not include prose, markdown, headings, commentary, or explanation outside the JSON object.");
});
});
describe("assumption frontier — presence and absence checks", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
it("contains assumptions field in required fields", () => {
expect(ASSUMPTION).toContain("- assumptions");
});
it("does NOT mention observations (as a field)", () => {
expect(ASSUMPTION).not.toContain('"observations"');
expect(ASSUMPTION).not.toContain("observations:");
});
it("does NOT mention relationships", () => {
expect(ASSUMPTION).not.toContain("relationships");
});
it("does NOT mention targetNodeId", () => {
expect(ASSUMPTION).not.toContain("targetNodeId");
});
});
describe("assumption frontier — exact JSON shape", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
it('shows "assumptions": ["zero or more genuinely user-held assumptions"]', () => {
expect(ASSUMPTION).toContain('"assumptions": ["zero or more genuinely user-held assumptions"]');
});
it('shows "uncertainties": ["one uncertainty"]', () => {
expect(ASSUMPTION).toContain('"uncertainties": ["one uncertainty"]');
});
it('shows "possibleFollowUpQuestions": ["one follow-up question"]', () => {
expect(ASSUMPTION).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
});
});
describe("assumption frontier — assumption rule present exactly once", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
it("contains the assumption rule verbatim", () => {
expect(ASSUMPTION).toContain("what unstated proposition does the user's answer itself rely upon for it to make sense?");
});
it("the assumption rule appears exactly once", () => {
const ruleText = "assumptions: what unstated proposition does the user's answer itself rely upon for it to make sense?";
expect(countOccurrences(ASSUMPTION, ruleText)).toBe(1);
});
});
describe("assumption frontier — empty assumptions explicitly permitted", () => {
const ASSUMPTION = buildAssumptionFrontierPrompt(CASE);
it("prompt text contains the phrase 'assumptions: []' allowing empty arrays", () => {
expect(ASSUMPTION).toContain("return assumptions: []");
});
});
// ── EXP46 — observation+assumption frontier prompt builder ────────────────
describe("observation+assumption frontier prompt builder — determinism (req 1)", () => {
it("buildObservationAssumptionFrontierPrompt produces byte-identical output on repeated calls", () => {
const a = buildObservationAssumptionFrontierPrompt(CASE);
const b = buildObservationAssumptionFrontierPrompt(CASE);
expect(a).toBe(b);
});
it("all existing builders remain deterministic (req 2)", () => {
for (const builder of [buildMinimalFrontierPrompt, buildObservationFrontierPrompt, buildRelationshipFrontierPrompt, buildAssumptionFrontierPrompt]) {
const a = builder(CASE);
const b = builder(CASE);
expect(a).toBe(b);
}
});
});
describe("observation+assumption frontier — shared context formatter (req 3)", () => {
it("shares the same centralStatement as minimal builder", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(OAF).toContain(CASE.centralStatement);
expect(MIN).toContain(CASE.centralStatement);
});
it("shares the same targetLabel as minimal builder", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(OAF).toContain(CASE.targetLabel);
expect(MIN).toContain(CASE.targetLabel);
});
it("shares the same targetDescription as minimal builder", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(OAF).toContain(CASE.targetDescription);
expect(MIN).toContain(CASE.targetDescription);
});
it("shares the same question as minimal builder", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(OAF).toContain(CASE.question);
expect(MIN).toContain(CASE.question);
});
it("shares the same answer as minimal builder", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(OAF).toContain(CASE.answer);
expect(MIN).toContain(CASE.answer);
});
});
describe("observation+assumption frontier — shared frontier rules (req 4)", () => {
it("contains the shared frontier rule text", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
expect(OAF).toContain("Identify the single nearest thing that is still unknown because of this answer.");
});
it("the frontier rule line appears exactly once", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
expect(countOccurrences(OAF, "Identify the single nearest thing that is still unknown because of this answer.")).toBe(1);
});
it("shares the same frontier rule text as minimal builder", () => {
const extractFrontierRules = (prompt) => {
const startMarker = "Identify the single nearest thing that is still unknown because of this answer.";
const endMarker = "Use ordinary language a capable non-expert can understand immediately.";
const startIdx = prompt.indexOf(startMarker);
const endIdx = prompt.indexOf(endMarker) + endMarker.length;
return prompt.slice(startIdx, endIdx);
};
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(extractFrontierRules(OAF)).toBe(extractFrontierRules(MIN));
});
});
describe("observation+assumption frontier — shared JSON-only instruction (req 5)", () => {
it('contains "Return exactly one JSON object."', () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
expect(OAF).toContain("Return exactly one JSON object.");
});
it('contains "Return JSON only."', () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
expect(OAF).toContain("Return JSON only.");
});
it("prohibits prose outside JSON", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
expect(OAF).toContain("Do not include prose, markdown, headings, commentary, or explanation outside the JSON object.");
});
});
describe("observation+assumption frontier — observation rule reused unchanged (req 6)", () => {
it("contains the observation rule verbatim", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
expect(OAF).toContain("only meaning directly supported by what the user's answer states. Do not strengthen implications into observations.");
});
it("the observation rule appears exactly once", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const ruleText = "observations: only meaning directly supported by what the user's answer states.";
expect(countOccurrences(OAF, ruleText)).toBe(1);
});
});
describe("observation+assumption frontier — assumption rule reused unchanged (req 7)", () => {
it("contains the assumption rule verbatim", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
expect(OAF).toContain("what unstated proposition does the user's answer itself rely upon for it to make sense?");
});
it("the assumption rule appears exactly once", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const ruleText = "assumptions: what unstated proposition does the user's answer itself rely upon for it to make sense?";
expect(countOccurrences(OAF, ruleText)).toBe(1);
});
it("contains empty-assumptions guidance verbatim", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
expect(OAF).toContain("return assumptions: []");
});
});
describe("observation+assumption frontier — presence checks (req 8, 9)", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
it("contains observations field in required fields (req 8)", () => {
expect(OAF).toContain("- observations");
});
it('shows "observations": ["one or more directly supported observations"] (req 8)', () => {
expect(OAF).toContain('"observations": ["one or more directly supported observations"]');
});
it("contains assumptions field in required fields (req 9)", () => {
expect(OAF).toContain("- assumptions");
});
it('shows "assumptions": ["zero or more genuinely user-held assumptions"] (req 9)', () => {
expect(OAF).toContain('"assumptions": ["zero or more genuinely user-held assumptions"]');
});
});
describe("observation+assumption frontier — absence checks (req 10, 11)", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
it("does NOT mention relationships as a field (req 10)", () => {
expect(OAF).not.toContain('"relationships"');
expect(OAF).not.toContain("- relationships");
});
it("does NOT mention targetNodeId (req 11)", () => {
expect(OAF).not.toContain("targetNodeId");
});
});
describe("observation+assumption frontier — exact JSON shape present (req 12)", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
it('shows all four required fields', () => {
expect(OAF).toContain('"observations": ["one or more directly supported observations"]');
expect(OAF).toContain('"assumptions": ["zero or more genuinely user-held assumptions"]');
expect(OAF).toContain('"uncertainties": ["one uncertainty"]');
expect(OAF).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
});
});
describe("observation+assumption frontier — empty assumptions permitted (req 13)", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
it("prompt text contains guidance allowing empty assumptions array", () => {
expect(OAF).toContain("return assumptions: []");
});
});
// ── EXP49 — observation+strict-assumption frontier prompt builder ───────
describe("observation+strict-assumption frontier prompt builder — determinism (req 1)", () => {
it("buildObservationStrictAssumptionFrontierPrompt produces byte-identical output on repeated calls", () => {
const a = buildObservationStrictAssumptionFrontierPrompt(CASE);
const b = buildObservationStrictAssumptionFrontierPrompt(CASE);
expect(a).toBe(b);
});
it("all existing builders remain deterministic (req 2)", () => {
for (const builder of [buildMinimalFrontierPrompt, buildObservationFrontierPrompt, buildRelationshipFrontierPrompt, buildAssumptionFrontierPrompt, buildObservationAssumptionFrontierPrompt]) {
const a = builder(CASE);
const b = builder(CASE);
expect(a).toBe(b);
}
});
});
describe("observation+strict-assumption frontier — shared context formatter (req 3)", () => {
it("shares the same centralStatement as minimal builder", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(SAF).toContain(CASE.centralStatement);
expect(MIN).toContain(CASE.centralStatement);
});
it("shares the same targetLabel as minimal builder", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(SAF).toContain(CASE.targetLabel);
expect(MIN).toContain(CASE.targetLabel);
});
it("shares the same targetDescription as minimal builder", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(SAF).toContain(CASE.targetDescription);
expect(MIN).toContain(CASE.targetDescription);
});
it("shares the same question as minimal builder", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(SAF).toContain(CASE.question);
expect(MIN).toContain(CASE.question);
});
it("shares the same answer as minimal builder", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(SAF).toContain(CASE.answer);
expect(MIN).toContain(CASE.answer);
});
});
describe("observation+strict-assumption frontier — shared frontier rules (req 4)", () => {
it("contains the shared frontier rule text", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
expect(SAF).toContain("Identify the single nearest thing that is still unknown because of this answer.");
});
it("the frontier rule line appears exactly once", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
expect(countOccurrences(SAF, "Identify the single nearest thing that is still unknown because of this answer.")).toBe(1);
});
it("shares the same frontier rule text as minimal builder", () => {
const extractFrontierRules = (prompt) => {
const startMarker = "Identify the single nearest thing that is still unknown because of this answer.";
const endMarker = "Use ordinary language a capable non-expert can understand immediately.";
const startIdx = prompt.indexOf(startMarker);
const endIdx = prompt.indexOf(endMarker) + endMarker.length;
return prompt.slice(startIdx, endIdx);
};
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
const MIN = buildMinimalFrontierPrompt(CASE);
expect(extractFrontierRules(SAF)).toBe(extractFrontierRules(MIN));
});
});
describe("observation+strict-assumption frontier — shared JSON-only instruction (req 5)", () => {
it('contains "Return exactly one JSON object."', () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
expect(SAF).toContain("Return exactly one JSON object.");
});
it('contains "Return JSON only."', () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
expect(SAF).toContain("Return JSON only.");
});
it("prohibits prose outside JSON", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
expect(SAF).toContain("Do not include prose, markdown, headings, commentary, or explanation outside the JSON object.");
});
});
describe("observation+strict-assumption frontier — observation rule reused unchanged (req 6)", () => {
it("contains the observation rule verbatim", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
expect(SAF).toContain("only meaning directly supported by what the user's answer states. Do not strengthen implications into observations.");
});
it("the observation rule appears exactly once", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
const ruleText = "observations: only meaning directly supported by what the user's answer states.";
expect(countOccurrences(SAF, ruleText)).toBe(1);
});
});
describe("observation+strict-assumption frontier — presence checks (req 7, 8)", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
it("contains observations field in required fields", () => {
expect(SAF).toContain("- observations");
});
it('shows "observations": ["one or more directly supported observations"]', () => {
expect(SAF).toContain('"observations": ["one or more directly supported observations"]');
});
it("contains assumptions field in required fields", () => {
expect(SAF).toContain("- assumptions");
});
it('shows "assumptions": ["zero or more genuinely user-held assumptions"]', () => {
expect(SAF).toContain('"assumptions": ["zero or more genuinely user-held assumptions"]');
});
});
describe("observation+strict-assumption frontier — exact JSON shape present (req 9)", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
it('shows all four required fields', () => {
expect(SAF).toContain('"observations": ["one or more directly supported observations"]');
expect(SAF).toContain('"assumptions": ["zero or more genuinely user-held assumptions"]');
expect(SAF).toContain('"uncertainties": ["one uncertainty"]');
expect(SAF).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
});
});
describe("observation+strict-assumption frontier — absence checks (req 10, 11)", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
it("does NOT mention relationships as a field", () => {
expect(SAF).not.toContain('"relationships"');
expect(SAF).not.toContain("- relationships");
});
it("does NOT mention targetNodeId", () => {
expect(SAF).not.toContain("targetNodeId");
});
});
describe("observation+strict-assumption frontier — empty assumptions permitted", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
it("prompt text contains guidance allowing empty assumptions array", () => {
expect(SAF).toContain("return assumptions: []");
});
});
describe("observation+strict-assumption frontier — no observation→assumption dependency", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
it("does NOT contain instruction to derive assumptions from observations", () => {
expect(SAF).not.toContain("derive assumptions");
expect(SAF).not.toContain("base assumptions");
expect(SAF).not.toContain("constrain assumptions");
});
});
// ── EXP49 — same workload and structure control ──────────────────────────
describe("observation+strict-assumption vs observation+assumption — same workload and structure", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
it("both contain the same observations field", () => {
expect(OAF).toContain("- observations");
expect(SAF).toContain("- observations");
expect(OAF).toContain('"observations": ["one or more directly supported observations"]');
expect(SAF).toContain('"observations": ["one or more directly supported observations"]');
});
it("both contain the same assumptions field", () => {
expect(OAF).toContain("- assumptions");
expect(SAF).toContain("- assumptions");
expect(OAF).toContain('"assumptions": ["zero or more genuinely user-held assumptions"]');
expect(SAF).toContain('"assumptions": ["zero or more genuinely user-held assumptions"]');
});
it("both contain the same uncertainties field", () => {
expect(OAF).toContain('"uncertainties": ["one uncertainty"]');
expect(SAF).toContain('"uncertainties": ["one uncertainty"]');
});
it("both contain the same possibleFollowUpQuestions field", () => {
expect(OAF).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
expect(SAF).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
});
it("both have identical JSON shape", () => {
expect(OAF).toContain('"observations": ["one or more directly supported observations"]');
expect(SAF).toContain('"observations": ["one or more directly supported observations"]');
expect(OAF).toContain('"assumptions": ["zero or more genuinely user-held assumptions"]');
expect(SAF).toContain('"assumptions": ["zero or more genuinely user-held assumptions"]');
expect(OAF).toContain('"uncertainties": ["one uncertainty"]');
expect(SAF).toContain('"uncertainties": ["one uncertainty"]');
expect(OAF).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
expect(SAF).toContain('"possibleFollowUpQuestions": ["one follow-up question"]');
});
it("both share the same context formatter output", () => {
for (const key of Object.keys(CASE)) {
expect(OAF).toContain(CASE[key]);
expect(SAF).toContain(CASE[key]);
}
});
it("both contain identical observation rule", () => {
const obsRule = "observations: only meaning directly supported by what the user's answer states. Do not strengthen implications into observations.";
expect(OAF).toContain(obsRule);
expect(SAF).toContain(obsRule);
expect(countOccurrences(OAF, "observations: only meaning directly supported by what the user's answer states.")).toBe(1);
expect(countOccurrences(SAF, "observations: only meaning directly supported by what the user's answer states.")).toBe(1);
});
it("both contain identical frontier rules", () => {
const extractFrontierRules = (prompt) => {
const startMarker = "Identify the single nearest thing that is still unknown because of this answer.";
const endMarker = "Use ordinary language a capable non-expert can understand immediately.";
const startIdx = prompt.indexOf(startMarker);
const endIdx = prompt.indexOf(endMarker) + endMarker.length;
return prompt.slice(startIdx, endIdx);
};
expect(extractFrontierRules(OAF)).toBe(extractFrontierRules(SAF));
});
it("both contain identical JSON-only instructions", () => {
expect(OAF).toContain("Return exactly one JSON object.");
expect(SAF).toContain("Return exactly one JSON object.");
expect(OAF).toContain("Return JSON only.");
expect(SAF).toContain("Return JSON only.");
});
it("both contain the same required top-level field list", () => {
for (const field of ["- observations", "- assumptions", "- uncertainties", "- possibleFollowUpQuestions"]) {
expect(OAF).toContain(field);
expect(SAF).toContain(field);
}
});
it("neither prompt contains relationships", () => {
expect(OAF).not.toContain("- relationships");
expect(SAF).not.toContain("- relationships");
});
it("neither prompt contains targetNodeId", () => {
expect(OAF).not.toContain("targetNodeId");
expect(SAF).not.toContain("targetNodeId");
});
});
// ── EXP49 — only intended rule difference ────────────────────────────────
describe("observation+strict-assumption vs observation+assumption — only rule difference", () => {
const OAF = buildObservationAssumptionFrontierPrompt(CASE);
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
it("SAF contains the strict attribution boundary text", () => {
expect(SAF).toContain("Co-mentioned, contrasted, or juxtaposed facts do not by themselves establish a user-held assumption.");
});
it("OAF does NOT contain the strict attribution boundary text", () => {
expect(OAF).not.toContain("Co-mentioned, contrasted, or juxtaposed facts do not by themselves establish a user-held assumption.");
});
it("restoring the original assumption rule in SAF reconstructs OAF byte-for-byte", () => {
const originalRule = "assumptions: what unstated proposition does the user's answer itself rely upon for it to make sense? Attribute only when such a proposition is genuinely attributable to the user's reasoning. The boundary is narrow: attribute only propositions that the user's answer would cease to make sense if they were false. Do NOT import plausible interpretations from the wider investigation context, scenario framing, domain relevance, strategic implications, or model-generated analysis into this field — those belong in uncertainties, other structured fields where permitted, or possibleFollowUpQuestions. Do NOT connect a factual statement the user makes to a broader capability or constraint concept unless the user explicitly links them. Example: answering \"I only have bank account access\" to a question about delegation constraints does NOT assume that \"delegation feasibility is contingent upon banking access\" — it only states a fact about access, and connecting that fact to delegation feasibility is your own scenario-level inference, not a user-held assumption. If the user's answer does not contain or rely upon an identifiable assumption, return assumptions: []. Do NOT require verbatim copying from the user's answer; paraphrasing is allowed only when the reasoning genuinely relies on it.";
const strictRule = SAF.match(/assumptions:.*reasoning genuinely relies on it\./s)?.[0];
expect(strictRule).toBeDefined();
const reconstructed = SAF.replace(strictRule, originalRule);
expect(reconstructed).toBe(OAF);
});
it("difference is the strict assumption-attribution boundary only", () => {
// Extract everything except the two assumption rules and compare structure
const extractAssumptionRule = (prompt) => prompt.match(/assumptions:.*reasoning genuinely relies on it\./s)?.[0];
expect(extractAssumptionRule(OAF)).not.toBe(extractAssumptionRule(SAF));
// Remove the assumption rule from both and verify they match
const removeAssumptionRule = (prompt) => prompt.replace(/assumptions:.*reasoning genuinely relies on it\./s, "");
expect(removeAssumptionRule(OAF)).toBe(removeAssumptionRule(SAF));
});
});
// ── EXP49 — strict boundary present ──────────────────────────────────────
describe("observation+strict-assumption frontier — strict boundary assertions", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
it("contains co-mentioned facts boundary", () => {
expect(SAF).toContain("Co-mentioned");
});
it("contains contrasted facts boundary", () => {
expect(SAF).toContain("contrasted");
});
it("contains juxtaposed facts boundary", () => {
expect(SAF).toContain("juxtaposed");
});
it("contains 'do not invent a proposition merely to explain'", () => {
expect(SAF).toContain("Do not invent a proposition merely to explain why two facts can both be true.");
});
it("contains answer-dependence test", () => {
expect(SAF).toContain("the user's answer itself depends on that proposition for its meaning");
});
it("contains 'assumptions: []' fallback", () => {
expect(SAF).toContain("Otherwise return assumptions: []");
});
});
// ── EXP49 — no case contamination ────────────────────────────────────────
describe("observation+strict-assumption frontier — no case-specific language", () => {
const SAF = buildObservationStrictAssumptionFrontierPrompt(CASE);
// Extract just the assumption rule portion (starts with "assumptions:" and ends before "Identify")
const ruleMatch = SAF.match(/assumptions:.*?rely on it\./s);
const strictRule = ruleMatch?.[0] ?? "";
it("does NOT mention 'supplier payments' in the assumption rule", () => {
expect(strictRule).not.toContain("supplier payments");
});
it("does NOT mention 'formal training' in the assumption rule", () => {
expect(strictRule).not.toContain("formal training");
});
it("does NOT mention 'delegation' in the assumption rule", () => {
expect(strictRule).not.toContain("delegation");
});
it("does NOT mention 'reliable judgment' in the assumption rule", () => {
expect(strictRule).not.toContain("reliable judgment");
});
});