3.5 KiB
Experiment 60B.43 — Terminal post-mutation eligibility
Date: 2026-08-14
Branch: feature/post-mutation-terminal-eligibility-v0.38
Purpose
Extend the 60B.42 selector guard to the remaining post-mutation question-target eligibility checks so terminal-status unknown nodes cannot remain active or become the final selected question after mutation.
Starting point from 60B.42
60B.42 fixed selectActiveUnknownCandidate(...) so it no longer scores or returns unknown-kind nodes whose status is terminal:
knownresolvedcontradicted
That closed one fallback source, but several independent post-mutation checks in apply-proposal.js still used weaker eligibility rules and could keep terminal nodes alive through other paths.
Remaining post-mutation eligibility changes
This experiment changed post-mutation eligibility only in lib/graph/apply-proposal.js.
Updated paths:
isSelectableUnresolvedUnknown(...)remainingUnknownExistscarriedActiveUnknownStillUnresolvedlistUnresolvedUnknownCandidates(...)listEligibleUnknownCandidates(...)selectPatternCompatibleUnknownCandidate(...)
Terminal-status rule applied post-mutation
A selectable unresolved post-mutation target now requires:
kind === unknown
status NOT IN [known, resolved, contradicted]
not in resolvedNodeIds
Important boundary preserved
validateSelectedQuestion(...) was not changed.
The closure proposal remains valid pre-mutation even when:
selectedQuestion.nodeId = n_product_launch_decision- the same proposal updates
n_product_launch_decision -> known
Only after mutation is that now-terminal target discarded.
60B.37 deterministic regression
Added focused regression:
60B.43 — terminal post-mutation target is cleared after valid decision closure
Reproduced the 60B.37-shaped closure:
- existing active unknown:
n_enterprise_customer_signing - proposal resolves
n_enterprise_customer_signing - proposal updates
n_product_launch_decision -> known - proposal still selects
n_product_launch_decision - no added nodes or edges
Result
- proposal applied successfully
- customer factor resolved in place
- decision became known in place
- both options preserved unchanged
activeUnknownNodeId = null- final
selectedQuestion = null
Fallback-to-real-unknown result
Added a second focused case where:
- proposal-selected target becomes
known - another genuine unresolved unknown remains after mutation
Result:
- terminal known target discarded
- remaining genuine unresolved candidate selected
Known-only post-mutation result
Added a valid mutated case where the final remaining unknown becomes known in the same mutation.
Result:
activeUnknownNodeId = nullselectedQuestion = null
Preservation checks
Focused run also preserved:
- 60B.11 preferred-target behaviour
- pricing prerequisite-first behaviour
- resolved exclusion
- contradicted exclusion
Validation
Command run:
npx vitest run tests/graph/apply-proposal.test.js -t "60B.43|60B.11|replaces downstream pricing"
Result:
- PASS —
14 passed | 76 skipped
What remains unproven until live rerun
This deterministic bounded fix now clears the exact 60B.37-shaped stale target through the post-mutation production path under test.
What remains unproven until a live rerun is whether the full runtime/orchestration path with the real customer-signing closure answer produces the same null-question closure end state under live conditions.