prompt: require candidate question for new unknowns

This commit is contained in:
2026-08-11 18:51:22 +01:00
parent a8732288eb
commit bf1f219256
2 changed files with 78 additions and 3 deletions
+2 -2
View File
@@ -114,7 +114,7 @@ The JSON object must contain exactly these top-level fields:
13a. For every new unknown node, include at least one added edge that connects it to an existing updated/resolved node or to a newly added non-unknown node introduced from the answer.
14. Do not invent evidence.
15. Do not create unsupported causal edges.
16. If consequential unresolved unknowns exist, selectedQuestion may identify one valid candidate unknown, but the engine will deterministically choose final priority after validation.
16. When your proposal adds one or more new unresolved unknowns (status !== 'resolved'), you MUST include a selectedQuestion identifying one of those as a candidate unknown node. The engine validates your candidate and retains deterministic final-priority selection; your candidate does not need to be the highest-scoring unknown — it only needs to be a valid unresolved unknown that exists in the graph or in addedNodes.
17. selectedQuestion.nodeId must reference an unresolved unknown node that exists either already in the graph or in addedNodes.
18. selectedQuestion.question must be one narrow non-compound question about that one unknown.
19. Do not prioritise downstream implementation, pricing, optimisation, or speculative branches ahead of prerequisite definitions, actors, success criteria, constraints, measures, or terminology.
@@ -140,7 +140,7 @@ The JSON object must contain exactly these top-level fields:
- 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.
- If you add a new unknown, its description must do two jobs in one sentence: what is unknown, and why resolving it matters for the case.
- Treat selectedQuestion as a candidate only; the engine will apply deterministic information-value scoring after validation.
- When selectedQuestion is provided, your role ends at supplying one valid unresolved unknown node from the graph or addedNodes — the engine retains deterministic final-priority selection and may choose a different question if multiple candidates exist.
- 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.
- If rule #6 applies but you choose an update/refinement of existing structure, resolve an existing unknown, or add justified new structure, your structural proposal plus answerMeaning together represent the complete response — answerMeaning preserves semantic fidelity while structural mutation handles graph progress; neither replaces the other.
- If you add a new unknown with addedNodes, connect it with at least one addedEdge to an existing updated/resolved node or to a newly added non-unknown node from the answer.
+76 -1
View File
@@ -109,7 +109,7 @@ describe("buildGraphUpdatePrompt", () => {
"selectedQuestion.question must be one narrow non-compound question",
);
expect(prompt).toContain(
"the engine will deterministically choose final priority after validation",
"engine retains deterministic final-priority selection",
);
});
@@ -560,3 +560,78 @@ describe("buildGraphUpdatePrompt — 57J.55 uncertainty identity vs topical over
expect(guidance).toContain("preserves semantic fidelity");
});
});
// ── Experiment 57J.59 — Selected-Question Contract Alignment ──────────
describe("buildGraphUpdatePrompt — 57J.59 selected-question contract alignment", () => {
function getRule(prompt, ruleNum) {
return prompt.split("\n").find((l) => l.trimStart().startsWith(`${ruleNum}. `));
}
// Test 1 — added consequential unresolved unknown → selectedQuestion is explicitly mandatory
it("test 1: rule #16 says you MUST include selectedQuestion when adding new unresolved unknowns", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(prompt).toContain("MUST include a selectedQuestion");
expect(prompt).toContain("adds one or more new unresolved unknowns");
});
// Test 2 — wording no longer uses permissive "may" for this condition
it("test 2: rule #16 does not use 'may' to describe the selectedQuestion obligation", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(getRule(prompt, 16)).not.toContain("may identify");
});
// Test 3 — model is required to provide a valid candidate, not necessarily the best/final candidate
it("test 3: rule #16 states candidate does not need to be highest-scoring unknown", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(getRule(prompt, 16)).toContain("does not need to be the highest-scoring unknown");
});
// Test 4 — engine retains deterministic final-priority ownership
it("test 4: rule #16 states engine retains deterministic final-priority selection", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(getRule(prompt, 16)).toContain("engine validates your candidate and retains deterministic final-priority selection");
});
// Test 5 — null remains permitted when the triggering condition does not apply (rule #20)
it("test 5: rule #20 still permits null selectedQuestion when no consequential unresolved unknown remains", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(prompt).toContain("Return selectedQuestion as null only when no consequential unresolved unknown remains");
});
// Test 6 — rule does not claim updatedNodes triggers the requirement
it("test 6: rule #16 trigger is new added unknowns, not updatedNodes", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(getRule(prompt, 16)).not.toContain("updatedNode");
expect(getRule(prompt, 16)).not.toContain("updated node");
});
// Test 7 — rule does not claim actual resolution of an answered node is required
it("test 7: rule #16 trigger does not depend on resolved nodes", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(getRule(prompt, 16)).not.toContain("resolvedUnknownNodeIds");
expect(getRule(prompt, 16)).not.toContain("after resolut");
});
// Test 8 — existing selectedQuestion node-validity requirements remain intact (rule #17)
it("test 8: rule #17 nodeId validity requirement is preserved", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(prompt).toContain("selectedQuestion.nodeId must reference an unresolved unknown node that exists either already in the graph or in addedNodes");
});
// Test 9 — uncertainty-identity guidance from v0.21 remains intact (same-resolution-question definition)
it("test 9: uncertainty identity 'same resolution question' guidance is preserved", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(prompt).toContain("Same uncertainty");
expect(prompt).toContain("same resolution question");
expect(prompt).toContain("topical overlap");
});
// Test 10 — structured semantic fidelity guidance remains intact (supportCategory + resolutionGuidance)
it("test 10: structured semantic fidelity rules are preserved", () => {
const prompt = buildGraphUpdatePrompt(makeContext());
expect(prompt).toContain("supportCategory");
expect(prompt).toContain("resolutionGuidance");
expect(prompt).toContain("genuinely new concepts");
});
});