fix: handle unjustified unknown selection ties

This commit is contained in:
2026-08-02 16:09:00 +01:00
parent a1f6d0c2b9
commit 51ce356218
8 changed files with 731 additions and 145 deletions
+110 -10
View File
@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";
import {
formulateQuestion,
formulateTieResolutionQuestion,
selectInvestigationStrategy,
} from "@/lib/graph/question-formulator.js";
import { makeEdge, makeGraph, makeNode } from "@/lib/graph/schema.js";
@@ -178,16 +179,24 @@ describe("formulateQuestion", () => {
});
it("the same unknown can produce different questions when paired with different strategies", () => {
const unknown = makeNode({
id: "n-same-unknown",
const thresholdUnknown = makeNode({
id: "n-threshold-unknown",
label: "Value threshold",
description: "Need to resolve the value threshold.",
kind: "unknown",
status: "unknown",
confidence: "high",
});
const definitionUnknown = makeNode({
id: "n-definition-unknown",
label: "Value term",
description: "Need to resolve what value term refers to in this context.",
kind: "unknown",
status: "unknown",
confidence: "high",
});
const decisionGraph = makeGraphFor(unknown, {
const decisionGraph = makeGraphFor(thresholdUnknown, {
centralStatement: "We are deciding whether to launch this product.",
nodes: [
makeNode({
@@ -197,35 +206,35 @@ describe("formulateQuestion", () => {
kind: "state",
status: "known",
confidence: "medium",
childIds: [unknown.id],
childIds: [thresholdUnknown.id],
value: "Deciding whether to launch the product",
}),
],
});
const definitionGraph = makeGraphFor(unknown, {
const definitionGraph = makeGraphFor(definitionUnknown, {
centralStatement:
"The team uses the term value threshold inconsistently.",
nodes: [
makeNode({
id: "n-definition",
label: "Definition disagreement",
label: "Definition disagreement about value threshold",
description:
"Need a definition of value threshold before comparing options.",
"Need a definition of value threshold because the term is used inconsistently before comparing options.",
kind: "state",
status: "known",
confidence: "medium",
childIds: [unknown.id],
childIds: [definitionUnknown.id],
}),
],
});
const decisionResult = formulateQuestion({
node: unknown,
node: thresholdUnknown,
graph: decisionGraph,
});
const definitionResult = formulateQuestion({
node: unknown,
node: definitionUnknown,
graph: definitionGraph,
});
@@ -296,4 +305,95 @@ describe("formulateQuestion", () => {
"What would resolve uncertainty regarding",
);
});
it("ambiguous contradiction produces a broad distinguishing question without accounting jargon", () => {
const unknown = makeNode({
id: "n-cause-a",
label: "Cash outflow cause",
description: "Unclear explanation for the contradiction.",
kind: "unknown",
status: "unknown",
confidence: "high",
});
const contradiction = makeNode({
id: "n-contradiction",
label: "Divergent movement between revenue and cash",
description: "Two signals moved in opposite directions.",
kind: "relationship",
status: "supported",
confidence: "medium",
});
const graph = makeGraphFor(unknown, {
centralStatement:
"Revenue increased by 18%, but cash in the bank fell over the same period.",
nodes: [contradiction],
});
const result = formulateTieResolutionQuestion({ graph });
expect(result.question).toBe(
"What changed during the period that could explain why Revenue increased by 18%, but cash in the bank fell over the same period?",
);
expect(result.question.toLowerCase()).not.toMatch(
/accounts receivable|capex|debt repayments|working capital/,
);
});
it("definition is selected only for genuine definition unknowns", () => {
const unknown = makeNode({
id: "n-definition-only",
label: "Definition of success criteria",
description: "The term is used inconsistently and needs a definition.",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const result = formulateQuestion({
node: unknown,
graph: makeGraphFor(unknown),
});
expect(result.strategy).toBe("definition");
});
it("an unknown about possible causes does not become a definition question", () => {
const unknown = makeNode({
id: "n-causes",
label: "Possible causes of the divergence",
description: "Several causes may explain the divergence.",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const result = formulateQuestion({
node: unknown,
graph: makeGraphFor(unknown),
});
expect(result.strategy).toBeNull();
expect(result.question).toBe(
"What would clarify possible causes of the divergence in this situation?",
);
});
it("malformed punctuation is rejected", () => {
const unknown = makeNode({
id: "n-punct",
label: "Magnitude and nature of cash outflows (operating expenses).",
description:
"Magnitude and nature of cash outflows (operating expenses).",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const result = formulateQuestion({
node: unknown,
graph: makeGraphFor(unknown),
});
expect(result.question).not.toContain("). is true?");
expect(result.question).toBe(
"What would clarify magnitude and nature of cash outflows (operating expenses) in this situation?",
);
});
});