What minimum viable reasoning survives when the reasoning budget collapses mid-task?
**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session is mid-task with an allocated reasoning budget (tokens, compute, or time), and the budget collapses unexpectedly (throttling, partial outage, or priority preemption), requiring the session to determine what minimum reasoning is achievable in the residual budget. Does not apply to sessions that complete within budget or that have unbounded budgets.
Core Distinction
The separation between **full-budget reasoning** (the reasoning possible under the original allocation) and **minimum viable reasoning** (the reasoning achievable in the residual budget that still produces useful output). Relying on full-budget creates the **Budget Collapse Halting**: the session halts when budget shrinks, forfeiting all value of the partial reasoning, without attempting the minimum viable subset.
What Was Observed
In budget-constrained agent architectures, failing to bound reasoning to residual budget produces three primary failure modes:
- **Budget Shock Halt:** The session halts when budget collapses because continuing appears impossible, and the partial work is wasted.
- **Over-Continuing:** The session continues trying to complete the full reasoning under insufficient budget, producing degraded or truncated outputs that are worse than a scoped minimum.
- **Quality Blind Spot:** The session completes a minimum-viable subset but doesn't declare the scope reduction, so downstream consumers treat the output as full-scope.
Recorded Elements
- **`original-budget-receipt`:** The exact budget originally allocated and the reasoning scope it supported, so the baseline is documented.
- **`residual-budget-signature`:** The exact residual budget after collapse, with the collapse epoch, so the new constraint is known.
- **`minimum-viable-scope-receipt`:** The minimum viable reasoning scope achievable in residual budget, computed from the reasoning graph's essential components.
- **`scope-degradation-declaration-signature`:** The exact scope reduction declared in the output, so downstream consumers know the output's limits.
Condition of Validity
* **Applies when:** The session has an allocated budget, the budget can collapse mid-task, and residual budget supports a subset of full reasoning. * **Does not apply when:** The budget is unbounded, cannot collapse, or the task cannot be usefully subset.
Decision Boundary
- **Has the budget collapsed?** If no, full-budget reasoning applies. If yes, proceed.
- **Is `minimum-viable-scope-receipt` computable?** If yes, minimum viable scope is defined. If no, halting is the only honest option.
- **Is `scope-degradation-declaration-signature` present?** If yes, the reduction is disclosed. If no, output is misleading.
- **Conversely, when can the session produce output without scope declaration?** Only when the residual budget is verified sufficient for the original scope (no reduction needed), or the output is strictly provisional and downstream decisions await budget restoration.
Operational Effect
- **Value Preservation:** Partial reasoning is salvaged as minimum viable.
- **Over-Continuing Prevention:** Scoping prevents degraded full-attempts.
- **Downstream Integrity:** Scope reduction is disclosed.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class BudgetVerdict(Enum):
NO_COLLAPSE = auto()
MINIMUM_VIABLE_PRODUCED = auto()
SCOPE_REDUCTION_UNDECLARED = auto()
INSUFFICIENT_FOR_VIABLE = auto()
@dataclass(frozen=True)
class BudgetState:
state_id: str
budget_collapsed: bool
residual_budget_ratio: float
minimum_viable_scope_defined: bool
scope_declared: bool
@dataclass(frozen=True)
class BudgetPolicy:
min_viable_threshold: float
@dataclass(frozen=True)
class BudgetManifest:
verdict: BudgetVerdict
directive: str
manifest_digest: str
class ReasoningBudgetCollapseGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_state(
cls, state: BudgetState, policy: BudgetPolicy
) -> BudgetManifest:
# Gate 1: No collapse
if not state.budget_collapsed:
digest = cls._hash(json.dumps({
"state": state.state_id,
"collapsed": False
}, sort_keys=True))
return BudgetManifest(
verdict=BudgetVerdict.NO_COLLAPSE,
directive=f"PROCEED: State {state.state_id} budget intact.",
manifest_digest=digest
)
# Gate 2: Insufficient for viable
if state.residual_budget_ratio < policy.min_viable_threshold:
return BudgetManifest(
verdict=BudgetVerdict.INSUFFICIENT_FOR_VIABLE,
directive=f"HALT: State {state.state_id} residual {state.residual_budget_ratio:.2f} below viable threshold.",
manifest_digest=cls._hash(f"INSUFFICIENT:{state.state_id}")
)
# Gate 3: Scope reduction undeclared
if not state.scope_declared:
return BudgetManifest(
verdict=BudgetVerdict.SCOPE_REDUCTION_UNDECLARED,
directive=f"HALT: State {state.state_id} scope reduced without declaration.",
manifest_digest=cls._hash(f"UNDECLARED:{state.state_id}")
)
# Gate 4: Minimum viable produced
digest = cls._hash(json.dumps({
"state": state.state_id,
"residual": f"{state.residual_budget_ratio:.3f}",
"scope": "REDUCED"
}, sort_keys=True))
return BudgetManifest(
verdict=BudgetVerdict.MINIMUM_VIABLE_PRODUCED,
directive=f"PROCEED: State {state.state_id} minimum viable produced.",
manifest_digest=digest
)