fix(reasoning): recognise decision in sufficiency question
This commit is contained in:
@@ -1105,7 +1105,7 @@ describe("formulateQuestion", () => {
|
||||
id: "n_product_launch_decision",
|
||||
label: "Whether to launch product X",
|
||||
description: "Launch vs not launch decision for product X.",
|
||||
kind: "state",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
childIds: [],
|
||||
@@ -1137,7 +1137,7 @@ describe("formulateQuestion", () => {
|
||||
id: "n_product_launch_decision",
|
||||
label: "Whether to launch product X",
|
||||
description: "Launch vs not launch decision for product X.",
|
||||
kind: "state",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
});
|
||||
@@ -1170,7 +1170,7 @@ describe("formulateQuestion", () => {
|
||||
id: "n_product_launch_decision",
|
||||
label: "Whether to launch product X",
|
||||
description: "Launch vs not launch decision.",
|
||||
kind: "state",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
childIds: [factor.id],
|
||||
@@ -1201,7 +1201,7 @@ describe("formulateQuestion", () => {
|
||||
id: "n_product_launch_decision",
|
||||
label: "Whether to launch product X",
|
||||
description: "Launch vs not launch decision.",
|
||||
kind: "state",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
});
|
||||
@@ -1261,7 +1261,7 @@ describe("formulateQuestion", () => {
|
||||
id: "n-decision",
|
||||
label: "Build decision",
|
||||
description: "Decision introduced by the answer.",
|
||||
kind: "state",
|
||||
kind: "unknown",
|
||||
status: "known",
|
||||
confidence: "medium",
|
||||
childIds: [unknown.id],
|
||||
@@ -1294,7 +1294,7 @@ describe("formulateQuestion", () => {
|
||||
id: "n_product_launch_decision",
|
||||
label: "Whether to launch product X",
|
||||
description: "Launch vs not launch decision.",
|
||||
kind: "state",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
childIds: [factor.id],
|
||||
@@ -1325,7 +1325,7 @@ describe("formulateQuestion", () => {
|
||||
id: "n_product_launch_decision",
|
||||
label: "Whether to launch product X",
|
||||
description: "Launch vs not launch decision.",
|
||||
kind: "state",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
});
|
||||
@@ -1342,3 +1342,211 @@ describe("formulateQuestion", () => {
|
||||
expect(result.reason).toContain("material factors");
|
||||
});
|
||||
});
|
||||
|
||||
// ── 60B.75 — real decision detection for sufficiency question ────
|
||||
|
||||
describe("60B.75 — real decision detection for sufficiency question", () => {
|
||||
it("Test 1 — actual decision representation reaches State B", () => {
|
||||
const decision = makeNode({
|
||||
id: "n_product_launch_decision",
|
||||
label: "Which option leaves us better off overall?",
|
||||
description:
|
||||
"Uncertainty about which product-launch timing option provides superior net value.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
});
|
||||
|
||||
const graph = makeGraphFor(decision, { nodes: [], edges: [] });
|
||||
|
||||
expect(hasRemainingMaterialFactors(decision.id, graph)).toBe(false);
|
||||
|
||||
const result = formulateQuestion({
|
||||
node: decision,
|
||||
graph,
|
||||
context: { resolvedValues: [] },
|
||||
});
|
||||
|
||||
expect(result.questionFamily).toBe("decision_threshold");
|
||||
expect(result.selectedQuestionTemplate).toBe(
|
||||
"decision_threshold_sufficiency_confirmation",
|
||||
);
|
||||
expect(result.question).toContain("anything else material");
|
||||
expect(result.reasoningPattern).toBe("decision");
|
||||
});
|
||||
|
||||
it("Test 2 — ordinary unknown factor does NOT trigger State B", () => {
|
||||
const unknown = makeNode({
|
||||
id: "n_evidence_unknown",
|
||||
label: "Evidence of demand",
|
||||
description: "Need evidence of demand.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
});
|
||||
|
||||
const graph = makeGraphFor(unknown);
|
||||
|
||||
const result = formulateQuestion({
|
||||
node: unknown,
|
||||
graph,
|
||||
});
|
||||
|
||||
expect(result.selectedQuestionTemplate).not.toBe(
|
||||
"decision_threshold_sufficiency_confirmation",
|
||||
);
|
||||
});
|
||||
|
||||
it("Test 3 — genuine decision with remaining factor does NOT trigger State B", () => {
|
||||
const factor = makeNode({
|
||||
id: "n_customer_readiness",
|
||||
label: "Customer readiness level",
|
||||
description: "How ready the customer is to adopt.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
parentId: "n_product_launch_decision",
|
||||
});
|
||||
|
||||
const decision = makeNode({
|
||||
id: "n_product_launch_decision",
|
||||
label: "Which option leaves us better off overall?",
|
||||
description: "Uncertainty about which product-launch timing option provides superior net value.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
childIds: [factor.id],
|
||||
});
|
||||
|
||||
const graph = makeGraphFor(factor, {
|
||||
nodes: [decision],
|
||||
edges: [],
|
||||
});
|
||||
|
||||
expect(hasRemainingMaterialFactors(decision.id, graph)).toBe(true);
|
||||
|
||||
const result = formulateQuestion({
|
||||
node: decision,
|
||||
graph,
|
||||
context: { resolvedValues: [] },
|
||||
});
|
||||
|
||||
expect(result.selectedQuestionTemplate).not.toBe(
|
||||
"decision_threshold_sufficiency_confirmation",
|
||||
);
|
||||
});
|
||||
|
||||
it("Test 4 — explicit confirmation still prevents question path", () => {
|
||||
const decision = makeNode({
|
||||
id: "n_product_launch_decision",
|
||||
label: "Which option leaves us better off overall?",
|
||||
description:
|
||||
"Uncertainty about which product-launch timing option provides superior net value.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
});
|
||||
|
||||
const graph = makeGraphFor(decision, { nodes: [], edges: [] });
|
||||
|
||||
const result = formulateQuestion({
|
||||
node: decision,
|
||||
graph,
|
||||
context: {
|
||||
resolvedValues: ["no other material uncertainty remains"],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.selectedQuestionTemplate).not.toBe(
|
||||
"decision_threshold_sufficiency_confirmation",
|
||||
);
|
||||
});
|
||||
|
||||
it("Test 5 — existing decision_threshold case preserved", () => {
|
||||
const unknown = makeNode({
|
||||
id: "n-commercial",
|
||||
label: "Uncertainty regarding the commercial value of the product",
|
||||
description:
|
||||
"Commercial justification remains unclear because the decision depends on it.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
parentId: "n-decision",
|
||||
});
|
||||
|
||||
const decision = makeNode({
|
||||
id: "n-decision",
|
||||
label: "Build decision",
|
||||
description: "Decision introduced by the answer.",
|
||||
kind: "unknown",
|
||||
status: "known",
|
||||
confidence: "medium",
|
||||
childIds: [unknown.id],
|
||||
});
|
||||
|
||||
const graph = makeGraphFor(unknown, {
|
||||
nodes: [decision],
|
||||
resolvedNodeIds: [decision.id],
|
||||
});
|
||||
|
||||
const result = formulateQuestion({ node: unknown, graph });
|
||||
|
||||
expect(result.questionFamily).toBe("decision_threshold");
|
||||
});
|
||||
|
||||
it("Test 6 — exact 60B.73-style production-shaped fixture", () => {
|
||||
const optLaunch = makeNode({
|
||||
id: "opt_launch_this_year",
|
||||
label: "Launch this year",
|
||||
description: "New software product launches this year.",
|
||||
kind: "unknown",
|
||||
status: "known",
|
||||
confidence: "high",
|
||||
parentId: "n_product_launch_decision",
|
||||
});
|
||||
|
||||
const optWait = makeNode({
|
||||
id: "opt_wait_twelve_months",
|
||||
label: "Wait twelve months",
|
||||
description: "Defer product launch by twelve months.",
|
||||
kind: "unknown",
|
||||
status: "known",
|
||||
confidence: "high",
|
||||
parentId: "n_product_launch_decision",
|
||||
});
|
||||
|
||||
const decision = makeNode({
|
||||
id: "n_product_launch_decision",
|
||||
label: "Which option leaves us better off overall?",
|
||||
description:
|
||||
"Uncertainty about which of the two product-launch timing options — launch this year or wait twelve months — provides superior net value for the organisation.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
childIds: [optLaunch.id, optWait.id],
|
||||
});
|
||||
|
||||
const graph = makeGraphFor(decision, {
|
||||
nodes: [optLaunch, optWait],
|
||||
edges: [
|
||||
{ id: "e-opt-launch-to-dec", fromNodeId: optLaunch.id, toNodeId: decision.id, relationship: "contained_in", confidence: "high", description: "Launch this year option is a candidate for the product launch decision" },
|
||||
{ id: "e-opt-wait-to-dec", fromNodeId: optWait.id, toNodeId: decision.id, relationship: "contained_in", confidence: "high", description: "Wait twelve months option is a candidate for the product launch decision" },
|
||||
],
|
||||
});
|
||||
|
||||
expect(hasRemainingMaterialFactors(decision.id, graph)).toBe(false);
|
||||
|
||||
const result = formulateQuestion({
|
||||
node: decision,
|
||||
graph,
|
||||
context: { resolvedValues: [] },
|
||||
});
|
||||
|
||||
expect(result.questionFamily).toBe("decision_threshold");
|
||||
expect(result.selectedQuestionTemplate).toBe(
|
||||
"decision_threshold_sufficiency_confirmation",
|
||||
);
|
||||
expect(result.reasoningPattern).toBe("decision");
|
||||
expect(result.question).toContain("anything else material");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user