fix: reselect after reasoning pattern filtering
This commit is contained in:
+170
-42
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ function buildDiagnostics({
|
||||
compatibilityFailures,
|
||||
replacementActions,
|
||||
graphReasoningIntegrity,
|
||||
noQuestionReason,
|
||||
}) {
|
||||
return {
|
||||
promptVersion: analysis?.promptVersion ?? null,
|
||||
@@ -112,6 +113,28 @@ function buildDiagnostics({
|
||||
compatibilityFailures: compatibilityFailures ?? [],
|
||||
replacementActions: replacementActions ?? [],
|
||||
graphReasoningIntegrity: graphReasoningIntegrity ?? null,
|
||||
noQuestionReason: noQuestionReason ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
function fallbackStartCaseReasoningPatternValidation(
|
||||
selectedQuestion,
|
||||
existingValidation,
|
||||
) {
|
||||
if (existingValidation) {
|
||||
return existingValidation;
|
||||
}
|
||||
|
||||
if (!selectedQuestion?.reasoningPattern) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
activePattern: selectedQuestion.reasoningPattern,
|
||||
valid: Boolean(selectedQuestion.question),
|
||||
reason: selectedQuestion.question
|
||||
? "Initial graph-backed selection produced a reasoning-pattern-compatible question."
|
||||
: "Initial graph-backed selection did not produce a valid question for the inferred reasoning pattern.",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -443,8 +466,10 @@ export async function startCase(body) {
|
||||
reasoningPatternReason:
|
||||
initialQuestionResult.selectedQuestion?.reasoningPatternReason ??
|
||||
null,
|
||||
reasoningPatternValidation:
|
||||
initialQuestionResult.reasoningPatternValidation ?? null,
|
||||
reasoningPatternValidation: fallbackStartCaseReasoningPatternValidation(
|
||||
initialQuestionResult.selectedQuestion,
|
||||
initialQuestionResult.reasoningPatternValidation,
|
||||
),
|
||||
patternCompatibleNodeCount:
|
||||
initialQuestionResult.patternCompatibleNodeCount ?? 0,
|
||||
incompatibleNodeIds: initialQuestionResult.incompatibleNodeIds ?? [],
|
||||
@@ -453,6 +478,7 @@ export async function startCase(body) {
|
||||
replacementActions: initialQuestionResult.replacementActions ?? [],
|
||||
graphReasoningIntegrity:
|
||||
initialQuestionResult.graphReasoningIntegrity ?? null,
|
||||
noQuestionReason: initialQuestionResult.noQuestionReason ?? null,
|
||||
}),
|
||||
validationErrors: graphReferenceValidation.errors,
|
||||
statusCode: 500,
|
||||
@@ -509,8 +535,10 @@ export async function startCase(body) {
|
||||
null,
|
||||
reasoningPatternReason:
|
||||
initialQuestionResult.selectedQuestion?.reasoningPatternReason ?? null,
|
||||
reasoningPatternValidation:
|
||||
initialQuestionResult.reasoningPatternValidation ?? null,
|
||||
reasoningPatternValidation: fallbackStartCaseReasoningPatternValidation(
|
||||
initialQuestionResult.selectedQuestion,
|
||||
initialQuestionResult.reasoningPatternValidation,
|
||||
),
|
||||
patternCompatibleNodeCount:
|
||||
initialQuestionResult.patternCompatibleNodeCount ?? 0,
|
||||
incompatibleNodeIds: initialQuestionResult.incompatibleNodeIds ?? [],
|
||||
@@ -518,6 +546,7 @@ export async function startCase(body) {
|
||||
replacementActions: initialQuestionResult.replacementActions ?? [],
|
||||
graphReasoningIntegrity:
|
||||
initialQuestionResult.graphReasoningIntegrity ?? null,
|
||||
noQuestionReason: initialQuestionResult.noQuestionReason ?? null,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user