feat: classify observation relationships after comparability

This commit is contained in:
2026-08-02 16:40:24 +01:00
parent 0c7558d31f
commit c97f5f7303
5 changed files with 316 additions and 50 deletions
+5 -6
View File
@@ -65,7 +65,6 @@ describe("ambiguity generalisation", () => {
expect(explanation.alphabeticalUsedAsReasoning).toBe(false);
expect(neutralExplanation.status).toBe("ambiguous");
expect(isSingleQuestion(tieQuestion.question)).toBe(true);
expect(tieQuestion.question.toLowerCase()).not.toContain(" and ");
expect(tieQuestion.question.toLowerCase()).not.toContain(" or ");
return {
@@ -86,7 +85,7 @@ describe("ambiguity generalisation", () => {
"candidateCount": 2,
"explanationFavoured": false,
"investigationStrategy": null,
"question": "What changed during the period that could explain why Revenue increased by 18%, but cash in the bank fell over the same period?",
"question": "Were these figures measured on the same basis and at the same scale?",
"scenario": "Revenue increased by 18%, but cash in the bank fell over the same period.",
"tieReason": "No justified distinction between leading unknowns.",
},
@@ -95,7 +94,7 @@ describe("ambiguity generalisation", () => {
"candidateCount": 2,
"explanationFavoured": false,
"investigationStrategy": null,
"question": "What changed during the period that could explain why Customer satisfaction scores increased, but complaints also increased?",
"question": "Were these figures measured over the same period and at the same scale?",
"scenario": "Customer satisfaction scores increased, but complaints also increased.",
"tieReason": "No justified distinction between leading unknowns.",
},
@@ -104,7 +103,7 @@ describe("ambiguity generalisation", () => {
"candidateCount": 2,
"explanationFavoured": false,
"investigationStrategy": null,
"question": "What changed during the period that could explain why Average delivery time decreased by 25%, but order cancellations increased?",
"question": "Were these figures measured over the same period and at the same scale?",
"scenario": "Average delivery time decreased by 25%, but order cancellations increased.",
"tieReason": "No justified distinction between leading unknowns.",
},
@@ -113,7 +112,7 @@ describe("ambiguity generalisation", () => {
"candidateCount": 2,
"explanationFavoured": false,
"investigationStrategy": null,
"question": "What changed during the period that could explain why Website traffic doubled, but sales remained unchanged?",
"question": "Were these figures measured over the same period and at the same scale?",
"scenario": "Website traffic doubled, but sales remained unchanged.",
"tieReason": "No justified distinction between leading unknowns.",
},
@@ -122,7 +121,7 @@ describe("ambiguity generalisation", () => {
"candidateCount": 2,
"explanationFavoured": false,
"investigationStrategy": null,
"question": "What changed during the period that could explain why Production output increased by 30%, but quality defects also increased?",
"question": "Were these figures measured over the same period and at the same scale?",
"scenario": "Production output increased by 30%, but quality defects also increased.",
"tieReason": "No justified distinction between leading unknowns.",
},
+102 -39
View File
@@ -1,15 +1,17 @@
import { describe, expect, it } from "vitest";
import {
assessComparability,
classifyObservationRelationship,
formulateTieResolutionQuestion,
} from "@/lib/graph/question-formulator.js";
import { explainUnknownSelection } from "@/lib/graph/utils.js";
import { comparabilityAssessmentFixtures } from "@/tests/fixtures/comparability-assessment.js";
describe("comparability assessment", () => {
it("generates comparison questions only when comparability is uncertain", () => {
it("generates comparison or relationship questions only when warranted", () => {
const summary = comparabilityAssessmentFixtures.map((fixture) => {
const assessment = assessComparability(fixture.graph);
const relationship = classifyObservationRelationship(fixture.graph);
const question = formulateTieResolutionQuestion({ graph: fixture.graph });
const ambiguity = explainUnknownSelection(fixture.graph, []);
@@ -24,7 +26,7 @@ describe("comparability assessment", () => {
expect(question.question.toLowerCase()).toContain("same");
expect(question.contradictionReasoningAllowed).toBe(false);
} else {
expect(question.question.toLowerCase()).not.toContain(
expect(question.question?.toLowerCase() || "").not.toContain(
"same period and at the same scale",
);
}
@@ -36,50 +38,111 @@ describe("comparability assessment", () => {
return {
scenario: fixture.scenario,
comparabilityStatus: assessment.comparabilityStatus,
contradictionReasoningAllowed: assessment.contradictionReasoningAllowed,
relationshipStatus: relationship.relationshipStatus,
contradictionReasoningAllowed: question.contradictionReasoningAllowed,
question: question.question,
};
});
expect(summary).toMatchInlineSnapshot(`
[
expect(summary).toEqual([
{
scenario:
"Revenue increased by 18%, but cash in the bank fell over the same period.",
comparabilityStatus: "uncertain",
relationshipStatus: "compatible",
contradictionReasoningAllowed: false,
question:
"Were these figures measured on the same basis and at the same scale?",
},
{
scenario: "Complaints increased. Production increased.",
comparabilityStatus: "uncertain",
relationshipStatus: "compatible",
contradictionReasoningAllowed: false,
question:
"Were these figures measured over the same period and at the same scale?",
},
{
scenario:
"Average delivery time decreased by 25%, but order cancellations increased.",
comparabilityStatus: "uncertain",
relationshipStatus: "compatible",
contradictionReasoningAllowed: false,
question:
"Were these figures measured over the same period and at the same scale?",
},
{
scenario: "Customer satisfaction increased, but complaints increased.",
comparabilityStatus: "uncertain",
relationshipStatus: "compatible",
contradictionReasoningAllowed: false,
question:
"Were these figures measured over the same period and at the same scale?",
},
{
scenario: "Temperature increased. Ice melted.",
comparabilityStatus: "confirmed",
relationshipStatus: "compatible",
contradictionReasoningAllowed: false,
question: null,
},
{
scenario: "Sales doubled. Sales doubled.",
comparabilityStatus: "confirmed",
relationshipStatus: "duplicate",
contradictionReasoningAllowed: false,
question: null,
},
]);
});
it("allows contradiction reasoning only for genuine contradictions", () => {
const serviceGraph = {
centralStatement:
"The service was reported as available throughout the hour and unavailable throughout the same hour.",
nodes: [
{
"comparabilityStatus": "uncertain",
"contradictionReasoningAllowed": false,
"question": "Were these figures measured on the same basis and at the same scale?",
"scenario": "Revenue increased by 18%, but cash in the bank fell over the same period.",
id: "service-available",
label: "The service was available throughout the hour.",
description: "The service was available throughout the hour.",
kind: "observation",
status: "supported",
confidence: "high",
value: null,
unit: null,
evidenceIds: [],
dependsOn: [],
affects: [],
parentId: null,
childIds: [],
},
{
"comparabilityStatus": "uncertain",
"contradictionReasoningAllowed": false,
"question": "Were these figures measured over the same period and at the same scale?",
"scenario": "Complaints increased. Production increased.",
id: "service-unavailable",
label: "The service was unavailable throughout the same hour.",
description: "The service was unavailable throughout the same hour.",
kind: "observation",
status: "supported",
confidence: "high",
value: null,
unit: null,
evidenceIds: [],
dependsOn: [],
affects: [],
parentId: null,
childIds: [],
},
{
"comparabilityStatus": "uncertain",
"contradictionReasoningAllowed": false,
"question": "Were these figures measured over the same period and at the same scale?",
"scenario": "Average delivery time decreased by 25%, but order cancellations increased.",
},
{
"comparabilityStatus": "uncertain",
"contradictionReasoningAllowed": false,
"question": "Were these figures measured over the same period and at the same scale?",
"scenario": "Customer satisfaction increased, but complaints increased.",
},
{
"comparabilityStatus": "confirmed",
"contradictionReasoningAllowed": true,
"question": "What changed during the period that could explain why Temperature increased. Ice melted?",
"scenario": "Temperature increased. Ice melted.",
},
{
"comparabilityStatus": "confirmed",
"contradictionReasoningAllowed": false,
"question": "What changed during the period that could explain why Sales doubled. Sales doubled?",
"scenario": "Sales doubled. Sales doubled.",
},
]
`);
],
edges: [],
activeUnknownNodeId: null,
resolvedNodeIds: [],
currentSummary: "Service contradiction fixture",
};
const relationship = classifyObservationRelationship(serviceGraph);
expect(relationship).toMatchObject({
relationshipStatus: "contradictory",
contradictionReasoningAllowed: true,
questionRequired: true,
});
});
});
+19 -2
View File
@@ -323,17 +323,34 @@ describe("formulateQuestion", () => {
status: "supported",
confidence: "medium",
});
const revenueObservation = makeNode({
id: "n-revenue-observation",
label: "Revenue increased by 18%.",
description: "Revenue increased by 18%.",
kind: "observation",
status: "supported",
confidence: "high",
});
const cashObservation = 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",
});
const graph = makeGraphFor(unknown, {
centralStatement:
"Revenue increased by 18%, but cash in the bank fell over the same period.",
nodes: [contradiction],
nodes: [contradiction, revenueObservation, cashObservation],
});
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?",
"Were these figures measured on the same basis and at the same scale?",
);
expect(result.comparabilityStatus).toBe("uncertain");
expect(result.question.toLowerCase()).not.toMatch(
/accounts receivable|capex|debt repayments|working capital/,
);