fix(reasoning): preserve ready material question target

This commit is contained in:
2026-08-13 09:36:10 +01:00
parent 854c3aa002
commit 54bc48342b
4 changed files with 705 additions and 12 deletions
+64
View File
@@ -1982,6 +1982,41 @@ function selectPatternCompatibleUnknownCandidate({
]);
}
function hasUnresolvedSameProposalDependsOnPrerequisite({
graph,
proposal,
targetNodeId,
}) {
const addedNodeIds = new Set(
(proposal?.addedNodes || []).map((node) => node.id),
);
if (!addedNodeIds.has(targetNodeId)) return false;
const targetNode = findNodeById(graph, targetNodeId);
if (!targetNode) return false;
const directPrerequisiteIds = new Set();
for (const dependencyId of targetNode.dependsOn || []) {
directPrerequisiteIds.add(dependencyId);
}
for (const edge of graph.edges || []) {
if (
edge.relationship === "depends_on" &&
edge.fromNodeId === targetNodeId &&
edge.toNodeId
) {
directPrerequisiteIds.add(edge.toNodeId);
}
}
return [...directPrerequisiteIds].some(
(nodeId) =>
addedNodeIds.has(nodeId) && isSelectableUnresolvedUnknown(graph, nodeId),
);
}
function collectPatternCompatibilityDiagnostics({
graph,
activePattern,
@@ -3677,6 +3712,35 @@ export function applyValidatedProposal({
const interactionSummary = propagationResult.interactionSummary;
const propagationReason = propagationResult.reason;
// Bounded model-selection honour: prefer a model-selected target only when it
// is still valid, was added in this proposal turn, and has no unresolved
// same-proposal-added unknown prerequisite via depends_on. Otherwise fall
// through to existing deterministic selection unchanged.
if (validatedProposal.selectedQuestion?.nodeId) {
const candidateNodeId = validatedProposal.selectedQuestion.nodeId;
const candidateWasAddedThisProposal = (
validatedProposal.addedNodes || []
).some((node) => node.id === candidateNodeId);
if (
isSelectableUnresolvedUnknown(updatedSituationGraph, candidateNodeId) &&
candidateWasAddedThisProposal &&
!hasUnresolvedSameProposalDependsOnPrerequisite({
graph: updatedSituationGraph,
proposal: validatedProposal,
targetNodeId: candidateNodeId,
})
) {
deterministicSelection = {
status: "selected",
nodeId: candidateNodeId,
reason:
"Honoured the model-selected unresolved unknown as preferred target because it was added in this proposal and has no unresolved same-proposal depends_on prerequisite.",
};
}
}
if (
deterministicSelection?.status === "selected" &&
deterministicSelection?.nodeId
+2 -2
View File
@@ -116,7 +116,7 @@ The JSON object must contain exactly these top-level fields:
13a. For every new unknown node, include at least one added edge that connects it to an existing updated/resolved node or to a newly added non-unknown node introduced from the answer.
14. Do not invent evidence.
15. Do not create unsupported causal edges.
16. When your proposal adds one or more new unresolved unknowns (status !== 'resolved'), you MUST include a selectedQuestion identifying one of those as a candidate unknown node. The engine validates your candidate and retains deterministic final-priority selection; your candidate does not need to be the highest-scoring unknown — it only needs to be a valid unresolved unknown that exists in the graph or in addedNodes.
16. When your proposal adds one or more new unresolved unknowns (status !== 'resolved'), you MUST include a selectedQuestion identifying one of those as a candidate unknown node. The engine validates your candidate and retains deterministic prerequisite ordering, fallback selection, and formulation authority; prefer nodes with no unresolved depends_on prerequisites from same-proposal additions. Your candidate does not need to be the highest-scoring unknown — it only needs to be a valid unresolved unknown that exists in the graph or in addedNodes.
17. selectedQuestion.nodeId must reference an unresolved unknown node that exists either already in the graph or in addedNodes.
18. selectedQuestion.question must be one narrow non-compound question about that one unknown.
19. Do not prioritise downstream implementation, pricing, optimisation, or speculative branches ahead of prerequisite definitions, actors, success criteria, constraints, measures, or terminology.
@@ -169,7 +169,7 @@ When answerMeaning.userSupportedMeaning is populated you MUST set structuralActi
- If the answer creates a more specific decision situation, add the smallest set of new nodes and edges needed to represent that situation and only its most consequential unknowns.
- If you add a new unknown, do not leave it floating: connect it with an added edge to the relevant decision/context node created or updated from the answer.
- If you add a new unknown, its description must do two jobs in one sentence: what is unknown, and why resolving it matters for the case.
- When selectedQuestion is provided, your role ends at supplying one valid unresolved unknown node from the graph or addedNodes — the engine retains deterministic final-priority selection and may choose a different question if multiple candidates exist.
- When selectedQuestion is provided, identify the specific material continuation factor as selectedQuestion.nodeId; the engine retains deterministic prerequisite ordering, validation, and formulation authority — it favours your selected node when it has no unresolved depends_on prerequisites from same-proposal additions, falls back to existing deterministic selection otherwise, and may choose a different question if structural constraints require.
- If rule #6 does not apply (the answer contains no user-supported meaning that requires graph progress) and there is no other justification for change, return empty arrays for every category.
- If rule #6 applies but you choose an update/refinement of existing structure, resolve an existing unknown, or add justified new structure, your structural proposal plus answerMeaning together represent the complete response — answerMeaning preserves semantic fidelity while structural mutation handles graph progress; neither replaces the other.
- If you add a new unknown with addedNodes, connect it with at least one addedEdge to an existing updated/resolved node or to a newly added non-unknown node from the answer.