feat: decompose composite unknowns before questioning

This commit is contained in:
2026-08-02 19:24:38 +01:00
parent b1c633ba5c
commit 0723c2f49a
9 changed files with 768 additions and 25 deletions
+58
View File
@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import {
assessUnknownAtomicity,
formulateQuestion,
formulateTieResolutionQuestion,
selectInvestigationStrategy,
@@ -18,6 +19,63 @@ function makeGraphFor(node, extra = {}) {
}
describe("formulateQuestion", () => {
it("atomicity assessment leaves focused unknowns direct and marks broad explanation unknowns composite", () => {
const atomicUnknown = makeNode({
id: "n-atomic",
label: "Complaint rate denominator",
description:
"Need the denominator because it directly determines the complaint rate.",
kind: "unknown",
status: "unknown",
confidence: "high",
});
const compositeUnknown = makeNode({
id: "n-composite",
label:
"Explanation for why revenue increased by 18%, but cash in the bank fell over the same period",
description:
"Need to understand what change or event could explain why these observations differ, because that is needed to investigate their relationship.",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const compositeGraph = makeGraphFor(compositeUnknown, {
centralStatement:
"Revenue increased by 18%, but cash in the bank fell over the same period.",
nodes: [
makeNode({
id: "n-revenue-observation",
label: "Revenue increased by 18%.",
description: "Revenue increased by 18%.",
kind: "observation",
status: "supported",
confidence: "high",
}),
makeNode({
id: "n-cash-observation",
label: "Cash in the bank decreased over the same period.",
description: "Cash in the bank decreased over the same period.",
kind: "observation",
status: "supported",
confidence: "high",
}),
],
});
expect(
assessUnknownAtomicity({
node: atomicUnknown,
graph: makeGraphFor(atomicUnknown),
}).atomicity,
).toBe("atomic");
expect(
assessUnknownAtomicity({
node: compositeUnknown,
graph: compositeGraph,
}).atomicity,
).toBe("composite");
});
it("commercial viability plus build decision produces a decision-threshold question", () => {
const unknown = makeNode({
id: "n-commercial",