fix(reasoning): reconcile evidence and preserve deterministic continuation

This commit is contained in:
2026-08-17 08:06:08 +01:00
parent f2f495d5c7
commit ade445e453
6 changed files with 1373 additions and 8 deletions
+86
View File
@@ -912,6 +912,92 @@ describe("applyGraphUpdate", () => {
});
});
describe("selectActiveUnknownCandidate deterministic tie resolution", () => {
it("returns a stable non-null winner when two eligible candidates tie on top score", () => {
const decision = makeNode({
id: "n_decision_tie",
label: "Which option leaves us better off overall?",
description: "Decision context",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const launch = makeNode({
id: "opt_launch_tie",
label: "Launch this year",
description: "Launch this year.",
kind: "option",
status: "known",
confidence: "high",
});
const timeline = makeNode({
id: "n_customer_decision_timeline",
label: "When will the enterprise customer make its decision?",
description:
"Unknown when the enterprise customer will make its decision, and the timing could still affect launch planning.",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const viability = makeNode({
id: "n_launch_viability_without_anchor_customer",
label: "Is launch commercially viable without the £700,000?",
description:
"Unknown whether launching this year is still commercially viable without the £700,000 enterprise-customer revenue.",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const competitor = makeNode({
id: "n_competitor_move_first_risk",
label: "Could competitors move first during a 12-month delay?",
description:
"Unknown whether competitors could move first if launch is delayed by twelve months.",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const graph = makeGraph({
centralStatement: "Launch decision",
nodes: [decision, launch, timeline, viability, competitor],
edges: [
makeEdge({
fromNodeId: launch.id,
toNodeId: decision.id,
relationship: "contained_in",
}),
makeEdge({
fromNodeId: timeline.id,
toNodeId: launch.id,
relationship: "depends_on",
}),
makeEdge({
fromNodeId: viability.id,
toNodeId: decision.id,
relationship: "depends_on",
}),
makeEdge({
fromNodeId: competitor.id,
toNodeId: launch.id,
relationship: "contained_in",
}),
],
activeUnknownNodeId: null,
resolvedNodeIds: [],
currentSummary: "Tie case",
});
const first = selectActiveUnknownCandidate(graph, []);
const second = selectActiveUnknownCandidate(graph, []);
expect(first?.status).toBe("selected");
expect(first?.nodeId).toBeTruthy();
expect(second?.status).toBe("selected");
expect(second?.nodeId).toBe(first?.nodeId);
});
});
describe("validateGraphUpdate", () => {
it("accepts a no-op update with added nodes", () => {
const graph = makeTestGraph();