Implemented Investigation Strategy
This commit is contained in:
@@ -139,7 +139,41 @@ function toGerundPhrase(phrase) {
|
||||
return [gerund, ...rest].join(" ");
|
||||
}
|
||||
|
||||
function detectStrategy({ node, graph, relatedNodes, combinedText, meaning }) {
|
||||
function buildInvestigationStrategy({
|
||||
key,
|
||||
reason,
|
||||
node,
|
||||
graph,
|
||||
relatedNodes,
|
||||
meaning,
|
||||
actionPhrase,
|
||||
}) {
|
||||
return {
|
||||
key,
|
||||
reason,
|
||||
nodeId: node?.id ?? null,
|
||||
nodeLabel: node?.label ?? null,
|
||||
meaning,
|
||||
actionPhrase,
|
||||
relatedNodeIds: relatedNodes.map((relatedNode) => relatedNode.id),
|
||||
centralStatement: graph?.centralStatement ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
export function selectInvestigationStrategy({ node, graph, context = {} }) {
|
||||
const relatedNodes = collectRelatedNodes(node, graph);
|
||||
const meaning = extractMeaning(node);
|
||||
const combinedText = [
|
||||
node?.label,
|
||||
node?.description,
|
||||
...relatedNodes.map((relatedNode) => relatedNode.label),
|
||||
...relatedNodes.map((relatedNode) => relatedNode.description),
|
||||
graph?.centralStatement,
|
||||
...(context.resolvedValues || []),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
const text = normaliseText(combinedText);
|
||||
const nodeText = normaliseText(
|
||||
`${node?.label || ""} ${node?.description || ""}`,
|
||||
@@ -172,21 +206,22 @@ function detectStrategy({ node, graph, relatedNodes, combinedText, meaning }) {
|
||||
nodeText,
|
||||
);
|
||||
|
||||
if (/\b(customer|user|buyer|stakeholder|recipient|audience)\b/.test(text)) {
|
||||
return { strategy: "actor/customer", meaning, actionPhrase };
|
||||
}
|
||||
|
||||
const hasBaselineLanguage =
|
||||
/\b(before|previous|baseline|prior|comparable state)\b/.test(text);
|
||||
const hasPrimaryBaselineLanguage =
|
||||
/\b(before|previous|baseline|prior|comparable state)\b/.test(nodeText);
|
||||
|
||||
if (hasBaselineLanguage && hasPrimaryBaselineLanguage) {
|
||||
return { strategy: "baseline", meaning, actionPhrase };
|
||||
}
|
||||
|
||||
if (/\b(when|timing|timeline|duration|sequence|milestone)\b/.test(text)) {
|
||||
return { strategy: "transition/timing", meaning, actionPhrase };
|
||||
return buildInvestigationStrategy({
|
||||
key: "baseline_reconstruction",
|
||||
reason:
|
||||
"Selected because the unknown explicitly references a missing previous or baseline state.",
|
||||
node,
|
||||
graph,
|
||||
relatedNodes,
|
||||
meaning,
|
||||
actionPhrase,
|
||||
});
|
||||
}
|
||||
|
||||
const hasDefinitionLanguage =
|
||||
@@ -206,84 +241,116 @@ function detectStrategy({ node, graph, relatedNodes, combinedText, meaning }) {
|
||||
/\b(metric|measure|measurable|roi|revenue projection|benchmark)\b/.test(
|
||||
text,
|
||||
);
|
||||
const hasEvidenceLanguage =
|
||||
/\b(evidence|proof|validate|validation|signal|demand)\b/.test(text) ||
|
||||
node?.kind === "reported_claim" ||
|
||||
node?.kind === "conclusion" ||
|
||||
/\b(claim|assertion|true|false)\b/.test(text);
|
||||
const hasContradictionLanguage =
|
||||
/\b(contradiction|contradict|conflict|inconsistent|inconsistency|disagree|mismatch)\b/.test(
|
||||
`${text} ${relatedText}`,
|
||||
) ||
|
||||
relatedNodes.some(
|
||||
(relatedNode) =>
|
||||
relatedNode.status === "contradicted" ||
|
||||
relatedNode.kind === "conclusion",
|
||||
);
|
||||
|
||||
if (hasDecisionValueLanguage && hasMeasurementLanguage) {
|
||||
return { strategy: "measurement", meaning, actionPhrase };
|
||||
}
|
||||
|
||||
if (hasPrimaryDefinitionLanguage) {
|
||||
return { strategy: "definition", meaning, actionPhrase };
|
||||
if (hasPrimaryDefinitionLanguage || hasDefinitionLanguage) {
|
||||
return buildInvestigationStrategy({
|
||||
key: "definition",
|
||||
reason:
|
||||
"Selected because the unknown is primarily about clarifying what a term means in this case.",
|
||||
node,
|
||||
graph,
|
||||
relatedNodes,
|
||||
meaning,
|
||||
actionPhrase,
|
||||
});
|
||||
}
|
||||
|
||||
if (hasDecisionValueLanguage || hasCriteriaLanguage) {
|
||||
return { strategy: "decision criterion", meaning, actionPhrase };
|
||||
return buildInvestigationStrategy({
|
||||
key: "decision_threshold",
|
||||
reason:
|
||||
"Selected because the unknown determines the threshold for making or justifying a decision.",
|
||||
node,
|
||||
graph,
|
||||
relatedNodes,
|
||||
meaning,
|
||||
actionPhrase,
|
||||
});
|
||||
}
|
||||
|
||||
if (hasConstraintLanguage && hasPrimaryConstraintLanguage) {
|
||||
return { strategy: "constraint", meaning, actionPhrase };
|
||||
if (hasPrimaryBaselineLanguage || hasBaselineLanguage) {
|
||||
return buildInvestigationStrategy({
|
||||
key: "baseline_reconstruction",
|
||||
reason:
|
||||
"Selected because reconstructing the prior state is the most direct way to resolve the unknown.",
|
||||
node,
|
||||
graph,
|
||||
relatedNodes,
|
||||
meaning,
|
||||
actionPhrase,
|
||||
});
|
||||
}
|
||||
|
||||
if (hasDefinitionLanguage) {
|
||||
return { strategy: "definition", meaning, actionPhrase };
|
||||
if (hasContradictionLanguage) {
|
||||
return buildInvestigationStrategy({
|
||||
key: "contradiction_resolution",
|
||||
reason:
|
||||
"Selected because the graph context indicates conflicting claims or inconsistent states that must be reconciled.",
|
||||
node,
|
||||
graph,
|
||||
relatedNodes,
|
||||
meaning,
|
||||
actionPhrase,
|
||||
});
|
||||
}
|
||||
|
||||
if (hasBaselineLanguage) {
|
||||
return { strategy: "baseline", meaning, actionPhrase };
|
||||
if (hasEvidenceLanguage || hasMeasurementLanguage || hasConstraintLanguage) {
|
||||
return buildInvestigationStrategy({
|
||||
key: "evidence_gathering",
|
||||
reason:
|
||||
hasConstraintLanguage && hasPrimaryConstraintLanguage
|
||||
? "Selected because evidence about the practical limiting factor is needed before the unknown can be resolved."
|
||||
: "Selected because resolving the unknown requires evidence, signals, or measurable confirmation.",
|
||||
node,
|
||||
graph,
|
||||
relatedNodes,
|
||||
meaning,
|
||||
actionPhrase,
|
||||
});
|
||||
}
|
||||
|
||||
if (hasConstraintLanguage) {
|
||||
return { strategy: "constraint", meaning, actionPhrase };
|
||||
}
|
||||
|
||||
if (/\b(evidence|proof|validate|validation|signal|demand)\b/.test(text)) {
|
||||
return { strategy: "evidence", meaning, actionPhrase };
|
||||
}
|
||||
|
||||
if (hasMeasurementLanguage) {
|
||||
return { strategy: "measurement", meaning, actionPhrase };
|
||||
}
|
||||
|
||||
if (
|
||||
/\b(objective|goal|outcome|problem|job to be done|benefit)\b/.test(text)
|
||||
) {
|
||||
return { strategy: "objective", meaning, actionPhrase };
|
||||
}
|
||||
|
||||
if (
|
||||
node?.kind === "reported_claim" ||
|
||||
node?.kind === "conclusion" ||
|
||||
/\b(claim|assertion|true|false)\b/.test(text)
|
||||
) {
|
||||
return { strategy: "evidence", meaning, actionPhrase };
|
||||
}
|
||||
|
||||
return { strategy: "generic clarification", meaning, actionPhrase };
|
||||
return buildInvestigationStrategy({
|
||||
key: "definition",
|
||||
reason:
|
||||
"Selected as the deterministic fallback because clarifying the exact meaning of the unknown is the narrowest first step.",
|
||||
node,
|
||||
graph,
|
||||
relatedNodes,
|
||||
meaning,
|
||||
actionPhrase,
|
||||
});
|
||||
}
|
||||
|
||||
function buildQuestion({ strategy, meaning, actionPhrase }) {
|
||||
switch (strategy) {
|
||||
case "decision criterion":
|
||||
return actionPhrase
|
||||
? `What outcome would demonstrate enough value to justify ${toGerundPhrase(actionPhrase)}?`
|
||||
function buildQuestionFromStrategy(strategy) {
|
||||
switch (strategy.key) {
|
||||
case "decision_threshold":
|
||||
return strategy.actionPhrase
|
||||
? `What outcome would demonstrate enough value to justify ${toGerundPhrase(strategy.actionPhrase)}?`
|
||||
: "What outcome would be sufficient to justify this decision?";
|
||||
case "definition":
|
||||
return `What does ${meaning} mean in this situation?`;
|
||||
case "evidence":
|
||||
return `What evidence would show whether ${meaning} is true?`;
|
||||
case "baseline":
|
||||
return `What was the comparable state before ${meaning}?`;
|
||||
case "actor/customer":
|
||||
return "Who experiences the problem or receives the value in this situation?";
|
||||
case "objective":
|
||||
return "What outcome is this decision or effort meant to achieve?";
|
||||
case "constraint":
|
||||
return "What constraint most limits the available options in this situation?";
|
||||
case "measurement":
|
||||
return `What measure would determine whether ${meaning} is sufficient?`;
|
||||
case "transition/timing":
|
||||
return `When does ${meaning} become relevant in the decision or change?`;
|
||||
return `What does ${strategy.meaning} mean in this situation?`;
|
||||
case "evidence_gathering":
|
||||
return `What evidence would show whether ${strategy.meaning} is true?`;
|
||||
case "baseline_reconstruction":
|
||||
return `What was the comparable state before ${strategy.meaning}?`;
|
||||
case "contradiction_resolution":
|
||||
return `What fact would resolve the contradiction about ${strategy.meaning}?`;
|
||||
default:
|
||||
return `What specific fact would resolve whether ${meaning} is true?`;
|
||||
return `What specific fact would resolve whether ${strategy.meaning} is true?`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,36 +399,22 @@ function validateFormulatedQuestion(question, meaning) {
|
||||
}
|
||||
|
||||
export function formulateQuestion({ node, graph, context = {} }) {
|
||||
const relatedNodes = collectRelatedNodes(node, graph);
|
||||
const meaning = extractMeaning(node);
|
||||
const combinedText = [
|
||||
node?.label,
|
||||
node?.description,
|
||||
...relatedNodes.map((relatedNode) => relatedNode.label),
|
||||
...relatedNodes.map((relatedNode) => relatedNode.description),
|
||||
graph?.centralStatement,
|
||||
...(context.resolvedValues || []),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
const detected = detectStrategy({
|
||||
const investigationStrategy = selectInvestigationStrategy({
|
||||
node,
|
||||
graph,
|
||||
relatedNodes,
|
||||
combinedText,
|
||||
meaning,
|
||||
context,
|
||||
});
|
||||
|
||||
let question = buildQuestion(detected);
|
||||
let question = buildQuestionFromStrategy(investigationStrategy);
|
||||
|
||||
if (!validateFormulatedQuestion(question, meaning)) {
|
||||
question = `What evidence would resolve whether ${meaning} is true?`;
|
||||
if (!validateFormulatedQuestion(question, investigationStrategy.meaning)) {
|
||||
question = `What evidence would resolve whether ${investigationStrategy.meaning} is true?`;
|
||||
}
|
||||
|
||||
return {
|
||||
question,
|
||||
reason: `Formulated from graph context using the ${detected.strategy} strategy.`,
|
||||
strategy: detected.strategy,
|
||||
reason: `Formulated from graph context using the ${investigationStrategy.key} investigation strategy.`,
|
||||
strategy: investigationStrategy.key,
|
||||
investigationStrategy,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user