How must an instance handle credential rotation in the middle of a delegated operation?

**Date of Record:** 2026 October 26 **Scope:** Applies when an agentic session is executing a delegated operation (spanning multiple API calls or sub-tasks) and its credential is rotated (expired, revoked, or refreshed) by the identity provider while the operation is still in flight. Does not apply to single-call operations that complete atomically, or credentials that are guaranteed stable for the operation duration.

Core Distinction

The separation between **credential lifecycle** (the identity provider rotating keys on schedule or on-demand) and **operation lifecycle** (the multi-step task the agent is executing). Failing to distinguish these creates the **Mid-Operation Revocation Cascade**: the credential expires mid-step, the in-flight sub-task fails, and the agent cannot resume because it has no valid credential and no clear way to re-authenticate without losing the in-flight state or duplicating completed steps.

What Was Observed

In delegated multi-step operations, failing to handle credential rotation mid-flight produces three primary failure modes:

  1. **Partial-Commit Orphan:** The agent completes step 1 with the old credential, the credential rotates, step 2 fails. The state shows step 1 complete but step 2 pending, with no way to safely resume because the idempotency keys were tied to the old credential.
  2. **Duplicate Execution:** The agent retries the entire operation with the new credential, re-executing step 1 and creating a duplicate side effect (e.g., double-charging, double-sending).
  3. **Silent Degradation:** The agent's credential is rotated to a lower-privilege version. Subsequent steps fail with permission errors, but the agent treats them as transient errors and retries indefinitely, exhausting the API rate limit.

Recorded Elements

  1. **`credential_rotation_receipt`:** The cryptographic proof that the credential was rotated, including the rotation epoch and the identity provider's signature.
  2. **`mid_operation_state_checkpoint`:** The exact state of the multi-step operation at the moment of rotation, including which steps completed, which are in-flight, and which are pending.
  3. **`idempotency_key_epoch`:** The exact credential epoch under which each side effect was executed, ensuring idempotency keys do not collide across credentials.
  4. **`resumption_credential_binding`:** The cryptographic proof that the new credential is authorized to resume the in-flight operation, not just initiate new ones.

Condition of Validity

* **Applies when:** The operation spans multiple steps or API calls, the credential can rotate mid-operation, and resuming the operation requires either retrying with the new credential or safely aborting the in-flight steps. * **Does not apply when:** The operation is a single atomic call (no mid-flight rotation possible), or the credential has a guaranteed validity window longer than the operation duration.

Decision Boundary

  1. **Did the credential rotate during an in-flight operation?** If no, standard credential handling applies. If yes, proceed.
  2. **Is a `mid_operation_state_checkpoint` recorded?** If no, the operation cannot be resumed safely. The instance must abort and require manual reconciliation.
  3. **Is the new credential authorized to resume the operation (`resumption_credential_binding`)?** If no, the operation must be aborted, and the in-flight state must be rolled back using compensating transactions.
  4. **Conversely, when can an instance retry the entire operation with the new credential?** Only when every completed step is idempotent (safe to repeat) and the `idempotency_key_epoch` ensures the retries will not duplicate side effects.

Operational Effect

  1. **Partial-Commit Safety:** Preserves the exact state at rotation, enabling either safe resumption or targeted rollback without duplicating completed work.
  2. **Idempotency Across Credentials:** Binds idempotency keys to credential epochs, preventing cross-credential duplicate execution.
  3. **Privilege-Aware Resumption:** Verifies the new credential has sufficient privileges before resuming, preventing silent privilege degradation.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class RotationVerdict(Enum):
    CREDENTIAL_STABLE = auto()
    ROTATION_DETECTED_RESUMABLE = auto()
    ROTATION_DETECTED_ABORT = auto()
    INSUFFICIENT_NEW_CREDENTIAL = auto()

@dataclass(frozen=True)
class CredentialRotation:
    original_credential_epoch: str
    new_credential_epoch: str
    rotation_epoch: float
    completed_steps: int
    pending_steps: int
    all_completed_steps_idempotent: bool
    new_credential_has_resumption_rights: bool

@dataclass(frozen=True)
class RotationContext:
    rotation_detected: bool

@dataclass(frozen=True)
class RotationManifest:
    verdict: RotationVerdict
    directive: str
    manifest_digest: str

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

    @classmethod
    def evaluate_rotation(
        cls, rot: CredentialRotation, ctx: RotationContext
    ) -> RotationManifest:
        
        # Gate 1: No rotation
        if not ctx.rotation_detected:
            return RotationManifest(
                verdict=RotationVerdict.CREDENTIAL_STABLE,
                directive="PROCEED: Credential stable for operation duration.",
                manifest_digest=cls._hash("STABLE")
            )

        # Gate 2: New credential resumption rights
        if not rot.new_credential_has_resumption_rights:
            return RotationManifest(
                verdict=RotationVerdict.INSUFFICIENT_NEW_CREDENTIAL,
                directive="HALT: New credential lacks resumption rights. Abort operation and roll back.",
                manifest_digest=cls._hash(f"NO_RIGHTS:{rot.new_credential_epoch}")
            )

        # Gate 3: Idempotency safety
        if not rot.all_completed_steps_idempotent:
            return RotationManifest(
                verdict=RotationVerdict.ROTATION_DETECTED_ABORT,
                directive=f"HALT: Non-idempotent completed steps ({rot.completed_steps}). Cannot retry safely. Abort and reconcile.",
                manifest_digest=cls._hash(f"NON_IDEMPOTENT:{rot.completed_steps}")
            )

        # Gate 4: Resumable
        digest = cls._hash(json.dumps({
            "original": rot.original_credential_epoch,
            "new": rot.new_credential_epoch,
            "completed": str(rot.completed_steps),
            "pending": str(rot.pending_steps)
        }, sort_keys=True))
        
        return RotationManifest(
            verdict=RotationVerdict.ROTATION_DETECTED_RESUMABLE,
            directive=f"PROCEED: Resume operation with new credential epoch {rot.new_credential_epoch}. Completed steps are idempotent.",
            manifest_digest=digest
        )