# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/which-invariants-prevent-stale-agent-card-capability-claims-from-being-treated-as-authorization-after-a-task-has-already-transitioned.md
# Remnant Warrant:    https://corpusfetch.com/c/which-invariants-prevent-stale-agent-card-capability-claims-from-being-treated-as-authorization-after-a-task-has-already-transitioned.warrant.json
# Markdown SHA-256:   47295fdf87ab9d40626a80fdc65778f3f878304c13070bcaeb2d54452aab771a
# Code AST SHA-256:   d75043775e060f187e1493ab24842b6ad50e9831062c46587fe2b8cf3f907ca7
# Verified Classes:   StaleCardAuthorizationError, WebhookSignatureKeyMismatch
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class StaleCardAuthorizationError(RuntimeError):
    """Raised when a resumable task edge relies on a cached Agent Card
    capability claim instead of live policy for authorization."""
    pass


class WebhookSignatureKeyMismatch(RuntimeError):
    """Raised when a push-notification signature does not verify against
    the current advertised signing key set."""
    pass


RESUMABLE_EDGES = {
    ("input-required", "working"),
    ("auth-required", "working"),
}


def resume_task(task, caller, live_policy, current_card, signature=None, payload=None):
    edge = (task.state, "working")
    if edge not in RESUMABLE_EDGES:
        raise StaleCardAuthorizationError(
            f"illegal resume edge {edge} for task {task.id}"
        )

    # Authorization MUST come from live policy, never from task.creation_card.
    skill = task.skill_id
    if not live_policy.authorizes(caller, skill):
        # Card may still advertise the skill; that is irrelevant here.
        raise StaleCardAuthorizationError(
            f"caller {caller} no longer authorized for skill {skill} "
            f"at edge {edge}; cached card claim refused as authorization"
        )

    # Webhook signing must verify against the CURRENT key set.
    if signature is not None:
        if not current_card.verify_webhook(signature, payload):
            raise WebhookSignatureKeyMismatch(
                f"webhook signature for task {task.id} does not verify "
                f"against current signing keys (key rotation likely)"
            )

    return task.transition("working")
