feat: advance reasoning after comparability is resolved

This commit is contained in:
2026-08-02 17:06:34 +01:00
parent 7d408701b5
commit 25a989450c
9 changed files with 649 additions and 5 deletions
+69 -2
View File
@@ -152,7 +152,28 @@ function analyseObservationText(text) {
};
}
export const COMPARABILITY_REASONING_NODE_ID = "reasoning:comparability";
function readStoredComparabilityState(graph) {
const reasoningState = graph?.reasoningState;
if (!reasoningState?.comparabilityStatus) return null;
return {
comparabilityStatus: reasoningState.comparabilityStatus,
reason:
reasoningState.comparabilityReason ||
"Comparability state was carried forward from earlier reasoning.",
contradictionReasoningAllowed:
reasoningState.comparabilityStatus === "confirmed",
};
}
export function assessComparability(graph) {
const storedState = readStoredComparabilityState(graph);
if (storedState) {
return storedState;
}
const observations = collectObservationNodes(graph);
const centralText = normaliseText(graph?.centralStatement || "");
const profiles = observations.map((node) =>
@@ -308,6 +329,9 @@ function classifyObservationRelationshipWhenComparable(graph) {
const directions = profiles.map((profile) =>
extractObservationDirection(profile),
);
const conceptUnion = new Set(conceptSets.flat());
const hasRevenueCashPair =
conceptUnion.has("revenue") && conceptUnion.has("cash");
if (
sharedConcepts.size > 0 &&
@@ -336,6 +360,19 @@ function classifyObservationRelationshipWhenComparable(graph) {
};
}
if (
hasRevenueCashPair &&
directions.every((direction) => direction !== "unknown")
) {
return {
relationshipStatus: "potentially_related",
reason:
"The observations concern connected business signals but do not establish a direct contradiction or cause.",
contradictionReasoningAllowed: false,
questionRequired: true,
};
}
if (
sharedConcepts.size === 0 &&
directions.every((direction) => direction !== "unknown")
@@ -396,6 +433,30 @@ export function classifyObservationRelationship(graph) {
};
}
export function buildReasoningState(graph, overrides = {}) {
const relationship = classifyObservationRelationship({
...graph,
reasoningState: {
...(graph?.reasoningState || {}),
...(overrides || {}),
},
});
return {
comparabilityStatus: relationship.reasoningStages[0]?.status ?? null,
comparabilityReason: relationship.reasoningStages[0]?.outcome ?? null,
comparabilityEvidence:
overrides.comparabilityEvidence ??
graph?.reasoningState?.comparabilityEvidence ??
[],
relationshipStatus: relationship.relationshipStatus,
relationshipReason: relationship.reason,
relationshipAssessed: relationship.relationshipAssessed,
contradictionReasoningAllowed: relationship.contradictionReasoningAllowed,
reasoningStages: relationship.reasoningStages,
};
}
function buildComparabilityQuestion(graph, assessment) {
const centralText = normaliseText(graph?.centralStatement || "");
const mentionsPeriod =
@@ -430,6 +491,13 @@ function detectContradictionContext(graph) {
};
}
function buildBroadInvestigationQuestion(graph) {
const central = sanitizeQuestionText(
stripTrailingPunctuation(graph?.centralStatement || "these observations"),
);
return `What changed during that period that could help explain why ${central}?`;
}
export function formulateTieResolutionQuestion({ graph }) {
const comparability = assessComparability(graph);
if (comparability.comparabilityStatus === "uncertain") {
@@ -475,8 +543,7 @@ export function formulateTieResolutionQuestion({ graph }) {
if (relationship.relationshipStatus === "potentially_related") {
return {
question:
"What connection, if any, should we check between these observations?",
question: buildBroadInvestigationQuestion(graph),
reason:
"Formulated as a neutral relationship question because the observations may be related without being contradictory.",
strategy: null,