fix(reasoning): enforce terminal post-mutation eligibility
This commit is contained in:
@@ -234,6 +234,14 @@ Experiment 54N tested whether an interpretation disagreement can be judged for m
|
||||
- Focused preservation run passed via `npx vitest run tests/graph/apply-proposal.test.js -t "60B.42|60B.11|replaces downstream pricing"`.
|
||||
- Broader duplicated post-mutation eligibility checks remain unchanged; this fixes the selector contract only, not the full stale-question lifecycle.
|
||||
|
||||
### 60B.43 terminal post-mutation eligibility
|
||||
|
||||
- Extended terminal-status exclusion across the remaining post-mutation eligibility checks in `lib/graph/apply-proposal.js` while leaving pre-mutation `validateSelectedQuestion(...)` unchanged.
|
||||
- `isSelectableUnresolvedUnknown(...)`, `remainingUnknownExists`, carried-active reuse, unresolved/eligible candidate listing, and pattern-compatible post-mutation selection now all treat `known|resolved|contradicted` as terminal/non-selectable.
|
||||
- Deterministic 60B.37-shaped closure regression now passes: proposal applies, `n_enterprise_customer_signing` resolves, `n_product_launch_decision` becomes known, `activeUnknownNodeId` becomes null, and final `selectedQuestion` becomes null.
|
||||
- Focused fallback case also passes: when the proposal-selected target becomes known but another real unresolved unknown remains, the terminal target is discarded and the real unresolved node is selected.
|
||||
- Focused preservation run passed via `npx vitest run tests/graph/apply-proposal.test.js -t "60B.43|60B.11|replaces downstream pricing"`; live rerun still required to prove the same outcome end-to-end under live conditions.
|
||||
|
||||
### When This Knowledge-Management Phase Is Complete
|
||||
|
||||
Provisional criteria for review (all confirmed met by Experiment 38 cold-start test):
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# 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:
|
||||
|
||||
- `known`
|
||||
- `resolved`
|
||||
- `contradicted`
|
||||
|
||||
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(...)`
|
||||
- `remainingUnknownExists`
|
||||
- `carriedActiveUnknownStillUnresolved`
|
||||
- `listUnresolvedUnknownCandidates(...)`
|
||||
- `listEligibleUnknownCandidates(...)`
|
||||
- `selectPatternCompatibleUnknownCandidate(...)`
|
||||
|
||||
### Terminal-status rule applied post-mutation
|
||||
|
||||
A selectable unresolved post-mutation target now requires:
|
||||
|
||||
```text
|
||||
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 = null`
|
||||
- `selectedQuestion = null`
|
||||
|
||||
## Preservation checks
|
||||
|
||||
Focused run also preserved:
|
||||
|
||||
- 60B.11 preferred-target behaviour
|
||||
- pricing prerequisite-first behaviour
|
||||
- resolved exclusion
|
||||
- contradicted exclusion
|
||||
|
||||
## Validation
|
||||
|
||||
Command run:
|
||||
|
||||
```bash
|
||||
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.
|
||||
Reference in New Issue
Block a user