feat: back next questions with explicit graph unknowns

This commit is contained in:
2026-08-02 19:03:07 +01:00
parent 25a989450c
commit b1c633ba5c
7 changed files with 310 additions and 40 deletions
+61
View File
@@ -1133,6 +1133,9 @@ describe("applyValidatedProposal", () => {
expect(result.resolvedReasoningNodeIds).toEqual([
"reasoning:comparability",
]);
expect(result.emergentReasoningNodeCreated).toBe(true);
expect(result.emergentReasoningNodeId).toBeTruthy();
expect(result.emergentReasoningNodeReason).toContain("backed by the graph");
expect(result.previousReasoningState.comparabilityStatus).toBe("uncertain");
expect(result.reasoningState).toMatchObject({
comparabilityStatus: "confirmed",
@@ -1142,6 +1145,7 @@ describe("applyValidatedProposal", () => {
expect(result.reasoningState.comparabilityEvidence).toEqual([
comparabilityUnknownId,
]);
expect(result.selectedQuestion?.nodeId).toBe(result.newActiveUnknownNodeId);
expect(result.selectedQuestion?.question).toMatch(
/^What changed during that period that could help explain why /,
);
@@ -1163,6 +1167,27 @@ describe("applyValidatedProposal", () => {
"The observations concern connected business signals but do not establish a direct contradiction or cause.",
},
]);
const emergentNode = result.updatedSituationGraph.nodes.find(
(node) => node.id === result.emergentReasoningNodeId,
);
expect(emergentNode).toMatchObject({
kind: "unknown",
status: "unknown",
confidence: "medium",
});
expect(emergentNode.description.toLowerCase()).toContain("because");
expect(
result.updatedSituationGraph.edges.filter(
(edge) => edge.toNodeId === result.emergentReasoningNodeId,
),
).not.toEqual([]);
expect(
result.updatedSituationGraph.edges.some(
(edge) =>
edge.toNodeId === result.emergentReasoningNodeId &&
edge.relationship === "causes",
),
).toBe(false);
expect(
JSON.stringify(
result.updatedSituationGraph.nodes.find(
@@ -1171,4 +1196,40 @@ describe("applyValidatedProposal", () => {
),
).toBe(originalUnrelatedNode);
});
it("reuses an equivalent existing unresolved reasoning unknown instead of creating a duplicate", () => {
const { graph, proposal } = makeComparabilityUpdateFixture();
graph.nodes.push(
makeNode({
id: "n-existing-explanation",
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 result = applyValidatedProposal({
situationGraph: graph,
proposal,
previousQuestion:
"Were these figures measured on the same basis and at the same scale?",
answer:
"Yes. Both figures cover the same accounting period and are taken from the same management accounts.",
});
expect(result.success).toBe(true);
expect(result.emergentReasoningNodeCreated).toBe(false);
expect(result.emergentReasoningNodeId).toBe("n-existing-explanation");
expect(result.newActiveUnknownNodeId).toBe("n-existing-explanation");
expect(result.selectedQuestion?.nodeId).toBe("n-existing-explanation");
expect(
result.updatedSituationGraph.nodes.filter(
(node) => node.label === graph.nodes.at(-1).label,
),
).toHaveLength(1);
});
});
+6
View File
@@ -1046,7 +1046,12 @@ describe("lib/graph/orchestrator startCase", () => {
relationshipStatus: "potentially_related",
relationshipAssessed: true,
resolvedReasoningNodeIds: ["reasoning:comparability"],
emergentReasoningNodeCreated: true,
});
expect(result.diagnostics.emergentReasoningNodeId).toBeTruthy();
expect(result.diagnostics.emergentReasoningNodeReason).toContain(
"backed by the graph",
);
expect(result.diagnostics.reasoningStagesBefore).toEqual([
{
stage: "comparability",
@@ -1074,6 +1079,7 @@ describe("lib/graph/orchestrator startCase", () => {
"The observations concern connected business signals but do not establish a direct contradiction or cause.",
},
]);
expect(result.selectedQuestion?.nodeId).toBe(result.newActiveUnknownNodeId);
expect(result.selectedQuestion?.question).toMatch(
/^What changed during that period that could help explain why /,
);