experiment: define closure enforcement boundary
This commit is contained in:
@@ -4079,3 +4079,273 @@ Watchman used: NO
|
||||
Documentation updated: docs/experiment-60b78.md created; docs/current-handoff.md appended
|
||||
|
||||
Git status: will be clean after commit
|
||||
|
||||
---
|
||||
|
||||
#### Experiment 60B.79 — Closure Enforcement Boundary Analysis (READ-ONLY DESIGN)
|
||||
|
||||
**Date:** 2026-08-15
|
||||
**Branch:** `feature/sufficiency-decision-detection-v0.46`
|
||||
**Preceded by:** Experiment 60B.78 (explicit confirmation authoritatively gates closure)
|
||||
**Type:** Design analysis — no implementation
|
||||
|
||||
## Objective
|
||||
|
||||
Determine the smallest deterministic enforcement boundary that prevents model-led terminal closure without explicit confirmation, while preserving legitimate model reasoning/direction and keeping State B reachable.
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 1 — Direction representation
|
||||
|
||||
Existing fields carrying directional meaning WITHOUT parent terminal status:
|
||||
|
||||
| Field | Directional? | Requires terminal? | Survives removal? | Used downstream? |
|
||||
|-------|-------------|-------------------|-------------------|-----------------|
|
||||
| `answerMeaning.userSupportedMeaning` | YES | NO | YES | PARTIAL |
|
||||
| `answerMeaning.possibleInference` | YES | NO | YES | PARTIAL |
|
||||
| `answerMeaning.supportCategory` | PARTIAL | NO | YES | PARTIAL |
|
||||
| `answerMeaning.resolutionGuidance` | PARTIAL | NO | YES | YES |
|
||||
| `updatedNodes[].newValue` (child nodes) | YES | NO | YES | YES |
|
||||
| `updatedNodes[].newStatus` (non-parent) | PARTIAL | NO | YES | YES |
|
||||
| `updatedNodes[].reason` | YES (text) | NO | YES | PARTIAL |
|
||||
|
||||
Direction survives removal of parent terminal update via `userSupportedMeaning`, `possibleInference`, and child node updates. These are the legitimate channels for "launch is better" without closing the decision.
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 2 — What must be blocked
|
||||
|
||||
### Case A — Model proposes: decision → resolved, value = null
|
||||
- Block terminal status: **YES**
|
||||
- Direction preservable separately: **YES** (via `userSupportedMeaning` + `possibleInference`)
|
||||
- State B reachable: **YES**
|
||||
|
||||
### Case B — Model proposes: decision → known, value = "launch this year"
|
||||
- Block terminal status: **YES**
|
||||
- Direction preservable separately: **YES** (`userSupportedMeaning` can state same direction; child node values also survive). Critical note: `newValue` on unknown-status decision is semantically contradictory (see Checkpoint 6).
|
||||
- State B reachable: **YES**
|
||||
|
||||
### Case C — Model proposes: decision → resolved, value = "launch this year"
|
||||
- Block terminal status: **YES**
|
||||
- Direction preservable separately: **YES** (`userSupportedMeaning` + `possibleInference` carry direction; child updates survive)
|
||||
- State B reachable: **YES**
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 3 — Normalisation candidate
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Deterministic guarantee | HIGH |
|
||||
| Proposal remains usable | YES |
|
||||
| Customer resolution preserved | YES |
|
||||
| Option updates preserved | YES |
|
||||
| Direction preservable | CONDITIONAL — survives in `answerMeaning` but NOT as newValue on unknown decision |
|
||||
| Retry required | NO |
|
||||
| State B reachable | YES |
|
||||
| Silent-intent-change risk | MEDIUM |
|
||||
| Principal weakness | Model's directional conclusion on parent is lost to downstream consumers that check parent newValue/status rather than answerMeaning. Direction only survives in text fields, not structural form. |
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 4 — Rejection candidate
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Deterministic guarantee | HIGH |
|
||||
| Customer resolution lost | YES (entire proposal discarded) |
|
||||
| Retry required | YES |
|
||||
| Repeat-proposal risk | HIGH (60B.77 proved pattern is deterministic) |
|
||||
| State B reachable without retry | NO |
|
||||
| Semantic cleanliness | HIGH |
|
||||
| Principal weakness | Total loss of proposal work + high retry loop probability |
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 5 — Partial normalisation shape
|
||||
|
||||
Can reconciliation safely produce stripped shape (parent terminal removed, other updates preserved)?
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Safe shape possible | CONDITIONAL — reconcileResolutionSemantics line 356 forces newStatus="resolved" for nodes in resolvedUnknownNodeIds. A dedicated pre-validation step needed before reconciliation. |
|
||||
| Validators accept | NO (current reconciler forces terminal) / UNPROVEN with modification |
|
||||
| selectedQuestion interference | UNPROVEN (depends on which question was selected) |
|
||||
| Bookkeeping consistent | UNPROVEN — depends on ordering: normalisation must fire BEFORE deterministic closure gate (line 3787) |
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 6 — Parent value semantics on unknown decision
|
||||
|
||||
**Choice: C — TECHNICALLY ACCEPTED BUT SEMANTICALLY UNSAFE**
|
||||
|
||||
The schema accepts any newValue regardless of status. `applyGraphUpdate` applies it unconditionally. But:
|
||||
- An unknown-status node with a non-null value conflates determination with incompleteness
|
||||
- No downstream code path was designed for this hybrid state
|
||||
- Propagation (line 777) ignores them for resolution counting
|
||||
- **Do NOT preserve direction on parent node.** Use `answerMeaning.userSupportedMeaning` and `possibleInference` instead.
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 7 — Enforcement location
|
||||
|
||||
### Boundary A — reconcileResolutionSemantics()
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Raw answer available | NO |
|
||||
| Graph available | YES |
|
||||
| Proposal mutable | YES |
|
||||
| Retry risk | LOW |
|
||||
| Separation | LOW (confounds policy with semantic cleanup) |
|
||||
| Semantic risk | MEDIUM (requires adding answer parameter — changes function signature) |
|
||||
| Principal weakness | No raw answer. Cannot detect confirmation absence without modifying function interface. |
|
||||
|
||||
### Boundary B — Post-reconciliation, pre-validation
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Raw answer available | YES |
|
||||
| Graph available | YES |
|
||||
| Proposal mutable | CONDITIONAL (after line 3549, before line 3552) |
|
||||
| Retry risk | LOW |
|
||||
| Separation | HIGH (dedicated boundary layer owns closure policy) |
|
||||
| Semantic risk | LOW |
|
||||
| Principal weakness | Adds pipeline step but gap exists naturally at line 3549-3552. **RECOMMENDED LOCATION.** |
|
||||
|
||||
### Boundary C — Compatibility validation
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Raw answer available | CONDITIONAL (not all validators receive it) |
|
||||
| Graph available | YES |
|
||||
| Proposal mutable | NO (rejection returns immediately) |
|
||||
| Retry risk | HIGH |
|
||||
| Separation | MEDIUM (blurs validation/policy boundary) |
|
||||
| Semantic risk | LOW |
|
||||
| Principal weakness | Rejects ALL work. Retry loop risk HIGH. |
|
||||
|
||||
### Boundary D — Post-validation, pre-mutation (inside applyValidatedProposal)
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Raw answer available | CONDITIONAL (available as local variable at line 3493) |
|
||||
| Graph available | YES |
|
||||
| Proposal mutable | YES (proposalSnapshot at line 3659) |
|
||||
| Retry risk | MEDIUM |
|
||||
| Separation | LOW (merges with existing gate at lines 3787-3851) |
|
||||
| Semantic risk | MEDIUM |
|
||||
| Principal weakness | Existing gate only ADDS closures; doesn't STRIP model-proposed ones. Adding strip logic here is consistent but conflates two responsibilities in one function. |
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 8 — Prompt alignment
|
||||
|
||||
**Prompt clarification required:** YES
|
||||
|
||||
**Conflicting rule:** Rule 143 (prompt-builder.js line 143):
|
||||
> "If the currently supported evidence is sufficient to distinguish the options and no such material unresolved factor remains, resolve the existing decision context."
|
||||
|
||||
This permits closure based on model judgment alone. Does NOT require user confirmation.
|
||||
|
||||
**Minimum semantic change:** Add explicit requirement that closure requires user confirmation matching deterministic gate criteria. Example:
|
||||
> "You may not resolve the decision context unless the user explicitly confirms (using their own words) that no other material uncertainty remains. If you judge evidence sufficient but user has not confirmed, state directional conclusion in possibleInference and recommend continuation question."
|
||||
|
||||
**Would prompt clarification alone be sufficient:** NO — 60B.78 confirmed stochastic compliance is insufficient when model closure pattern was proven deterministic (60B.77).
|
||||
|
||||
---
|
||||
|
||||
## Candidate enforcement models assessment
|
||||
|
||||
### Model A — PROMPT ONLY
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature closure | NO |
|
||||
| Preserves proposal work | HIGH/LOW (stochastic) |
|
||||
| Preserves direction safely | PARTIAL |
|
||||
| Retry risk | MEDIUM |
|
||||
| State B reachable | STOCHASTIC |
|
||||
| Schema change | NO |
|
||||
| Principal weakness | Same fundamental problem as current state |
|
||||
|
||||
### Model B — REJECT WHOLE PROPOSAL
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature closure | YES |
|
||||
| Preserves proposal work | LOW (total loss) |
|
||||
| Preserves direction safely | NO |
|
||||
| Retry risk | HIGH |
|
||||
| State B reachable | CONDITIONAL |
|
||||
| Schema change | NO |
|
||||
| Principal weakness | Total loss + high retry loop probability |
|
||||
|
||||
### Model C — NORMALISE TERMINAL PARENT UPDATE AWAY
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature closure | YES |
|
||||
| Preserves proposal work | HIGH |
|
||||
| Preserves direction safely | PARTIAL (answerMeaning only) |
|
||||
| Retry risk | LOW |
|
||||
| State B reachable | YES |
|
||||
| Schema change | NO |
|
||||
| Principal weakness | Direction lost from parent node; survives only in text fields |
|
||||
|
||||
### Model D — NORMALISE STATUS BUT KEEP PARENT VALUE
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature closure | YES |
|
||||
| Preserves proposal work | HIGH |
|
||||
| Preserves direction safely | NO (semantically contradictory, unhandled edge case) |
|
||||
| Retry risk | LOW |
|
||||
| State B reachable | YES |
|
||||
| Schema change | NO (creates unhandled edge case) |
|
||||
| Principal weakness | Hybrid unknown+value state no downstream code handles correctly |
|
||||
|
||||
### Model E — NORMALISE TERMINAL UPDATE AWAY, PRESERVE OTHER EVIDENCE
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature closure | YES |
|
||||
| Preserves proposal work | HIGH |
|
||||
| Preserves direction safely | PARTIAL (answerMeaning survives; parent node direction does not) |
|
||||
| Retry risk | LOW |
|
||||
| State B reachable | YES |
|
||||
| Schema change | NO |
|
||||
| Principal weakness | Direction only in text fields, not structural form on parent. Acceptable trade-off vs Model D's unhandled edge case or Model B's total loss. |
|
||||
|
||||
---
|
||||
|
||||
## Critical distinction
|
||||
|
||||
**Choice: E — CURRENT REPRESENTATION CANNOT PRESERVE DIRECTION SAFELY**
|
||||
|
||||
Why: On an unknown-status decision node, a non-null newValue is semantically contradictory (Checkpoint 6, Choice C). Schema accepts it technically but no downstream code path handles it correctly. Direction CAN survive in answerMeaning.userSupportedMeaning and possibleInference — these fields exist for carrying user intent independent of status. But this is PARTIAL preservation (textual, not structural on the parent).
|
||||
|
||||
**Practical consequence:** Model E is best available because it deterministically prevents premature closure while preserving direction in the canonical channel (answerMeaning) where current semantics safely permit it. State B remains reachable and no schema change needed.
|
||||
|
||||
---
|
||||
|
||||
## Minimum corrective boundary
|
||||
|
||||
**Choice: C — prompt clarification + dedicated pre-validation closure-ownership normalisation**
|
||||
|
||||
Why:
|
||||
1. Explicit confirmation remains authoritative (deterministic enforcement)
|
||||
2. Customer-factor resolution survives in preserved non-parent updates
|
||||
3. Unrelated proposal work preserved (Model E approach)
|
||||
4. No retry loop (application proceeds, State B fires naturally)
|
||||
5. State B reachable deterministically
|
||||
6. Parent lifecycle internally consistent (no hybrid states)
|
||||
7. Direction preserved only where current semantics safely permit it (answerMeaning)
|
||||
8. No schema change
|
||||
|
||||
**Would explicit confirmation remain authoritative:** YES
|
||||
**Would customer-factor resolution survive:** YES
|
||||
**Would State B remain reachable:** YES
|
||||
**Would retry loops be avoided:** YES
|
||||
**Would schema remain unchanged:** YES
|
||||
|
||||
---
|
||||
|
||||
## Implementation readiness
|
||||
|
||||
**Choice: A — READY FOR BOUNDED IMPLEMENTATION**
|
||||
|
||||
One unresolved question: Boundary B (dedicated pre-validation function) vs Boundary D (extend existing gate). Boundary D is more tightly coupled but less architecturally clean. **Recommendation: Boundary B** — `reconcileDecisionClosureOwnership(graph, proposal, answer)` between reconciliation (line 3549) and validation (line 3552).
|
||||
|
||||
Smallest implementation boundary: One new function + one prompt rule change. No schema changes.
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
# Experiment 60B.79 — Closure Enforcement Boundary Analysis (READ-ONLY DESIGN)
|
||||
|
||||
**Date:** 2026-08-15
|
||||
**Branch:** `feature/sufficiency-decision-detection-v0.46`
|
||||
**Preceded by:** Experiment 60B.78 (explicit confirmation authoritatively gates closure)
|
||||
**Type:** Design analysis — no implementation
|
||||
|
||||
## Objective
|
||||
|
||||
Answer: **What is the smallest deterministic enforcement boundary that prevents model-led terminal closure without explicit confirmation, while preserving any legitimate model reasoning/direction and keeping State B reachable?**
|
||||
|
||||
Do not implement anything.
|
||||
|
||||
## Fixed Policy (settled per 60B.78)
|
||||
|
||||
```
|
||||
NO explicit user sufficiency confirmation
|
||||
=>
|
||||
parent decision must NOT become terminal
|
||||
```
|
||||
|
||||
Terminal = any status in TERMINAL_STATUSES: `known`, `resolved`, `contradicted`.
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 1 — How model direction is currently represented
|
||||
|
||||
Existing fields that carry directional meaning without parent terminal status:
|
||||
|
||||
| Field | Directional? | Requires terminal? | Survives removal? | Used downstream? |
|
||||
|-------|-------------|-------------------|-------------------|-----------------|
|
||||
| `answerMeaning.userSupportedMeaning` | YES | NO | YES | PARTIAL |
|
||||
| `answerMeaning.possibleInference` | YES | NO | YES | PARTIAL |
|
||||
| `answerMeaning.supportCategory` | PARTIAL | NO | YES | PARTIAL |
|
||||
| `answerMeaning.resolutionGuidance` | PARTIAL | NO | YES | YES |
|
||||
| `updatedNodes[].newValue` (child nodes) | YES | NO | YES | YES |
|
||||
| `updatedNodes[].newStatus` (non-parent) | PARTIAL | NO | YES | YES |
|
||||
| `updatedNodes[].reason` | YES (text) | NO | YES | PARTIAL |
|
||||
|
||||
Direction survives removal of parent terminal update via `userSupportedMeaning`, `possibleInference`, and child node updates. These are the legitimate channels for expressing "launch is better" without closing the decision.
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 2 — What exactly must be blocked
|
||||
|
||||
### Case A — Model proposes: decision → resolved, value = null
|
||||
|
||||
- **Should terminal status be blocked:** YES
|
||||
- **Can directional value be preserved separately under current representation:** YES — via `userSupportedMeaning` (states what user answered) and `possibleInference` (stronger interpretation). These fields exist precisely to carry the answer's meaning independently of decision closure.
|
||||
- **Can State B remain reachable afterwards:** YES — decision remains "unknown" → activeUnknownNodeId is non-null → State B questioning fires.
|
||||
|
||||
### Case B — Model proposes: decision → known, value = "launch this year"
|
||||
|
||||
- **Should terminal status be blocked:** YES
|
||||
- **Can directional value be preserved separately under current representation:** YES — `userSupportedMeaning` can state the same direction factually. Child option/evidence nodes may also carry directional values as supporting evidence. The critical loss is that `newValue = "launch this year"` on an unknown-status decision node is semantically contradictory (value determined but investigation ongoing).
|
||||
- **Can State B remain reachable afterwards:** YES — decision remains "unknown" → State B fires.
|
||||
|
||||
### Case C — Model proposes: decision → resolved, value = "launch this year"
|
||||
|
||||
- **Should terminal status be blocked:** YES
|
||||
- **Can directional value be preserved separately under current representation:** YES — `userSupportedMeaning` + `possibleInference` carry the direction. Child node updates also survive independently.
|
||||
- **Can State B remain reachable afterwards:** YES — decision remains "unknown" → State B fires.
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 3 — Normalisation candidate
|
||||
|
||||
Policy: If parent terminal transition lacks explicit confirmation, remove/neutralise it while preserving all other proposal updates.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Deterministic guarantee | HIGH — stripping is mechanical; no branching logic |
|
||||
| Proposal remains usable | YES — customer/option/evidence updates remain intact |
|
||||
| Customer-factor resolution preserved | YES — those updates are separate from parent terminal transition |
|
||||
| Option updates preserved | YES — model's structural changes to options survive |
|
||||
| Direction preservable | CONDITIONAL — survives in `answerMeaning` fields but NOT as `newValue` on unknown decision (semantically contradictory) |
|
||||
| Retry required | NO — application proceeds with stripped proposal |
|
||||
| State B reachable | YES — decision stays "unknown" → State B fires |
|
||||
| Risk of silently changing model intent | MEDIUM — model loses its parent update without explanation; direction preserved only in `answerMeaning` text, not in the decision node itself |
|
||||
| Principal weakness | Model cannot see its directional conclusion encoded on the parent. If downstream consumers rely on `updatedNodes[].newValue` or parent status for their reasoning, they won't find it. Direction is only in `answerMeaning` text fields, which some downstream code may ignore. |
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 4 — Rejection candidate
|
||||
|
||||
Policy: If parent terminal transition lacks explicit confirmation, reject the whole proposal at compatibility validation.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Deterministic guarantee | HIGH — validation error is unambiguous |
|
||||
| Customer-factor resolution lost with rejected proposal | YES — entire proposal discarded, including customer/option/evidence updates |
|
||||
| Retry required | YES — model must produce a new proposal without the terminal closure |
|
||||
| Risk model repeats same proposal | HIGH — model's reasoning pattern (resolve last factor → close parent) is deterministic and prompt-influenced; it will likely propose the same closure again |
|
||||
| State B reachable without retry | NO — rejection prevents any forward progress until model retries differently |
|
||||
| Semantic cleanliness | HIGH — clean boundary: invalid proposals rejected before application |
|
||||
| Principal weakness | Loss of all proposal work. Model retry loop risk is HIGH because the model's closure pattern was proven deterministic (60B.77). Without prompt changes explaining WHY it was rejected, the model repeats. Even with explanation, repeated rejection is worse than unnecessary questioning cost that State B was designed for. |
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 5 — Partial normalisation shape
|
||||
|
||||
Can reconciliation safely produce:
|
||||
```
|
||||
BEFORE NORMALISATION → AFTER NORMALISATION
|
||||
updatedNodes[customer→resolved] → updatedNodes[customer→resolved] (preserved)
|
||||
updatedNodes[decision→terminal] → removed → decision stays "unknown"
|
||||
resolvedUnknownNodeIds[customer, decision] → resolvedUnknownNodeIds[customer]
|
||||
```
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Can reconciliation safely produce this shape | CONDITIONAL — `reconcileResolutionSemantics` currently enforces that nodes in `resolvedUnknownNodeIds` must have status "resolved" in updatedNodes (line 356-364). It would need to NOT force terminal on the parent when confirmation is absent. The existing reconciliation logic assumes resolved = terminal, which conflicts with the normalisation goal. However, a pre-reconciliation hook could strip the parent before this function runs. |
|
||||
| Would existing validators accept it | NO — current `reconcileResolutionSemantics` line 356 forces `existingUpdate.newStatus = "resolved"` for any node in resolvedUnknownNodeIds. This is the exact conflict. A dedicated pre-validation step is needed before reconciliation, or reconciliation must be modified to accept non-terminal entries in resolvedUnknownNodeIds. |
|
||||
| Would selectedQuestion reconciliation interfere | UNPROVEN — `reconcileResolutionSemantics` line 378-390 clears selectedQuestion if its node is resolved. If parent decision stays unknown and selectedQuestion refers to a different node, no interference. Depends on which question was selected. |
|
||||
| Would closure bookkeeping remain internally consistent | UNPROVEN — `ensureResolvedUnknownId` (line 669) adds nodes to resolvedUnknownNodeIds during deterministic closure (lines 3824). If we strip the parent BEFORE deterministic closure fires, this is fine. If deterministic closure fires after normalisation and tries to add the parent back, it would re-close the decision. The ordering is critical: normalisation must happen before deterministic closure gate (line 3787+). |
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 6 — Value preservation on unknown decision node
|
||||
|
||||
**CRITICAL:** If model proposes `decision: newStatus=known, newValue="launch this year"`, and we remove the terminal update, can we keep `newValue = "launch this year"` on an `unknown` decision?
|
||||
|
||||
**Choice: C — TECHNICALLY ACCEPTED BUT SEMANTICALLY UNSAFE**
|
||||
|
||||
Why: The schema (lib/graph/schema.js line 145) accepts any string/number/null for `newValue` regardless of status. `applyGraphUpdate` (lib/graph/utils.js line 803-804) applies `newValue` unconditionally to the node's `value` field. So technically, a decision node with `status: "unknown"` and `value: "launch this year"` is accepted by the graph.
|
||||
|
||||
However, it is semantically contradictory:
|
||||
- `known` means "directional value determined" (TERMINAL_STATUSES includes it)
|
||||
- `unknown` means "needs investigation"
|
||||
- Having a non-null `value` on an `unknown` node conflates determination with incompleteness
|
||||
- Downstream code treats nodes in TERMINAL_STATUSES as investigated-complete. A node outside TERMINAL_STATUSES with a value is an inconsistent hybrid state that no existing code path was designed for.
|
||||
- Propagation logic (line 777) computes parent progress using child status, not values. An unknown-status decision with a value won't feed into propagation correctly — it's invisible to the resolution counting machinery while carrying misleading directional information.
|
||||
|
||||
**Conclusion:** Do NOT propose preserving the direction on the parent node. Direction must remain in `answerMeaning.userSupportedMeaning` and `possibleInference`, which are designed to carry answer meaning independently of decision status. These fields already exist and are downstream-consumed by State A/B selection logic.
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 7 — Enforcement location
|
||||
|
||||
### Boundary A — Inside reconcileResolutionSemantics()
|
||||
|
||||
Normalise parent terminal closure before compatibility validation.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Has raw answer available | NO — reconcileResolutionSemantics only receives (graph, proposal); no answer parameter |
|
||||
| Has graph available | YES |
|
||||
| Proposal still mutable | YES — returns a new cloned proposal |
|
||||
| Error/retry risk | LOW — silent normalisation |
|
||||
| Separation of concerns | LOW — reconciliation's purpose is semantic cleanup, not policy enforcement. Mixing closure ownership into this function conflates two distinct responsibilities. |
|
||||
| Semantic risk | MEDIUM — stripping based on missing confirmation requires the answer, which isn't available here without adding an answer parameter (changing the function signature). This would be a code change with broader implications. |
|
||||
| Principal weakness | No raw answer available. Cannot determine whether confirmation is present without passing the answer through. Changing function signature affects all callers. |
|
||||
|
||||
### Boundary B — Post-reconciliation, pre-validation
|
||||
|
||||
Dedicated function such as `reconcileDecisionClosureOwnership(graph, proposal, answer)`.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Has raw answer available | YES — answer is the original input to applyValidatedProposal (line 3493 parameter) |
|
||||
| Has graph available | YES — graph is also an input parameter |
|
||||
| Proposal still mutable | CONDITIONAL — after reconciliation produces reconciledProposal (line 3549), before validation (line 3552). The reconciled proposal is mutable at this point. |
|
||||
| Error/retry risk | LOW — deterministic stripping, no retry needed |
|
||||
| Separation of concerns | HIGH — dedicated boundary layer between reconciliation and validation explicitly owns closure ownership policy |
|
||||
| Semantic risk | LOW — clear location for policy; doesn't modify reconciliation semantics or validation rules. Normalisation is transparent to downstream layers. |
|
||||
| Principal weakness | Adds a new step in the pipeline. Must ensure it fires after reconciliation (so reconciled proposal structure is stable) and before validation (so validator doesn't see the invalid terminal transition). Currently, this gap exists naturally at line 3549-3552. |
|
||||
|
||||
### Boundary C — Proposal compatibility validation
|
||||
|
||||
Reject the whole proposal if parent terminal closure lacks confirmation.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Has raw answer available | CONDITIONAL — `validateAnswerMeaningCompatibilityWithRawAnswer` receives answer; other validators may not. Would need to pass answer through validation chain. |
|
||||
| Has graph available | YES |
|
||||
| Proposal still mutable | NO — at this point the proposal has been validated and is immutable; rejection returns errors immediately |
|
||||
| Error/retry risk | HIGH — rejection forces full model retry with uncertain understanding of why it was rejected |
|
||||
| Separation of concerns | MEDIUM — validation layer would need to understand closure policy semantics (confirmation detection), which blurs the line between structural validation and policy enforcement |
|
||||
| Semantic risk | LOW — rejection is clean; invalid proposals never reach mutation |
|
||||
| Principal weakness | Rejects ALL proposal work (customer resolution, option updates, evidence). Model retry loop risk HIGH per 60B.77 analysis. |
|
||||
|
||||
### Boundary D — Post-validation, pre-mutation
|
||||
|
||||
Strip terminal closure just before graph application.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Has raw answer available | CONDITIONAL — answer is a parameter to applyValidatedProposal but may not be forwarded through all validation steps. After line 3649 (validation succeeds), answer is still available as a local variable in the calling scope. |
|
||||
| Has graph available | YES |
|
||||
| Proposal still mutable | YES — `proposalSnapshot` at line 3659 is a cloned copy, fully mutable |
|
||||
| Error/retry risk | MEDIUM — mutation has already been computed (decomposition, propagation); stripping closure means re-computing if anything depends on the closure being applied first. Currently deterministic closure fires AFTER validation but BEFORE decomposition (line 3787), so this boundary is actually inside applyValidatedProposal's internal sequence, not post-mutation. |
|
||||
| Separation of concerns | LOW — merges with existing deterministic closure gate (lines 3787-3851). This IS the natural extension point: just add a confirmation check alongside the existing gate. |
|
||||
| Semantic risk | MEDIUM — the existing gate already does exactly this pattern for confirmed closures. Adding an additional guard (confirmation required before stripping model's terminal update) is consistent with the existing gate's intent but adds complexity to the gate's logic. |
|
||||
| Principal weakness | The deterministic closure gate (lines 3787-3851) only ADDS terminal updates when conditions are met; it doesn't STRIP them from model proposals. The existing code path allows model-proposed terminal transitions through without any additional check. This boundary requires adding the check where the model's proposed status is already committed to `proposalSnapshot`. |
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint 8 — Prompt alignment
|
||||
|
||||
**Prompt clarification required:** YES
|
||||
|
||||
**Existing conflicting rule:** Rule 143 (lib/graph/prompt-builder.js line 143):
|
||||
> "If the currently supported evidence is sufficient to distinguish the options and no such material unresolved factor remains, resolve the existing decision context."
|
||||
|
||||
This permits model-led closure based on model's judgment of sufficiency alone. It does NOT require user confirmation. The rule conflates "model-judged represented-factor exhaustion" with "user-confirmed nothing else material."
|
||||
|
||||
**Minimum semantic change:** Add explicit requirement that closure requires user confirmation matching the deterministic gate criteria. For example:
|
||||
|
||||
> "You may not resolve the decision context unless the user explicitly confirms (using their own words) that no other material uncertainty remains. If you judge evidence sufficient but the user has not confirmed sufficiency, state your directional conclusion in possibleInference and recommend a continuation question."
|
||||
|
||||
**Would prompt clarification alone be sufficient:** NO — 60B.78 already identified this; stochastic compliance is insufficient when the model's closure pattern was proven deterministic.
|
||||
|
||||
---
|
||||
|
||||
## Candidate enforcement models assessment
|
||||
|
||||
### Model A — PROMPT ONLY
|
||||
|
||||
No deterministic enforcement. Only reword Rule 143.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature terminal closure | NO — stochastic compliance; 60B.77 proved model closes deterministically |
|
||||
| Preserves useful proposal work | HIGH (if model complies) / LOW (if model doesn't) |
|
||||
| Preserves direction safely | PARTIAL — survives in answerMeaning but only if model writes it there instead of on the parent |
|
||||
| Retry risk | MEDIUM — model retries with same closure pattern; loop likely |
|
||||
| State B reachable | STOCHASTIC — depends on whether model complies with not closing |
|
||||
| Schema change | NO |
|
||||
| Principal weakness | Same fundamental problem as current state: model proven to close without confirmation. Prompt rule alone adds noise, not protection. |
|
||||
|
||||
### Model B — REJECT WHOLE PROPOSAL
|
||||
|
||||
Prompt clarification + compatibility rejection of invalid terminal closure.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature terminal closure | YES — deterministic rejection |
|
||||
| Preserves useful proposal work | LOW — entire proposal discarded |
|
||||
| Preserves direction safely | NO — all model output lost; must restart from scratch |
|
||||
| Retry risk | HIGH — model likely repeats same proposal (60B.77 proved pattern is deterministic) |
|
||||
| State B reachable | CONDITIONAL — only if model retries differently and doesn't close parent again |
|
||||
| Schema change | NO |
|
||||
| Principal weakness | Total loss of proposal work. High retry loop probability. Model may not understand why rejection occurred unless the rejection message explicitly explains "confirmation required." Even then, repeated rejections add friction without resolving the user's actual question. |
|
||||
|
||||
### Model C — NORMALISE TERMINAL PARENT UPDATE AWAY
|
||||
|
||||
Prompt clarification + deterministic pre-validation normalisation of parent terminal status only.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature terminal closure | YES — model cannot close without confirmation; stripping is deterministic |
|
||||
| Preserves useful proposal work | HIGH — customer/option/evidence updates all survive independently |
|
||||
| Preserves direction safely | PARTIAL — survives in answerMeaning but NOT as newValue on unknown decision (semantically contradictory per Checkpoint 6) |
|
||||
| Retry risk | LOW — application proceeds normally |
|
||||
| State B reachable | YES — decision remains "unknown" → State B fires deterministically |
|
||||
| Schema change | NO |
|
||||
| Principal weakness | Direction lost from parent node; only survives in text fields. Some downstream consumers may rely on parent newValue or status for their reasoning. Model's parental conclusion is unilaterally removed without explanation to the model itself. |
|
||||
|
||||
### Model D — NORMALISE STATUS BUT KEEP PARENT VALUE
|
||||
|
||||
Remove terminal status but keep newValue = "launch this year" on unknown decision.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature terminal closure | YES — status stays "unknown" (not in TERMINAL_STATUSES) |
|
||||
| Preserves useful proposal work | HIGH |
|
||||
| Preserves direction safely | NO — semantically contradictory state (Check #6: Choice C). Technically accepted but UNSAFE. No downstream code expects unknown-status nodes with values. Propagation ignores them for resolution counting. |
|
||||
| Retry risk | LOW |
|
||||
| State B reachable | YES |
|
||||
| Schema change | NO (but creates an unhandled edge case) |
|
||||
| Principal weakness | Creates a hybrid state that no existing code path handles correctly. Value exists without investigation being complete — invisible to propagation, misleading to completeness logic. This is the worst outcome: direction appears preserved but is functionally lost because downstream machinery cannot safely interpret it. |
|
||||
|
||||
### Model E — NORMALISE TERMINAL PARENT UPDATE AWAY, PRESERVE OTHER EVIDENCE
|
||||
|
||||
Remove parent terminal transition AND its resolved bookkeeping, retain all customer/option/evidence updates, let State B questioning proceed.
|
||||
|
||||
| Criterion | Assessment |
|
||||
|-----------|-----------|
|
||||
| Prevents premature terminal closure | YES — deterministic stripping of parent closure before validation/mutation |
|
||||
| Preserves useful proposal work | HIGH — all non-parent updates survive independently |
|
||||
| Preserves direction safely | PARTIAL — survives in answerMeaning.userSupportedMeaning and possibleInference. These fields are explicitly designed to carry answer meaning independent of decision status. Direction on the parent node itself is NOT preserved (semantically contradictory on unknown). |
|
||||
| Retry risk | LOW — application proceeds with normalized proposal; State B fires naturally |
|
||||
| State B reachable | YES — decision remains "unknown" → activeUnknownNodeId non-null → State B questioning fires deterministically |
|
||||
| Schema change | NO |
|
||||
| Principal weakness | Model's directional conclusion on the parent is lost to downstream consumers that check parent newValue/status rather than answerMeaning. This is an acceptable trade-off because the alternative (Model D) creates an unhandled edge case, and Model B loses everything. The direction IS preserved in answerMeaning which IS consumed by State A/B selection logic — the only place it matters functionally. |
|
||||
|
||||
---
|
||||
|
||||
## Critical distinction
|
||||
|
||||
**Choice: E — CURRENT REPRESENTATION CANNOT PRESERVE DIRECTION SAFELY**
|
||||
|
||||
Why: On an `unknown` decision node, a non-null `newValue` (e.g., "launch this year") is semantically contradictory per Checkpoint 6 (Choice C). The schema accepts it technically, but no downstream code path was designed for unknown-status nodes with values. Propagation ignores them; completeness logic misinterprets them. Direction CAN survive in `answerMeaning.userSupportedMeaning` and `possibleInference` — these fields exist precisely for this purpose. However, they do not constitute "direction on the parent node." The question "can direction be preserved safely?" has answer NO when it means "preserved as a graph-update on the decision node itself." Direction can only survive in the answerMeaning text fields, which is PARTIAL preservation (textual, not structural).
|
||||
|
||||
**Practical consequence:** Model E (normalise terminal update away, preserve other evidence) is the best available option because:
|
||||
1. It prevents premature closure deterministically
|
||||
2. Direction survives in answerMeaning (the canonical channel for carrying user intent independent of status)
|
||||
3. State B remains reachable
|
||||
4. No schema change needed
|
||||
5. The loss of directional structure on the parent is unavoidable without creating an unhandled edge case
|
||||
|
||||
---
|
||||
|
||||
## Minimum corrective boundary
|
||||
|
||||
**Choice: C — prompt clarification + dedicated pre-validation closure-ownership normalisation**
|
||||
|
||||
Why:
|
||||
1. Explicit confirmation remains authoritative (deterministic enforcement)
|
||||
2. Customer-factor resolution survives in preserved non-parent proposal updates
|
||||
3. Unrelated proposal work is preserved (Model E approach)
|
||||
4. No retry loop (application proceeds, State B fires naturally)
|
||||
5. State B remains reachable (decision stays "unknown")
|
||||
6. Parent lifecycle remains internally consistent (no hybrid unknown+value states)
|
||||
7. Direction preserved only in answerMeaning where current semantics safely permit it
|
||||
8. No schema change
|
||||
|
||||
**Would explicit confirmation remain authoritative:** YES — the deterministic gate is the only path to closure; stripping model proposals without confirmation preserves its authority.
|
||||
|
||||
**Would customer-factor resolution survive:** YES — those are separate updatedNodes entries that normalization preserves.
|
||||
|
||||
**Would State B remain reachable:** YES — decision stays "unknown" deterministically when confirmation absent.
|
||||
|
||||
**Would retry loops be avoided:** YES — no rejection, just normalisation; application proceeds normally.
|
||||
|
||||
**Would schema remain unchanged:** YES — only code in apply-proposal.js (a new pre-validation step) and prompt-builder.js (Rule 143 reword).
|
||||
|
||||
---
|
||||
|
||||
## Implementation readiness
|
||||
|
||||
**Choice: A — READY FOR BOUNDED IMPLEMENTATION**
|
||||
|
||||
One unresolved question: Should the normalisation function live as a dedicated function between reconciliation and validation (Boundary B), or should it extend the existing deterministic closure gate (Boundary D)? Boundary D is more tightly coupled to the existing gate logic but less clear in separation of concerns. Boundary B is cleaner architecturally but adds a pipeline step. **Recommendation: Boundary B** — `reconcileDecisionClosureOwnership(graph, proposal, answer)` called between reconciliation and validation, after line 3549 and before line 3552.
|
||||
|
||||
Smallest implementation boundary: One new function in apply-proposal.js (or a dedicated module) + one prompt rule change in prompt-builder.js line 143. No schema changes. No test changes required for this design analysis.
|
||||
Reference in New Issue
Block a user