feat: introduce comparability assessment before contradiction reasoning
This commit is contained in:
+164
@@ -0,0 +1,164 @@
|
||||
import { makeEdge, makeGraph, makeNode } from "@/lib/graph/schema.js";
|
||||
|
||||
function buildComparabilityFixture({
|
||||
key,
|
||||
scenario,
|
||||
observationLabels,
|
||||
contradictionLabel,
|
||||
expectedComparabilityStatus,
|
||||
expectsComparisonQuestion,
|
||||
}) {
|
||||
const summary = makeNode({
|
||||
id: `${key}-summary`,
|
||||
label: scenario,
|
||||
description: "Summary of the situation from the scenario text",
|
||||
kind: "state",
|
||||
status: "provisional",
|
||||
confidence: "medium",
|
||||
});
|
||||
|
||||
const observations = observationLabels.map((label, index) =>
|
||||
makeNode({
|
||||
id: `${key}-obs-${index + 1}`,
|
||||
label,
|
||||
description: label,
|
||||
kind: "observation",
|
||||
status: "supported",
|
||||
confidence: "high",
|
||||
}),
|
||||
);
|
||||
|
||||
const contradiction = contradictionLabel
|
||||
? [
|
||||
makeNode({
|
||||
id: `${key}-contradiction`,
|
||||
label: contradictionLabel,
|
||||
description: contradictionLabel,
|
||||
kind: "relationship",
|
||||
status: "supported",
|
||||
confidence: "medium",
|
||||
}),
|
||||
]
|
||||
: [];
|
||||
|
||||
const unknowns = [
|
||||
makeNode({
|
||||
id: `${key}-unknown-a`,
|
||||
label: "Possible explanation from one side of the situation.",
|
||||
description: "Possible explanation from one side of the situation.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
}),
|
||||
makeNode({
|
||||
id: `${key}-unknown-b`,
|
||||
label: "Possible explanation from another side of the situation.",
|
||||
description: "Possible explanation from another side of the situation.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
}),
|
||||
];
|
||||
|
||||
const edges = [
|
||||
...observations.map((node) =>
|
||||
makeEdge({
|
||||
id: `${node.id}-supports-summary`,
|
||||
fromNodeId: node.id,
|
||||
toNodeId: summary.id,
|
||||
relationship: "supports",
|
||||
description: `${node.label} supports the summary.`,
|
||||
}),
|
||||
),
|
||||
...unknowns.map((node) =>
|
||||
makeEdge({
|
||||
id: `${node.id}-depends-summary`,
|
||||
fromNodeId: node.id,
|
||||
toNodeId: summary.id,
|
||||
relationship: "depends_on",
|
||||
description: `${node.label} is an unresolved factor for this situation.`,
|
||||
}),
|
||||
),
|
||||
];
|
||||
|
||||
return {
|
||||
key,
|
||||
scenario,
|
||||
expectedComparabilityStatus,
|
||||
expectsComparisonQuestion,
|
||||
graph: makeGraph({
|
||||
centralStatement: scenario,
|
||||
nodes: [summary, ...observations, ...contradiction, ...unknowns],
|
||||
edges,
|
||||
activeUnknownNodeId: null,
|
||||
resolvedNodeIds: [],
|
||||
currentSummary: `Comparability fixture for ${key}`,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export const comparabilityAssessmentFixtures = [
|
||||
buildComparabilityFixture({
|
||||
key: "revenue-cash",
|
||||
scenario:
|
||||
"Revenue increased by 18%, but cash in the bank fell over the same period.",
|
||||
observationLabels: [
|
||||
"Revenue increased by 18%.",
|
||||
"Cash in the bank decreased over the same period.",
|
||||
],
|
||||
contradictionLabel:
|
||||
"Contradiction between revenue improvement and lower cash reserves.",
|
||||
expectedComparabilityStatus: "uncertain",
|
||||
expectsComparisonQuestion: true,
|
||||
}),
|
||||
buildComparabilityFixture({
|
||||
key: "complaints-production",
|
||||
scenario: "Complaints increased. Production increased.",
|
||||
observationLabels: ["Complaints increased.", "Production increased."],
|
||||
contradictionLabel:
|
||||
"Possible contradiction between complaints and production movement.",
|
||||
expectedComparabilityStatus: "uncertain",
|
||||
expectsComparisonQuestion: true,
|
||||
}),
|
||||
buildComparabilityFixture({
|
||||
key: "delivery-cancellations",
|
||||
scenario:
|
||||
"Average delivery time decreased by 25%, but order cancellations increased.",
|
||||
observationLabels: [
|
||||
"Average delivery time decreased by 25%.",
|
||||
"Order cancellations increased.",
|
||||
],
|
||||
contradictionLabel:
|
||||
"Contradiction between faster delivery and more cancellations.",
|
||||
expectedComparabilityStatus: "uncertain",
|
||||
expectsComparisonQuestion: true,
|
||||
}),
|
||||
buildComparabilityFixture({
|
||||
key: "satisfaction-complaints",
|
||||
scenario: "Customer satisfaction increased, but complaints increased.",
|
||||
observationLabels: [
|
||||
"Customer satisfaction increased.",
|
||||
"Complaints increased.",
|
||||
],
|
||||
contradictionLabel:
|
||||
"Contradiction between satisfaction improvement and more complaints.",
|
||||
expectedComparabilityStatus: "uncertain",
|
||||
expectsComparisonQuestion: true,
|
||||
}),
|
||||
buildComparabilityFixture({
|
||||
key: "temperature-ice",
|
||||
scenario: "Temperature increased. Ice melted.",
|
||||
observationLabels: ["Temperature increased.", "Ice melted."],
|
||||
contradictionLabel: null,
|
||||
expectedComparabilityStatus: "confirmed",
|
||||
expectsComparisonQuestion: false,
|
||||
}),
|
||||
buildComparabilityFixture({
|
||||
key: "sales-same",
|
||||
scenario: "Sales doubled. Sales doubled.",
|
||||
observationLabels: ["Sales doubled.", "Sales doubled."],
|
||||
contradictionLabel: null,
|
||||
expectedComparabilityStatus: "confirmed",
|
||||
expectsComparisonQuestion: false,
|
||||
}),
|
||||
];
|
||||
@@ -0,0 +1,85 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
assessComparability,
|
||||
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", () => {
|
||||
const summary = comparabilityAssessmentFixtures.map((fixture) => {
|
||||
const assessment = assessComparability(fixture.graph);
|
||||
const question = formulateTieResolutionQuestion({ graph: fixture.graph });
|
||||
const ambiguity = explainUnknownSelection(fixture.graph, []);
|
||||
|
||||
expect(assessment.comparabilityStatus).toBe(
|
||||
fixture.expectedComparabilityStatus,
|
||||
);
|
||||
expect(question.comparabilityStatus).toBe(
|
||||
fixture.expectedComparabilityStatus,
|
||||
);
|
||||
|
||||
if (fixture.expectsComparisonQuestion) {
|
||||
expect(question.question.toLowerCase()).toContain("same");
|
||||
expect(question.contradictionReasoningAllowed).toBe(false);
|
||||
} else {
|
||||
expect(question.question.toLowerCase()).not.toContain(
|
||||
"same period and at the same scale",
|
||||
);
|
||||
}
|
||||
|
||||
if (fixture.key !== "sales-same") {
|
||||
expect(ambiguity.status).toBe("ambiguous");
|
||||
}
|
||||
|
||||
return {
|
||||
scenario: fixture.scenario,
|
||||
comparabilityStatus: assessment.comparabilityStatus,
|
||||
contradictionReasoningAllowed: assessment.contradictionReasoningAllowed,
|
||||
question: question.question,
|
||||
};
|
||||
});
|
||||
|
||||
expect(summary).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"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.",
|
||||
},
|
||||
{
|
||||
"comparabilityStatus": "uncertain",
|
||||
"contradictionReasoningAllowed": false,
|
||||
"question": "Were these figures measured over the same period and at the same scale?",
|
||||
"scenario": "Complaints increased. Production increased.",
|
||||
},
|
||||
{
|
||||
"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.",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
@@ -253,14 +253,18 @@ describe("lib/graph/orchestrator startCase", () => {
|
||||
id: "q_tie_resolution",
|
||||
selectionStatus: "ambiguous",
|
||||
question:
|
||||
"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?",
|
||||
tiedCandidateIds: expect.arrayContaining([expect.any(String)]),
|
||||
comparabilityStatus: "uncertain",
|
||||
contradictionReasoningAllowed: false,
|
||||
});
|
||||
expect(result.diagnostics.unknownSelectionExplanation).toMatchObject({
|
||||
status: "ambiguous",
|
||||
tieType: "complete_unresolved_tie",
|
||||
selectedNodeId: null,
|
||||
alphabeticalUsedAsReasoning: false,
|
||||
tieResolutionQuestion:
|
||||
"Were these figures measured on the same basis and at the same scale?",
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user