feat: introduce comparability assessment before contradiction reasoning
This commit is contained in:
@@ -123,6 +123,105 @@ function buildEvidenceFallbackQuestion(meaning) {
|
||||
return `What evidence would confirm or rule out ${stripTrailingPunctuation(meaning)}?`;
|
||||
}
|
||||
|
||||
function collectObservationNodes(graph) {
|
||||
return (graph?.nodes || []).filter(
|
||||
(node) => node.kind === "observation" && node.status === "supported",
|
||||
);
|
||||
}
|
||||
|
||||
function analyseObservationText(text) {
|
||||
const normalised = normaliseText(text);
|
||||
return {
|
||||
text,
|
||||
normalised,
|
||||
isMeasurementLike:
|
||||
/\b(increase|increased|decrease|decreased|fell|rose|doubled|halved|remained|average|score|scores|rate|time|traffic|sales|output|defects|complaints|production|revenue|cash|temperature|quality)\b/.test(
|
||||
normalised,
|
||||
) || /%|percent/.test(String(text || "")),
|
||||
timeframeMentioned:
|
||||
/\b(period|timeframe|quarter|month|week|year|day|annual|daily|weekly|monthly|same period)\b/.test(
|
||||
normalised,
|
||||
),
|
||||
scaleMentioned: /\b(average|rate|score|scores|per|percent|%)\b/.test(
|
||||
normalised,
|
||||
),
|
||||
unitMentioned:
|
||||
/\b(celsius|fahrenheit|minutes|minute|hours|hour|days|day|units|sales|traffic|cash|revenue|complaints|defects)\b/.test(
|
||||
normalised,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export function assessComparability(graph) {
|
||||
const observations = collectObservationNodes(graph);
|
||||
const centralText = normaliseText(graph?.centralStatement || "");
|
||||
const profiles = observations.map((node) =>
|
||||
analyseObservationText(`${node.label} ${node.description}`),
|
||||
);
|
||||
|
||||
if (profiles.length < 2) {
|
||||
return {
|
||||
comparabilityStatus: "confirmed",
|
||||
reason: "Fewer than two supported observations need comparison.",
|
||||
contradictionReasoningAllowed: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
profiles.every((profile) => profile.normalised === profiles[0].normalised)
|
||||
) {
|
||||
return {
|
||||
comparabilityStatus: "confirmed",
|
||||
reason: "The observations restate the same measurement.",
|
||||
contradictionReasoningAllowed: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (profiles.some((profile) => !profile.isMeasurementLike)) {
|
||||
return {
|
||||
comparabilityStatus: "confirmed",
|
||||
reason: "The observations are not competing like-for-like measurements.",
|
||||
contradictionReasoningAllowed: true,
|
||||
};
|
||||
}
|
||||
|
||||
const hasExplicitTimeframe =
|
||||
/\b(period|timeframe|quarter|month|week|year|day|same period)\b/.test(
|
||||
centralText,
|
||||
) || profiles.every((profile) => profile.timeframeMentioned);
|
||||
|
||||
const hasSharedScale = profiles.every((profile) => profile.scaleMentioned);
|
||||
const hasSharedUnits = profiles.every((profile) => profile.unitMentioned);
|
||||
|
||||
if (!hasExplicitTimeframe || !hasSharedScale || !hasSharedUnits) {
|
||||
return {
|
||||
comparabilityStatus: "uncertain",
|
||||
reason:
|
||||
"Comparability between the observations is not yet established across period, scale, or measurement basis.",
|
||||
contradictionReasoningAllowed: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
comparabilityStatus: "uncertain",
|
||||
reason:
|
||||
"The observations appear comparable in form, but the basis for comparing them is still not established.",
|
||||
contradictionReasoningAllowed: false,
|
||||
};
|
||||
}
|
||||
|
||||
function buildComparabilityQuestion(graph, assessment) {
|
||||
const centralText = normaliseText(graph?.centralStatement || "");
|
||||
const mentionsPeriod =
|
||||
/\b(period|timeframe|quarter|month|week|year|day)\b/.test(centralText);
|
||||
|
||||
if (mentionsPeriod) {
|
||||
return "Were these figures measured on the same basis and at the same scale?";
|
||||
}
|
||||
|
||||
return "Were these figures measured over the same period and at the same scale?";
|
||||
}
|
||||
|
||||
function detectContradictionContext(graph) {
|
||||
const central = stripTrailingPunctuation(
|
||||
graph?.centralStatement || "this situation",
|
||||
@@ -146,6 +245,22 @@ function detectContradictionContext(graph) {
|
||||
}
|
||||
|
||||
export function formulateTieResolutionQuestion({ graph }) {
|
||||
const comparability = assessComparability(graph);
|
||||
if (comparability.comparabilityStatus === "uncertain") {
|
||||
return {
|
||||
question: buildComparabilityQuestion(graph, comparability),
|
||||
reason:
|
||||
"Formulated to confirm whether the observations are comparable before exploring competing explanations.",
|
||||
strategy: null,
|
||||
investigationStrategy: null,
|
||||
selectionStatus: "ambiguous",
|
||||
comparabilityStatus: comparability.comparabilityStatus,
|
||||
comparabilityReason: comparability.reason,
|
||||
contradictionReasoningAllowed:
|
||||
comparability.contradictionReasoningAllowed,
|
||||
};
|
||||
}
|
||||
|
||||
const { centralStatement, contradictionLabel } =
|
||||
detectContradictionContext(graph);
|
||||
const focus =
|
||||
@@ -161,6 +276,9 @@ export function formulateTieResolutionQuestion({ graph }) {
|
||||
strategy: null,
|
||||
investigationStrategy: null,
|
||||
selectionStatus: "ambiguous",
|
||||
comparabilityStatus: comparability.comparabilityStatus,
|
||||
comparabilityReason: comparability.reason,
|
||||
contradictionReasoningAllowed: comparability.contradictionReasoningAllowed,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user