From b8e6745c153a62114a8c1c973be5734d09c78dab Mon Sep 17 00:00:00 2001 From: robbond Date: Tue, 11 Aug 2026 17:47:12 +0100 Subject: [PATCH] prompt: distinguish uncertainty identity from topical overlap --- lib/graph/prompt-builder.js | 1 + tests/graph/prompt-builder.test.js | 87 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/lib/graph/prompt-builder.js b/lib/graph/prompt-builder.js index 9d32c5f..0fa7408 100644 --- a/lib/graph/prompt-builder.js +++ b/lib/graph/prompt-builder.js @@ -135,6 +135,7 @@ The JSON object must contain exactly these top-level fields: ## Additional Guidance - If the answer only clarifies an existing unknown, prefer updatedNodes and resolvedUnknownNodeIds over creating duplicate nodes. - 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. +- "Same uncertainty" means the same resolution question: resolving the existing unknown would also resolve the uncertainty introduced by the user's answer. Mere topical overlap (concerning the same topic, object, decision, or domain) is not automatically the same uncertainty. If the new concern can remain unresolved after the existing node is resolved, represent it separately as a distinct uncertainty. - When an answer resolves an existing unknown, include that existing node ID in resolvedUnknownNodeIds and update that node rather than creating only a parallel observation. - If the answer creates a more specific decision situation, add the smallest set of new nodes and edges needed to represent that situation and only its most consequential unknowns. - If you add a new unknown, do not leave it floating: connect it with an added edge to the relevant decision/context node created or updated from the answer. diff --git a/tests/graph/prompt-builder.test.js b/tests/graph/prompt-builder.test.js index 0c58f9d..7486f34 100644 --- a/tests/graph/prompt-builder.test.js +++ b/tests/graph/prompt-builder.test.js @@ -473,3 +473,90 @@ describe("buildGraphUpdatePrompt — 57J.46 existing-first uncertainty fallback" expect(prompt).not.toContain("ollama"); }); }); + +// ── Experiment 57J.55 — uncertainty identity vs topical overlap ───────── + +describe("buildGraphUpdatePrompt — 57J.55 uncertainty identity vs topical overlap", () => { + function getAdditionalGuidance(prompt) { + return prompt.split("## Additional Guidance")[1]; + } + + // Test 1 — "same uncertainty" defined by same resolution question + it("test 1: 'same uncertainty' is defined in terms of the same resolution question", () => { + const prompt = buildGraphUpdatePrompt(makeContext()); + const guidance = getAdditionalGuidance(prompt); + expect(guidance).toContain("same resolution question"); + }); + + // Test 2 — topical overlap explicitly insufficient + it("test 2: topical overlap is explicitly not sufficient for 'same uncertainty'", () => { + const prompt = buildGraphUpdatePrompt(makeContext()); + const guidance = getAdditionalGuidance(prompt); + expect(guidance).toContain("topical overlap"); + }); + + // Test 3 — independent resolvability means distinct uncertainty + it("test 3: uncertainty that can remain unresolved after existing is resolved is distinct", () => { + const prompt = buildGraphUpdatePrompt(makeContext()); + const guidance = getAdditionalGuidance(prompt); + expect(guidance).toContain("remain unresolved"); + }); + + // Test 4 — equivalent savings-uncertainty wording prefers reuse/refine (via existing-first) + it("test 4: existing-first ordering ensures equivalent uncertainties are refined not duplicated", () => { + const prompt = buildGraphUpdatePrompt(makeContext()); + const guidance = getAdditionalGuidance(prompt); + expect(guidance).toContain("first check whether an existing unresolved node"); + expect(guidance).toContain("if so, update/refine that existing structure rather than adding a duplicate"); + }); + + // Test 5 — broad cost vs savings realism requires distinct unknown + it("test 5: the guidance prevents broad nodes from automatically absorbing sub-concerns", () => { + const prompt = buildGraphUpdatePrompt(makeContext()); + const guidance = getAdditionalGuidance(prompt); + expect(guidance).toContain("not automatically"); + }); + + // Test 6 — retention vs productivity domain overlap handled separately + it("test 6: unrelated domains remain separate even if superficially topical", () => { + const prompt = buildGraphUpdatePrompt(makeContext()); + const guidance = getAdditionalGuidance(prompt); + expect(guidance).toContain("separately"); + }); + + // Test 7 — duplicate avoidance preserved (not weakened) + it("test 7: existing duplicate-avoidance remains intact", () => { + const prompt = buildGraphUpdatePrompt(makeContext()); + expect(prompt).toContain("Do not add duplicate unknowns"); + const guidance = getAdditionalGuidance(prompt); + expect(guidance).toContain("prefer updatedNodes and resolvedUnknownNodeIds over creating duplicate nodes"); + }); + + // Test 8 — existing-first ordering preserved (not displaced) + it("test 8: existing-first ordering is intact in the assembled prompt", () => { + const prompt = buildGraphUpdatePrompt(makeContext()); + const guidance = getAdditionalGuidance(prompt); + expect(guidance).toContain("first check whether an existing unresolved node"); + expect(guidance).toContain("if no such node exists, add a new unknown"); + }); + + // Test 9 — no keyword/synonym/semantic-matching machinery added + it("test 9: 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"); + expect(prompt).not.toContain("embedding"); + expect(prompt).not.toContain("similarity"); + }); + + // Test 10 — structured semantic fidelity preserved (supportCategory, resolutionGuidance) + it("test 10: structured semantic fidelity instructions remain intact", () => { + const prompt = buildGraphUpdatePrompt(makeContext()); + expect(prompt).toContain("supportCategory"); + expect(prompt).toContain("resolutionGuidance"); + expect(prompt).toContain("genuinely new concepts"); + const guidance = getAdditionalGuidance(prompt); + expect(guidance).toContain("preserves semantic fidelity"); + }); +});