fix: defer relationship classification until comparability is established

This commit is contained in:
2026-08-02 16:48:10 +01:00
parent c97f5f7303
commit 7d408701b5
3 changed files with 103 additions and 8 deletions
+65 -4
View File
@@ -210,6 +210,23 @@ export function assessComparability(graph) {
}; };
} }
function buildReasoningStages(comparability, relationship, deferred = false) {
return [
{
stage: "comparability",
status: comparability.comparabilityStatus,
outcome: comparability.reason,
},
{
stage: "relationship",
status: relationship.relationshipStatus,
outcome: deferred
? "not assessed until comparability is established"
: relationship.reason,
},
];
}
function extractObservationConcepts(profile) { function extractObservationConcepts(profile) {
const concepts = new Set(); const concepts = new Set();
const text = profile.normalised; const text = profile.normalised;
@@ -250,7 +267,7 @@ function extractObservationDirection(profile) {
return "unknown"; return "unknown";
} }
export function classifyObservationRelationship(graph) { function classifyObservationRelationshipWhenComparable(graph) {
const observations = collectObservationNodes(graph); const observations = collectObservationNodes(graph);
const profiles = observations.map((node) => const profiles = observations.map((node) =>
analyseObservationText(`${node.label} ${node.description}`), analyseObservationText(`${node.label} ${node.description}`),
@@ -343,6 +360,42 @@ export function classifyObservationRelationship(graph) {
}; };
} }
export function classifyObservationRelationship(graph) {
const comparability = assessComparability(graph);
if (comparability.comparabilityStatus !== "confirmed") {
const deferredRelationship = {
relationshipStatus: "insufficient_information",
reason:
"Relationship classification is deferred until comparability is established.",
contradictionReasoningAllowed: false,
questionRequired: comparability.comparabilityStatus === "uncertain",
questionSuppressedReason:
comparability.comparabilityStatus === "incompatible"
? "Relationship classification was not attempted because the observations are not yet comparable."
: undefined,
relationshipAssessed: false,
};
return {
...deferredRelationship,
reasoningStages: buildReasoningStages(
comparability,
deferredRelationship,
true,
),
};
}
const classified = classifyObservationRelationshipWhenComparable(graph);
return {
...classified,
relationshipAssessed: true,
reasoningStages: buildReasoningStages(comparability, classified, false),
};
}
function buildComparabilityQuestion(graph, assessment) { function buildComparabilityQuestion(graph, assessment) {
const centralText = normaliseText(graph?.centralStatement || ""); const centralText = normaliseText(graph?.centralStatement || "");
const mentionsPeriod = const mentionsPeriod =
@@ -380,6 +433,7 @@ function detectContradictionContext(graph) {
export function formulateTieResolutionQuestion({ graph }) { export function formulateTieResolutionQuestion({ graph }) {
const comparability = assessComparability(graph); const comparability = assessComparability(graph);
if (comparability.comparabilityStatus === "uncertain") { if (comparability.comparabilityStatus === "uncertain") {
const deferredRelationship = classifyObservationRelationship(graph);
return { return {
question: buildComparabilityQuestion(graph, comparability), question: buildComparabilityQuestion(graph, comparability),
reason: reason:
@@ -391,10 +445,11 @@ export function formulateTieResolutionQuestion({ graph }) {
comparabilityReason: comparability.reason, comparabilityReason: comparability.reason,
contradictionReasoningAllowed: contradictionReasoningAllowed:
comparability.contradictionReasoningAllowed, comparability.contradictionReasoningAllowed,
relationshipStatus: "insufficient_information", relationshipStatus: deferredRelationship.relationshipStatus,
relationshipReason: relationshipReason: deferredRelationship.reason,
"Relationship classification is deferred until comparability is established.", relationshipAssessed: deferredRelationship.relationshipAssessed,
questionRequired: true, questionRequired: true,
reasoningStages: deferredRelationship.reasoningStages,
}; };
} }
@@ -410,9 +465,11 @@ export function formulateTieResolutionQuestion({ graph }) {
comparabilityReason: comparability.reason, comparabilityReason: comparability.reason,
relationshipStatus: relationship.relationshipStatus, relationshipStatus: relationship.relationshipStatus,
relationshipReason: relationship.reason, relationshipReason: relationship.reason,
relationshipAssessed: relationship.relationshipAssessed,
contradictionReasoningAllowed: relationship.contradictionReasoningAllowed, contradictionReasoningAllowed: relationship.contradictionReasoningAllowed,
questionRequired: relationship.questionRequired, questionRequired: relationship.questionRequired,
questionSuppressedReason: relationship.questionSuppressedReason, questionSuppressedReason: relationship.questionSuppressedReason,
reasoningStages: relationship.reasoningStages,
}; };
} }
@@ -429,8 +486,10 @@ export function formulateTieResolutionQuestion({ graph }) {
comparabilityReason: comparability.reason, comparabilityReason: comparability.reason,
relationshipStatus: relationship.relationshipStatus, relationshipStatus: relationship.relationshipStatus,
relationshipReason: relationship.reason, relationshipReason: relationship.reason,
relationshipAssessed: relationship.relationshipAssessed,
contradictionReasoningAllowed: relationship.contradictionReasoningAllowed, contradictionReasoningAllowed: relationship.contradictionReasoningAllowed,
questionRequired: relationship.questionRequired, questionRequired: relationship.questionRequired,
reasoningStages: relationship.reasoningStages,
}; };
} }
@@ -453,8 +512,10 @@ export function formulateTieResolutionQuestion({ graph }) {
comparabilityReason: comparability.reason, comparabilityReason: comparability.reason,
relationshipStatus: relationship.relationshipStatus, relationshipStatus: relationship.relationshipStatus,
relationshipReason: relationship.reason, relationshipReason: relationship.reason,
relationshipAssessed: relationship.relationshipAssessed,
contradictionReasoningAllowed: relationship.contradictionReasoningAllowed, contradictionReasoningAllowed: relationship.contradictionReasoningAllowed,
questionRequired: relationship.questionRequired, questionRequired: relationship.questionRequired,
reasoningStages: relationship.reasoningStages,
}; };
} }
+36 -4
View File
@@ -39,6 +39,7 @@ describe("comparability assessment", () => {
scenario: fixture.scenario, scenario: fixture.scenario,
comparabilityStatus: assessment.comparabilityStatus, comparabilityStatus: assessment.comparabilityStatus,
relationshipStatus: relationship.relationshipStatus, relationshipStatus: relationship.relationshipStatus,
relationshipAssessed: relationship.relationshipAssessed,
contradictionReasoningAllowed: question.contradictionReasoningAllowed, contradictionReasoningAllowed: question.contradictionReasoningAllowed,
question: question.question, question: question.question,
}; };
@@ -49,7 +50,8 @@ describe("comparability assessment", () => {
scenario: scenario:
"Revenue increased by 18%, but cash in the bank fell over the same period.", "Revenue increased by 18%, but cash in the bank fell over the same period.",
comparabilityStatus: "uncertain", comparabilityStatus: "uncertain",
relationshipStatus: "compatible", relationshipStatus: "insufficient_information",
relationshipAssessed: false,
contradictionReasoningAllowed: false, contradictionReasoningAllowed: false,
question: question:
"Were these figures measured on the same basis and at the same scale?", "Were these figures measured on the same basis and at the same scale?",
@@ -57,7 +59,8 @@ describe("comparability assessment", () => {
{ {
scenario: "Complaints increased. Production increased.", scenario: "Complaints increased. Production increased.",
comparabilityStatus: "uncertain", comparabilityStatus: "uncertain",
relationshipStatus: "compatible", relationshipStatus: "insufficient_information",
relationshipAssessed: false,
contradictionReasoningAllowed: false, contradictionReasoningAllowed: false,
question: question:
"Were these figures measured over the same period and at the same scale?", "Were these figures measured over the same period and at the same scale?",
@@ -66,7 +69,8 @@ describe("comparability assessment", () => {
scenario: scenario:
"Average delivery time decreased by 25%, but order cancellations increased.", "Average delivery time decreased by 25%, but order cancellations increased.",
comparabilityStatus: "uncertain", comparabilityStatus: "uncertain",
relationshipStatus: "compatible", relationshipStatus: "insufficient_information",
relationshipAssessed: false,
contradictionReasoningAllowed: false, contradictionReasoningAllowed: false,
question: question:
"Were these figures measured over the same period and at the same scale?", "Were these figures measured over the same period and at the same scale?",
@@ -74,7 +78,8 @@ describe("comparability assessment", () => {
{ {
scenario: "Customer satisfaction increased, but complaints increased.", scenario: "Customer satisfaction increased, but complaints increased.",
comparabilityStatus: "uncertain", comparabilityStatus: "uncertain",
relationshipStatus: "compatible", relationshipStatus: "insufficient_information",
relationshipAssessed: false,
contradictionReasoningAllowed: false, contradictionReasoningAllowed: false,
question: question:
"Were these figures measured over the same period and at the same scale?", "Were these figures measured over the same period and at the same scale?",
@@ -83,6 +88,7 @@ describe("comparability assessment", () => {
scenario: "Temperature increased. Ice melted.", scenario: "Temperature increased. Ice melted.",
comparabilityStatus: "confirmed", comparabilityStatus: "confirmed",
relationshipStatus: "compatible", relationshipStatus: "compatible",
relationshipAssessed: true,
contradictionReasoningAllowed: false, contradictionReasoningAllowed: false,
question: null, question: null,
}, },
@@ -90,12 +96,38 @@ describe("comparability assessment", () => {
scenario: "Sales doubled. Sales doubled.", scenario: "Sales doubled. Sales doubled.",
comparabilityStatus: "confirmed", comparabilityStatus: "confirmed",
relationshipStatus: "duplicate", relationshipStatus: "duplicate",
relationshipAssessed: true,
contradictionReasoningAllowed: false, contradictionReasoningAllowed: false,
question: null, question: null,
}, },
]); ]);
}); });
it("defers relationship classification while comparability is uncertain", () => {
const fixture = comparabilityAssessmentFixtures[0];
const relationship = classifyObservationRelationship(fixture.graph);
expect(relationship).toMatchObject({
relationshipStatus: "insufficient_information",
relationshipAssessed: false,
contradictionReasoningAllowed: false,
questionRequired: true,
});
expect(relationship.reasoningStages).toEqual([
{
stage: "comparability",
status: "uncertain",
outcome:
"Comparability between the observations is not yet established across period, scale, or measurement basis.",
},
{
stage: "relationship",
status: "insufficient_information",
outcome: "not assessed until comparability is established",
},
]);
});
it("allows contradiction reasoning only for genuine contradictions", () => { it("allows contradiction reasoning only for genuine contradictions", () => {
const serviceGraph = { const serviceGraph = {
centralStatement: centralStatement:
+2
View File
@@ -256,6 +256,8 @@ describe("lib/graph/orchestrator startCase", () => {
"Were these figures measured on the same basis and at the same scale?", "Were these figures measured on the same basis and at the same scale?",
tiedCandidateIds: expect.arrayContaining([expect.any(String)]), tiedCandidateIds: expect.arrayContaining([expect.any(String)]),
comparabilityStatus: "uncertain", comparabilityStatus: "uncertain",
relationshipStatus: "insufficient_information",
relationshipAssessed: false,
contradictionReasoningAllowed: false, contradictionReasoningAllowed: false,
}); });
expect(result.diagnostics.unknownSelectionExplanation).toMatchObject({ expect(result.diagnostics.unknownSelectionExplanation).toMatchObject({