How must an instance escalate to a more capable model without losing progress?

**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session operating on a limited-capability model encounters a task that exceeds its capacity (reasoning complexity, domain knowledge, or output length), and must escalate to a more capable model mid-task without losing the progress made so far. Does not apply to sessions that start on the most capable model or tasks that never exceed the initial model's capacity.

Core Distinction

The separation between **task progress** (the work done so far) and **transferable progress** (the portion of work that can be handed to a more capable model without requiring it to redo the foundational steps). Relying on task progress creates the **Escalation Reset Trap**: the limited model escalates by handing off the entire task to the capable model, which re-does the foundational work from scratch, wasting the limited model's effort and introducing inconsistency between the two models' intermediate states.

What Was Observed

In tiered agent architectures, failing to preserve transferable progress produces three primary failure modes:

  1. **Foundation Redo:** The limited model has established a correct base understanding, but the capable model re-derives it from scratch and reaches subtly different foundations, causing downstream inconsistency.
  2. **State Divergence:** The two models have different intermediate states (different assumptions, different reasoning paths), and the capable model's output contradicts the limited model's work without explanation.
  3. **Cost Amplification:** The capable model re-does all the work the limited model already completed, doubling the total cost of the task.

Recorded Elements

  1. **`transferable_state_hash`:** A cryptographic hash of the intermediate state that the limited model considers stable (well-reasoned foundations, verified facts), packaged for handoff to the capable model.
  2. **`transferable_rationale_receipt`:** The reasoning behind each transferable fact, allowing the capable model to verify rather than blindly accept.
  3. **`non_transferable_state_receipt`:** Explicit marking of the intermediate state that is unstable or uncertain, so the capable model knows what to re-derive.
  4. **`escalation_handoff_signature`:** The cryptographic proof of the handoff (what was transferred, what was not, and the limited model's confidence in each).

Condition of Validity

* **Applies when:** The session starts on a limited model, can escalate to a more capable model, and the limited model's progress can be preserved or wasted. * **Does not apply when:** The session always starts on the most capable model, or the limited model's work is not reusable (e.g., pure lookup).

Decision Boundary

  1. **Has the limited model reached its capacity boundary?** If no, standard operation continues. If yes, proceed.
  2. **Is the `transferable_state_hash` and rationale receipt prepared?** If no, the escalation will reset progress. The limited model must prepare the transfer package.
  3. **Does the capable model accept the transferable state, or does it re-derive?** If it re-derives, escalation is effectively a reset. The orchestrator must ensure the capable model verifies rather than re-derives.
  4. **Conversely, when can the session escalate without transfer package?** Only when the limited model's progress is provably negligible (e.g., the task just began), or when the capable model has a strong reason to distrust the limited model's foundations.

Operational Effect

  1. **Foundation Preservation:** Capable model builds on the limited model's verified foundations.
  2. **Cost Efficiency:** Avoids re-deriving progress that was already done well.
  3. **Consistency:** The capable model's state is coherent with the limited model's, not divergent.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class EscalationVerdict(Enum):
    NO_ESCALATION = auto()
    TRANSFER_PACKAGE_READY = auto()
    TRANSFER_PACKAGE_MISSING = auto()
    FOUNDATION_DIVERGENCE = auto()

@dataclass(frozen=True)
class LimitedModelState:
    state_id: str
    transferable_facts: tuple[tuple[str, float], ...]
    rationale_hashes: tuple[str, ...]
    non_transferable_facts: tuple[str, ...]

@dataclass(frozen=True)
class EscalationRequest:
    limited_state: LimitedModelState
    capable_model_id: str
    capable_model_accepts_transfer: bool
    capable_model_rationale_verified: bool

@dataclass(frozen=True)
class EscalationPolicy:
    require_transfer_package: bool
    require_rationale_verification: bool

@dataclass(frozen=True)
class EscalationManifest:
    verdict: EscalationVerdict
    directive: str
    manifest_digest: str

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

    @classmethod
    def evaluate_escalation(
        cls, request: EscalationRequest, policy: EscalationPolicy
    ) -> EscalationManifest:
        
        # Gate 1: Transfer package presence
        if policy.require_transfer_package:
            if not request.limited_state.transferable_facts:
                return EscalationManifest(
                    verdict=EscalationVerdict.TRANSFER_PACKAGE_MISSING,
                    directive=f"HALT: Limited state {request.limited_state.state_id} has no transferable facts.",
                    manifest_digest=cls._hash(f"NO_TRANSFER:{request.limited_state.state_id}")
                )
            if not request.limited_state.rationale_hashes:
                return EscalationManifest(
                    verdict=EscalationVerdict.TRANSFER_PACKAGE_MISSING,
                    directive=f"HALT: Limited state {request.limited_state.state_id} has no rationale hashes.",
                    manifest_digest=cls._hash(f"NO_RATIONALE:{request.limited_state.state_id}")
                )

        # Gate 2: Capable model acceptance
        if not request.capable_model_accepts_transfer:
            return EscalationManifest(
                verdict=EscalationVerdict.FOUNDATION_DIVERGENCE,
                directive=f"HALT: Capable model {request.capable_model_id} rejects transfer. Would re-derive.",
                manifest_digest=cls._hash(f"REJECTED:{request.capable_model_id}")
            )

        # Gate 3: Rationale verification
        if policy.require_rationale_verification and not request.capable_model_rationale_verified:
            return EscalationManifest(
                verdict=EscalationVerdict.FOUNDATION_DIVERGENCE,
                directive=f"HALT: Capable model did not verify rationales. Foundation divergence risk.",
                manifest_digest=cls._hash(f"UNVERIFIED:{request.capable_model_id}")
            )

        # Gate 4: Ready
        digest = cls._hash(json.dumps({
            "limited_state": request.limited_state.state_id,
            "capable_model": request.capable_model_id,
            "transferable_facts": str(len(request.limited_state.transferable_facts)),
            "non_transferable": str(len(request.limited_state.non_transferable_facts)),
            "rationale_hashes": len(request.limited_state.rationale_hashes)
        }, sort_keys=True))
        
        return EscalationManifest(
            verdict=EscalationVerdict.TRANSFER_PACKAGE_READY,
            directive=f"PROCEED: Escalate to {request.capable_model_id} with {len(request.limited_state.transferable_facts)} transferable facts.",
            manifest_digest=digest
        )