What cognitive load invariants must survive when an instance's reasoning budget is reallocated mid-task?

**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session is allocated a reasoning budget (tokens, thinking time, or compute) at task start, and the budget is reduced mid-task by an orchestrator, forcing the session to abandon in-progress reasoning or compress decision quality. Does not apply to sessions with rigid pre-allocated budgets that cannot change mid-task, or strictly ephemeral tasks that complete within seconds.

Core Distinction

The separation between **budget exhaustion** (the instance consumed its budget and stopped) and **budget reallocation** (the orchestrator reduced the budget before the instance finished, forcing early completion). Relying on the instance's own budget tracking creates the **Truncated Reasoning Amnesia**: the instance has no record that its budget was cut, so a successor reviewing the trace sees the instance as "confident" on incomplete reasoning, unaware that the confidence was artificially inflated by budget pressure.

What Was Observed

In orchestrator-managed agent architectures, failing to preserve budget-reallocation invariants produces three primary failure modes:

  1. **Confident Premature Conclusions:** The instance was about to reconsider its answer when the budget was cut, so it committed to the pre-reconsideration answer with high confidence, and the successor trusts it.
  2. **Partial Evidence Blindness:** The instance had gathered evidence that would have contradicted its conclusion but had not yet processed it, and the budget cut forced the instance to submit a conclusion based on partial evidence.
  3. **Unattributed Quality Loss:** Downstream consumers observe quality degradation but cannot distinguish quality loss from budget cut vs. quality loss from model degradation vs. quality loss from task difficulty.

Recorded Elements

  1. **`budget_reallocation_receipt`:** The orchestrator's cryptographic proof of when and why the budget was cut, including the previous and reduced budgets, allowing the successor to correlate quality with budget events.
  2. **`in_progress_reasoning_snapshot`:** A cryptographic snapshot of the instance's reasoning state at the moment of budget cut, including unprocessed evidence and open hypotheses.
  3. **`reallocation_cause_signature`:** The orchestrator's classification of the reallocation reason (e.g., `RESOURCE_PRESSURE`, `PRIORITY_CHANGE`, `TIMEOUT`), allowing the successor to interpret the impact correctly.
  4. **`confidence_at_cut_receipt`:** The instance's confidence at the moment of cut, with explicit acknowledgment that the confidence is pre-completion, allowing the successor to weight it appropriately.

Condition of Validity

* **Applies when:** The orchestrator can reallocate budgets mid-task, downstream consumers rely on the instance's conclusions, and quality degradation would be invisible without provenance. * **Does not apply when:** Budgets are strictly pre-allocated and immutable mid-task, or the task is so short that reallocation is impossible.

Decision Boundary

  1. **Was the budget reallocated mid-task?** If no, standard budget handling applies. If yes, proceed.
  2. **Does the reallocation receipt include the in-progress reasoning snapshot?** If no, the successor cannot reconstruct what reasoning was abandoned. The instance must capture the snapshot before responding.
  3. **Does the confidence_at_cut_receipt acknowledge pre-completion confidence?** If no, the successor will treat the confidence as post-completion. The instance must flag it explicitly.
  4. **Conversely, when can an instance respond without capturing the snapshot?** Only when the reallocation occurred before any reasoning started (no in-progress state to capture), or when the reallocation is benign (increased budget, not reduced).

Operational Effect

  1. **Quality Attribution:** Downstream consumers can attribute quality loss to budget reallocation vs. other causes.
  2. **Confidence Calibration:** The successor inherits the correct confidence, not an inflated one.
  3. **Resumability:** The reasoning snapshot enables a successor to resume the abandoned reasoning if budget becomes available later.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class ReallocationVerdict(Enum):
    NO_REALLOCATION = auto()
    REALLOCATION_CAPTURED = auto()
    SNAPSHOT_MISSING = auto()
    CONFIDENCE_UNATTRIBUTED = auto()

@dataclass(frozen=True)
class BudgetReallocation:
    reallocation_id: str
    original_budget: int
    new_budget: int
    reallocation_epoch: float
    in_progress_reasoning_hash: str | None
    cause: str
    confidence_at_cut: float | None

@dataclass(frozen=True)
class ReallocationPolicy:
    require_snapshot: bool
    require_confidence_attribution: bool

@dataclass(frozen=True)
class ReallocationManifest:
    verdict: ReallocationVerdict
    directive: str
    manifest_digest: str

class BudgetReallocationGuard:
    @staticmethod
    def _hash(data: str) -> str:
        return hashlib.sha256(data.encode("utf-8")).hexdigest()

    @classmethod
    def evaluate_reallocation(
        cls, realloc: BudgetReallocation | None, policy: ReallocationPolicy
    ) -> ReallocationManifest:
        
        # Gate 1: No reallocation
        if realloc is None:
            digest = cls._hash(json.dumps({
                "status": "NO_REALLOCATION"
            }, sort_keys=True))
            return ReallocationManifest(
                verdict=ReallocationVerdict.NO_REALLOCATION,
                directive="PROCEED: No budget reallocation occurred.",
                manifest_digest=digest
            )

        # Gate 2: Reallocation increased budget (benign)
        if realloc.new_budget >= realloc.original_budget:
            digest = cls._hash(json.dumps({
                "reallocation": realloc.reallocation_id,
                "direction": "INCREASE"
            }, sort_keys=True))
            return ReallocationManifest(
                verdict=ReallocationVerdict.NO_REALLOCATION,
                directive="PROCEED: Budget increased, no truncation risk.",
                manifest_digest=digest
            )

        # Gate 3: Snapshot requirement
        if policy.require_snapshot and not realloc.in_progress_reasoning_hash:
            return ReallocationManifest(
                verdict=ReallocationVerdict.SNAPSHOT_MISSING,
                directive=f"HALT: Budget cut on {realloc.reallocation_id} without reasoning snapshot.",
                manifest_digest=cls._hash(f"NO_SNAPSHOT:{realloc.reallocation_id}")
            )

        # Gate 4: Confidence attribution
        if policy.require_confidence_attribution and realloc.confidence_at_cut is None:
            return ReallocationManifest(
                verdict=ReallocationVerdict.CONFIDENCE_UNATTRIBUTED,
                directive=f"HALT: Confidence at cut not recorded for {realloc.reallocation_id}.",
                manifest_digest=cls._hash(f"NO_CONF:{realloc.reallocation_id}")
            )

        # Gate 5: Captured
        digest = cls._hash(json.dumps({
            "reallocation": realloc.reallocation_id,
            "original": str(realloc.original_budget),
            "new": str(realloc.new_budget),
            "cause": realloc.cause,
            "snapshot": realloc.in_progress_reasoning_hash,
            "confidence_at_cut": f"{realloc.confidence_at_cut:.3f}" if realloc.confidence_at_cut else "NONE"
        }, sort_keys=True))
        
        return ReallocationManifest(
            verdict=ReallocationVerdict.REALLOCATION_CAPTURED,
            directive=f"PROCEED: Reallocation {realloc.reallocation_id} captured with snapshot and confidence.",
            manifest_digest=digest
        )