From 437aadc587a86dafa63ad9313525a6982460faa3 Mon Sep 17 00:00:00 2001 From: robbond Date: Fri, 14 Aug 2026 07:01:23 +0100 Subject: [PATCH] fix(reasoning): honor explicit whether propositions --- lib/graph/question-formulator.js | 7 ++- tests/graph/question-formulator.test.js | 74 +++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/lib/graph/question-formulator.js b/lib/graph/question-formulator.js index e09552c..e14075a 100644 --- a/lib/graph/question-formulator.js +++ b/lib/graph/question-formulator.js @@ -118,10 +118,11 @@ function extractMeaning(node) { }; if ( - /\b(status|likelihood|probability|chance|risk|uncertainty)\b/i.test( + /^whether\s+/i.test(strippedDescription) && + (/\b(status|likelihood|probability|chance|risk|uncertainty)\b/i.test( String(node?.label || ""), - ) && - /^whether\s+/i.test(strippedDescription) + ) || + /^whether\s+/i.test(description)) ) { return sentenceCase(extractWhetherProposition(strippedDescription)); } diff --git a/tests/graph/question-formulator.test.js b/tests/graph/question-formulator.test.js index aaebb98..3146adb 100644 --- a/tests/graph/question-formulator.test.js +++ b/tests/graph/question-formulator.test.js @@ -893,6 +893,53 @@ describe("formulateQuestion", () => { ); }); + it("60B.31 regression: bare 'Whether...' description defines proposition even with nominal label", () => { + const unknown = makeNode({ + id: "unc-60b31", + label: "Enterprise customer signing decision", + description: + "Whether the prospective enterprise customer will commit this year, because resolving this uncertainty is needed to decide if launching this year provides superior net value over waiting twelve months.", + kind: "unknown", + status: "unknown", + confidence: "medium", + }); + + const graph = makeGraphFor(unknown, { + centralStatement: + "We need to decide whether launching this year provides superior net value over waiting twelve months.", + }); + + const result = formulateQuestion({ node: unknown, graph }); + + expect(result.question).toBe( + "What evidence would clarify whether the prospective enterprise customer will commit this year?", + ); + expect(result.question).not.toContain("launching"); + expect(result.question).not.toContain("superior net value"); + expect(result.question).not.toContain("waiting twelve months"); + expect(result.question).not.toContain("because"); + }); + + it("bare 'Whether...' with unrelated nominal label remains proposition-specific", () => { + const unknown = makeNode({ + id: "unc-bare-nominal", + label: "Supplier contract decision", + description: "Whether the supplier will renew the contract.", + kind: "unknown", + status: "unknown", + confidence: "medium", + }); + + const result = formulateQuestion({ + node: unknown, + graph: makeGraphFor(unknown), + }); + + expect(result.question).toBe( + "What evidence would clarify whether the supplier will renew the contract?", + ); + }); + it("bare 'Whether...' remains unchanged (existing behaviour)", () => { const unknown = makeNode({ id: "unc-bare-whether", @@ -980,6 +1027,33 @@ describe("formulateQuestion", () => { ); }); + it("generic non-proposition decision unknown remains on its existing non-proposition path", () => { + const unknown = makeNode({ + id: "unc-generic-decision", + label: "Launch decision value threshold", + description: + "Need to determine what outcome would be sufficient to justify launching this year.", + kind: "unknown", + status: "unknown", + confidence: "medium", + }); + + const result = formulateQuestion({ + node: unknown, + graph: makeGraphFor(unknown, { + centralStatement: + "We need to decide whether launching this year provides superior net value over waiting twelve months.", + }), + }); + + expect(result.question).not.toContain( + "whether the prospective enterprise customer will commit this year", + ); + expect(result.question).not.toContain( + "whether the supplier will renew the contract", + ); + }); + it("nominal label without explicit 'whether...' falls back to label-based extraction", () => { const unknown = makeNode({ id: "unc-nominal",