fix: reselect after reasoning pattern filtering

This commit is contained in:
2026-08-03 12:39:01 +01:00
parent c27320984c
commit 34c25fcb43
4 changed files with 317 additions and 46 deletions
+170 -42
View File
@@ -2038,6 +2038,137 @@ function selectDecompositionChildCandidate(
};
}
function buildSelectedQuestionResult({
updatedSituationGraph,
deterministicSelection,
}) {
const selectedNode =
deterministicSelection?.status === "selected"
? findNodeById(updatedSituationGraph, deterministicSelection.nodeId)
: null;
const formulatedQuestion = selectedNode
? formulateQuestion({
node: selectedNode,
graph: updatedSituationGraph,
context: { selectionState: deterministicSelection },
})
: null;
const selectedQuestion =
deterministicSelection?.status === "ambiguous"
? {
id: "q_tie_resolution",
...formulateTieResolutionQuestion({ graph: updatedSituationGraph }),
nodeId: null,
tiedCandidateIds: deterministicSelection.tiedCandidateIds,
}
: deterministicSelection?.status === "selected" && formulatedQuestion
? {
nodeId: deterministicSelection.nodeId,
question:
formulatedQuestion.question || deterministicSelection.question,
reason: formulatedQuestion.reason,
strategy: formulatedQuestion.strategy,
investigationStrategy: formulatedQuestion.investigationStrategy,
reasoningPattern: formulatedQuestion.reasoningPattern,
reasoningPatternReason: formulatedQuestion.reasoningPatternReason,
questionFamily: formulatedQuestion.questionFamily,
allowedQuestionFamilies: formulatedQuestion.allowedQuestionFamilies,
rejectedQuestionFamilies:
formulatedQuestion.rejectedQuestionFamilies,
selectedQuestionTemplate:
formulatedQuestion.selectedQuestionTemplate,
questionComplexity: formulatedQuestion.questionComplexity,
plainLanguageNormalisations:
formulatedQuestion.plainLanguageNormalisations,
}
: null;
return {
selectedNode,
formulatedQuestion,
selectedQuestion,
};
}
function resolveAmbiguousGraphBackedSelection({
graphSnapshot,
updatedSituationGraph,
deterministicSelection,
}) {
const orderedCandidateIds =
deterministicSelection?.displayOrder ||
deterministicSelection?.tiedCandidateIds ||
[];
for (const candidateNodeId of orderedCandidateIds) {
if (
!isSelectableUnresolvedUnknown(updatedSituationGraph, candidateNodeId)
) {
continue;
}
const candidateResult = runDeterministicDecomposition({
graphSnapshot,
proposalSnapshot: {
addedNodes: [],
updatedNodes: [],
addedEdges: [],
removedEdgeIds: [],
resolvedUnknownNodeIds: [],
affectedNodeIds: [],
selectedQuestion: null,
},
updatedSituationGraph: cloneJsonSafe(updatedSituationGraph),
reasoningResolution: { reasoningStateOverride: {} },
deterministicSelection: {
status: "selected",
nodeId: candidateNodeId,
reason:
"Selected this tied candidate for deterministic decomposition-based reselection.",
},
});
if (!candidateResult.success) {
continue;
}
const nextGraph = candidateResult.updatedSituationGraph;
nextGraph.reasoningState = buildReasoningState(nextGraph);
const nextSelection = isSelectableUnresolvedUnknown(
nextGraph,
candidateResult.selectedChildNodeId,
)
? {
status: "selected",
nodeId: candidateResult.selectedChildNodeId,
reason:
"Selected the preserved decomposition child after resolving an initial tie.",
}
: candidateResult.deterministicSelection;
const questionResult = buildSelectedQuestionResult({
updatedSituationGraph: nextGraph,
deterministicSelection: nextSelection,
});
if (questionResult.selectedQuestion?.question) {
nextGraph.activeUnknownNodeId =
nextSelection?.status === "selected" ? nextSelection.nodeId : null;
nextGraph.currentSummary = describeGraph(nextGraph);
return {
...candidateResult,
updatedSituationGraph: nextGraph,
deterministicSelection: nextSelection,
...questionResult,
};
}
}
return null;
}
export function determineGraphBackedQuestion({ situationGraph }) {
const graphSnapshot = cloneJsonSafe(situationGraph);
let updatedSituationGraph = cloneJsonSafe(situationGraph);
@@ -2090,52 +2221,48 @@ export function determineGraphBackedQuestion({ situationGraph }) {
: null;
updatedSituationGraph.currentSummary = describeGraph(updatedSituationGraph);
const selectedNode =
deterministicSelection?.status === "selected"
? findNodeById(updatedSituationGraph, deterministicSelection.nodeId)
: null;
const formulatedQuestion = selectedNode
? formulateQuestion({
node: selectedNode,
graph: updatedSituationGraph,
context: { selectionState: deterministicSelection },
})
: null;
let questionResult = buildSelectedQuestionResult({
updatedSituationGraph,
deterministicSelection,
});
if (
deterministicSelection?.status === "ambiguous" &&
!questionResult.selectedQuestion?.question
) {
const reselectionResult = resolveAmbiguousGraphBackedSelection({
graphSnapshot,
updatedSituationGraph,
deterministicSelection,
});
if (reselectionResult) {
updatedSituationGraph = reselectionResult.updatedSituationGraph;
deterministicSelection = reselectionResult.deterministicSelection;
questionResult = reselectionResult;
}
}
const noQuestionReason = questionResult.selectedQuestion?.question
? null
: deterministicSelection?.status === "ambiguous"
? questionResult.selectedQuestion?.questionSuppressedReason ||
questionResult.selectedQuestion?.reason ||
"Eligible unresolved candidates remain tied after initial graph-backed selection."
: (updatedSituationGraph.nodes || []).some(
(node) =>
node.kind === "unknown" &&
!["resolved", "contradicted"].includes(node.status) &&
!(updatedSituationGraph.resolvedNodeIds || []).includes(node.id),
)
? "Compatible unresolved candidates remain, but none produced a valid graph-backed question."
: "No unresolved unknown candidates remain after initial graph construction.";
return {
success: true,
updatedSituationGraph,
deterministicSelection,
selectedQuestion:
deterministicSelection?.status === "ambiguous"
? {
id: "q_tie_resolution",
...formulateTieResolutionQuestion({ graph: updatedSituationGraph }),
nodeId: null,
tiedCandidateIds: deterministicSelection.tiedCandidateIds,
}
: deterministicSelection?.status === "selected" && formulatedQuestion
? {
nodeId: deterministicSelection.nodeId,
question:
formulatedQuestion.question || deterministicSelection.question,
reason: formulatedQuestion.reason,
strategy: formulatedQuestion.strategy,
investigationStrategy: formulatedQuestion.investigationStrategy,
reasoningPattern: formulatedQuestion.reasoningPattern,
reasoningPatternReason: formulatedQuestion.reasoningPatternReason,
questionFamily: formulatedQuestion.questionFamily,
allowedQuestionFamilies:
formulatedQuestion.allowedQuestionFamilies,
rejectedQuestionFamilies:
formulatedQuestion.rejectedQuestionFamilies,
selectedQuestionTemplate:
formulatedQuestion.selectedQuestionTemplate,
questionComplexity: formulatedQuestion.questionComplexity,
plainLanguageNormalisations:
formulatedQuestion.plainLanguageNormalisations,
}
: null,
selectedQuestion: questionResult.selectedQuestion,
atomicityAssessment: decompositionResult.atomicityAssessment,
answerabilityAssessment: decompositionResult.answerabilityAssessment,
independentlyAnswerable:
@@ -2160,7 +2287,8 @@ export function determineGraphBackedQuestion({ situationGraph }) {
selectedUnknownBefore: decompositionResult.selectedUnknownBefore,
selectedUnknownAfter: deterministicSelection?.nodeId ?? null,
questionComplexityAssessment:
formulatedQuestion?.questionComplexity ?? null,
questionResult.formulatedQuestion?.questionComplexity ?? null,
noQuestionReason,
};
}