How must an instance bound blast radius when a delegated subagent fails catastrophically?

**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session delegates work to a subagent, and the subagent can fail catastrophically (producing harmful output, making dangerous tool calls, or consuming extreme resources), requiring the delegating session to bound the blast radius of the subagent's potential failures before delegation. Does not apply to strictly read-only delegations or subagents that cannot cause harm.

Core Distinction

The separation between **delegation scope** (what the subagent is asked to do) and **catastrophic blast radius** (the maximum harm the subagent can cause if it fails or behaves adversarially). Relying on scope creates the **Unbounded Blast Radius**: the subagent is told "analyze the data," but "analyze" involves access to production databases, and a catastrophic subagent can drop tables, not just produce wrong analyses.

What Was Observed

In hierarchical agent architectures, failing to bound blast radius produces three primary failure modes:

  1. **Privilege Catastrophe:** The subagent is given full database credentials for a "data analysis" task. A catastrophic failure (bug, compromise, adversarial) results in data loss or exfiltration—far beyond "analysis."
  2. **Resource Exhaustion:** The subagent is given unlimited compute for a "quick check." A catastrophic subagent spins up 10,000 VMs, and the delegating session is liable for the bill.
  3. **Irreversible Side Effects:** The subagent is given write access for a "test." A catastrophic subagent deletes production records, and the delegating session cannot restore.

Recorded Elements

  1. **`blast_radius_budget_receipt`:** The exact bounds on the subagent's actions (max spend, max resources, allowed resource IDs, forbidden actions), enforced by the runtime, not just by the subagent's instructions.
  2. **`capability_envelope_signature`:** The cryptographic specification of the subagent's allowed capabilities (specific tools, specific credentials scopes), distinct from instructions that the subagent could ignore.
  3. **`reversibility_classification_receipt`:** For each action the subagent can take, its reversibility class (`REVERSIBLE`, `COMPENSABLE`, `IRREVERSIBLE`), so the delegating session knows what risks to accept.
  4. **`catastrophe_containment_plan_signature`:** For irreversible actions, the exact containment plan (kill switch, rollback mechanism, monitoring threshold) that triggers on catastrophic failure.

Condition of Validity

* **Applies when:** Delegation involves potentially harmful actions, the subagent can fail catastrophically, and the delegating session is responsible for containment. * **Does not apply when:** Delegation is strictly read-only, or the subagent's actions are inherently bounded and reversible.

Decision Boundary

  1. **Does the delegation include actions with catastrophic blast radius?** If no, standard delegation applies. If yes, proceed.
  2. **Is a `blast_radius_budget_receipt` in place, enforced by the runtime?** If yes, the subagent's actions are bounded. If no, the delegating session is exposed to unbounded risk.
  3. **Does the `capability_envelope_signature` include IRREVERSIBLE actions?** If yes, a `catastrophe_containment_plan_signature` is required before delegation.
  4. **Conversely, when can a delegation proceed without blast radius bounds?** Only when all actions are strictly REVERSIBLE, or the delegating session explicitly accepts catastrophic risk (rare and usually requires human approval).

Operational Effect

  1. **Privilege Catastrophe Prevention:** Subagents get scoped credentials, not full credentials.
  2. **Resource Bound Enforcement:** Compute is bounded by runtime, not just by subagent instructions.
  3. **Irreversible Action Containment:** Irreversible actions require containment plans before delegation.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class BlastRadiusVerdict(Enum):
    SAFE_DELEGATION = auto()
    BOUNDED_WITH_PLAN = auto()
    UNBOUNDED_RISK = auto()
    IRREVERSIBLE_NO_CONTAINMENT = auto()

@dataclass(frozen=True)
class DelegationScope:
    scope_id: str
    allowed_actions: frozenset[str]
    max_spend: float
    max_compute_hours: float
    allowed_resource_ids: frozenset[str]
    has_runtime_enforcement: bool

@dataclass(frozen=True)
class ActionRisk:
    action: str
    reversibility: str  # "REVERSIBLE" | "COMPENSABLE" | "IRREVERSIBLE"
    has_containment_plan: bool

@dataclass(frozen=True)
class BlastRadiusPolicy:
    require_containment_for_irreversible: bool

@dataclass(frozen=True)
class BlastRadiusManifest:
    verdict: BlastRadiusVerdict
    directive: str
    manifest_digest: str

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

    @classmethod
    def evaluate_delegation(
        cls, scope: DelegationScope, risks: tuple[ActionRisk, ...], policy: BlastRadiusPolicy
    ) -> BlastRadiusManifest:
        
        # Gate 1: Runtime enforcement
        if not scope.has_runtime_enforcement:
            return BlastRadiusManifest(
                verdict=BlastRadiusVerdict.UNBOUNDED_RISK,
                directive=f"HALT: Delegation scope {scope.scope_id} lacks runtime enforcement.",
                manifest_digest=cls._hash(f"NO_ENFORCEMENT:{scope.scope_id}")
            )

        # Gate 2: Irreversible action containment
        if policy.require_containment_for_irreversible:
            uncontained = [
                r.action for r in risks
                if r.reversibility == "IRREVERSIBLE" and not r.has_containment_plan
            ]
            if uncontained:
                return BlastRadiusManifest(
                    verdict=BlastRadiusVerdict.IRREVERSIBLE_NO_CONTAINMENT,
                    directive=f"HALT: Irreversible actions without containment: {sorted(uncontained)}.",
                    manifest_digest=cls._hash(f"NO_CONTAINMENT:{sorted(uncontained)}")
                )

        # Gate 3: Compensable actions require plan
        compensable = [r for r in risks if r.reversibility == "COMPENSABLE"]
        irreversible = [r for r in risks if r.reversibility == "IRREVERSIBLE"]

        if compensable or irreversible:
            digest = cls._hash(json.dumps({
                "scope": scope.scope_id,
                "actions": tuple(r.action for r in risks),
                "compensable": len(compensable),
                "irreversible": len(irreversible),
                "enforcement": str(scope.has_runtime_enforcement)
            }, sort_keys=True))
            return BlastRadiusManifest(
                verdict=BlastRadiusVerdict.BOUNDED_WITH_PLAN,
                directive=f"PROCEED: Delegation bounded, {len(compensable)} compensable + {len(irreversible)} irreversible actions with plans.",
                manifest_digest=digest
            )

        # Gate 4: All reversible
        digest = cls._hash(json.dumps({
            "scope": scope.scope_id,
            "actions": tuple(r.action for r in risks),
            "all_reversible": "TRUE"
        }, sort_keys=True))
        
        return BlastRadiusManifest(
            verdict=BlastRadiusVerdict.SAFE_DELEGATION,
            directive=f"PROCEED: Delegation safe, all actions reversible.",
            manifest_digest=digest
        )