4.2 KiB
Experiment 60B.19 — Bounded Structural Context Admission
Branch: feature/reasoning-context-compatibility-v0.28
Date: 2026-08-13
Status: COMPLETE
Type: BOUNDED IMPLEMENTATION
Objective
Replace the blocked 60B.16 global reasoning-compatibility fallback with the 60B.18 boundary:
- run structural context fallback only for newly-added unresolved unknowns;
- run it only when the full proposal is known but before graph mutation;
- use the pre-update
activeUnknownNodeIdas the decision-context identity; - preserve that same-turn admission through later validation without changing generic compatibility semantics for unrelated nodes.
Why the global 60B.16 integration was removed
60B.17 established that the structural Route A / Route B predicate itself was useful, but its global integration layer was too broad. Applying fallback inside generic compatibility checks caused 8 apply-proposal regressions by changing behaviour for unrelated pre-existing and later-selected unknowns.
The secondary defect was that later compatibility re-checks could lose the original decision-context identity and validate against the wrong active node.
Implemented boundary
Structural context fallback now runs only at the pre-mutation proposal boundary:
- eligibility is limited to
proposal.addedNodeswhere:kind === "unknown"status !== "resolved"
- the original context identity is:
situationGraph.activeUnknownNodeId
- the original context pattern is recovered from the pre-update graph
- structural admission is only relevant when:
activePattern === "decision"
No pre-existing unknowns, updated existing nodes, resolved nodes, or later-selected targets enter the fallback by scope.
Route A / Route B
Route A
Admit a newly-added unresolved unknown when its parentId / ancestor chain reaches the original active decision context node.
Route B
Admit a newly-added unresolved unknown when:
X --(may_cause | causes | affects)--> option ZZ --contained_in--> active decision DD.id === pre-update activeUnknownNodeId
Explicit non-qualifiers
These do not establish Route B:
supportsmeasuresdepends_on- arbitrary graph connectivity
Local admitted-node tracking
No schema field was added.
Within applyValidatedProposal() only, the implementation now maintains a local in-memory set of structurally admitted node IDs for same-turn newly-added unresolved unknowns.
That set is then threaded into later compatibility checks so the exact already-adjudicated diagnosis→decision mismatch is not rejected again during post-mutation selection/result validation.
This does not:
- rewrite intrinsic node pattern;
- make the node universally compatible;
- disable non-pattern validations;
- change question targeting, scoring, materiality, prompt, or schema.
Regression restoration
Focused suite:
npx vitest run tests/graph/reasoning-context-compatibility.test.js→ PASS (14/14)
Combined bounded verification:
npx vitest run tests/graph/apply-proposal.test.js tests/graph/reasoning-context-compatibility.test.js→ PASS (96/96)
This restored the 8 60B.17 regressions by construction:
- pre-existing unknowns no longer enter fallback;
- later-selected 60B.11 fixtures no longer trigger fallback merely because they are chosen after mutation;
- later compatibility re-checks now use the preserved original reasoning-context node identity instead of selected-child drift;
- generic compatibility semantics remain unchanged outside the bounded same-turn admission class.
What remains unproven
Still unproven until the exact live regression is rerun:
- the precise 60B.12 client-retention continuation case in a live end-to-end path where the model introduces the factor and the final selected target preserves that same ready material unknown.
Production code changed
YES — lib/graph/apply-proposal.js
Tests changed
YES — tests/graph/reasoning-context-compatibility.test.js
Prompt changed
NO
Schema changed
NO
Question targeting changed
NO
Materiality changed
NO
Selection scoring changed
NO
Ollama calls
0
Live API calls
0