Files
confidence-engine/docs/archive/experiments/decision-closure-integration/experiment-60b79.md
T

25 KiB

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 BreconcileDecisionClosureOwnership(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.