prompt: add existing-first uncertainty fallback
Add one explicit action-order rule in Additional Guidance for when rule #6 applies to explicitly unresolved uncertainty: 1. First check whether an existing unresolved node already represents the same uncertainty. 2. If so, update/refine that existing structure rather than creating a duplicate. 3. If no such node exists, add a new unknown that directly represents the unresolved uncertainty. 4. Do not use an edge alone to represent a previously unrepresented uncertainty. 14 focused prompt tests verify: existing-first ordering, reuse path, fallback-to-add, related-node-insufficient, edge-only-prohibited, possibleInference separation, resolution path preserved, duplicate contract preserved, scope uncertainty-only, fidelity/traceability preserved, noop validator untouched, no semantic classifier added.
This commit is contained in:
@@ -281,3 +281,155 @@ describe("buildGraphUpdatePrompt — semantic-to-mutation MUST rule", () => {
|
||||
expect(fullPrompt).not.toContain("must add a new node");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Experiment 57J.46 — existing-first uncertainty fallback ───
|
||||
|
||||
describe("buildGraphUpdatePrompt — 57J.46 existing-first uncertainty fallback", () => {
|
||||
function getAdditionalGuidance(prompt) {
|
||||
return prompt.split("## Additional Guidance")[1];
|
||||
}
|
||||
|
||||
// Test 1 — existing-first ordering exists
|
||||
it("test 1: assembled prompt explicitly says to check for an equivalent unresolved unknown first", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
expect(guidance).toContain("first check whether an existing unresolved node");
|
||||
expect(guidance).toContain("represents the same uncertainty");
|
||||
});
|
||||
|
||||
// Test 2 — reuse path explicit
|
||||
it("test 2: prompt says update/refine existing structure rather than add a duplicate when equivalent exists", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
expect(guidance).toContain("if so, update/refine that existing structure");
|
||||
expect(guidance).toContain("rather than adding a duplicate");
|
||||
});
|
||||
|
||||
// Test 3 — fallback-to-add explicit
|
||||
it("test 3: prompt explicitly requires adding a new unknown when no equivalent unresolved unknown exists", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
expect(guidance).toContain("if no such node exists");
|
||||
expect(guidance).toContain("add a new unknown that directly represents the unresolved uncertainty");
|
||||
});
|
||||
|
||||
// Test 4 — ordered fallback means: existing first, otherwise add
|
||||
it("test 4: full ordered fallback is present in the assembled prompt", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
// The entire rule must be present as a single coherent instruction:
|
||||
expect(guidance).toContain(
|
||||
"When rule #6 applies to explicitly unresolved uncertainty: first check whether an existing unresolved node already represents the same uncertainty; if so, update/refine that existing structure rather than adding a duplicate; if no such node exists, add a new unknown that directly represents the unresolved uncertainty; do not use an edge alone to represent a previously unrepresented uncertainty.",
|
||||
);
|
||||
});
|
||||
|
||||
// Test 5 — merely related node is insufficient
|
||||
it("test 5: prompt does not imply a general related state/cost node counts as representing the same uncertainty", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
// The rule requires "same uncertainty" — not "related" or "similar":
|
||||
expect(guidance).toContain("same uncertainty");
|
||||
// Must not use weaker criteria:
|
||||
expect(guidance).not.toContain("similar");
|
||||
expect(guidance).not.toContain("related to");
|
||||
});
|
||||
|
||||
// Test 6 — edge-only insufficient
|
||||
it("test 6: prompt explicitly prevents using an edge alone to represent previously unrepresented uncertainty", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
expect(guidance).toContain(
|
||||
"do not use an edge alone to represent a previously unrepresented uncertainty",
|
||||
);
|
||||
});
|
||||
|
||||
// Test 7 — possibleInference does not create unknowns
|
||||
it("test 7: existing possibleInference separation remains intact — rule #27 still separates interpretation from userSupportedMeaning", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
expect(prompt).toContain(
|
||||
"Put any stronger interpretation in answerMeaning.possibleInference, not in userSupportedMeaning",
|
||||
);
|
||||
// The 57J.46 rule must NOT reference possibleInference as a trigger:
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
expect(guidance).not.toContain("possibleInference");
|
||||
});
|
||||
|
||||
// Test 8 — actual resolution path preserved
|
||||
it("test 8: prompt still allows resolution when the user's answer genuinely resolves an existing unknown", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
// The "resolve existing" guidance must remain intact:
|
||||
expect(prompt).toContain(
|
||||
"include that existing node ID in resolvedUnknownNodeIds",
|
||||
);
|
||||
expect(prompt).toContain("update that node rather than creating only a parallel observation");
|
||||
// Rule #5 (resolve answered unknown first) must still exist:
|
||||
expect(prompt).toContain("Resolve the answered unknown first when the answer supports it");
|
||||
});
|
||||
|
||||
// Test 9 — duplicate validator/contract preserved
|
||||
it("test 9: existing duplicate-avoidance wording remains unchanged", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
expect(prompt).toContain("Do not add duplicate unknowns");
|
||||
expect(prompt).toContain("genuinely new concepts");
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
expect(guidance).toContain("prefer updatedNodes and resolvedUnknownNodeIds over creating duplicate nodes");
|
||||
});
|
||||
|
||||
// Test 10 — scope remains uncertainty-only (not universal to all categories)
|
||||
it("test 10: the new action-order rule does not apply universally to facts, constraints, decisions, or other meaning categories", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
// The rule must be scoped to "unresolved uncertainty" specifically:
|
||||
expect(guidance).toContain("explicitly unresolved uncertainty");
|
||||
// It must not say "any answer" or "all categories":
|
||||
expect(guidance).not.toContain("any answer");
|
||||
expect(guidance).not.toContain("every change");
|
||||
expect(guidance).not.toContain("all categories");
|
||||
// Rule #7 (new unknown conditions) and other category rules must be untouched:
|
||||
expect(prompt).toContain(
|
||||
"Add new unknown nodes only when the answer introduces a new decision, claim, object, measure, dependency, or unresolved term directly relevant to the case",
|
||||
);
|
||||
});
|
||||
|
||||
// Test 11 — fidelity / possibleInference separation preserved
|
||||
it("test 11: fidelity rule separating userSupportedMeaning from possibleInference is untouched", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
expect(prompt).toContain(
|
||||
"answerMeaning.userSupportedMeaning must state only what the user's answer directly supports",
|
||||
);
|
||||
});
|
||||
|
||||
// Test 12 — traceability preserved
|
||||
it("test 12: traceability requirement for new unknowns remains intact", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
expect(prompt).toContain(
|
||||
"Every new unknown must be directly traceable to the user's answer and its description must state why that uncertainty matters",
|
||||
);
|
||||
});
|
||||
|
||||
// Test 13 — no noop validator changed
|
||||
it("test 13: the 'rule #6 does not apply → empty arrays' permission is preserved unchanged", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
const guidance = getAdditionalGuidance(prompt);
|
||||
expect(guidance).toContain(
|
||||
"If rule #6 does not apply (the answer contains no user-supported meaning that requires graph progress) and there is no other justification for change, return empty arrays for every category",
|
||||
);
|
||||
});
|
||||
|
||||
// Test 14 — no semantic classifier or keyword logic added
|
||||
it("test 14: no new deterministic semantic matcher or keyword matching was added", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
expect(prompt).not.toContain("threshold");
|
||||
expect(prompt).not.toContain("synonym");
|
||||
expect(prompt).not.toContain("keyword match");
|
||||
});
|
||||
|
||||
// Test 15 — provider-agnostic preserved
|
||||
it("test 15: no provider-specific wording added", () => {
|
||||
const prompt = buildGraphUpdatePrompt(makeContext());
|
||||
expect(prompt).not.toContain("qwen");
|
||||
expect(prompt).not.toContain("claude");
|
||||
expect(prompt).not.toContain("gpt");
|
||||
expect(prompt).not.toContain("ollama");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user