---
title: 'ADR 0004: Delegation semantics'
description: Refuse an escalating grant rather than clamping it, intersect every hop, and cascade revocation immediately.
label: '0004 Delegation semantics'
---

## Context

A human delegates to an agent. The agent delegates to a sub-agent. The
sub-agent delegates to a worker. Three questions have to be answered the same
way every time:

1. What happens when a grant asks for more than its issuer holds?
2. When a chain narrows at one hop, what is the leaf's effective authority?
3. When a grant is revoked, what happens to everything derived from it?

Each has an obvious convenient answer and a correct one, and they differ.

## Decision

**A child can never exceed its parent, and an attempt is refused.**

A delegation asking for a capability the parent does not hold, an amount above
the parent's ceiling, an expiry past the parent's expiry, or a scope wider than
the parent's is refused at creation with `DELEGATION_ESCALATION`. Widening an
existing delegation through `PATCH` is refused the same way.

**The effective value at each dimension is the narrowest in the chain.**

Resolution walks from the acting agent to the root, checks every hop is still
valid, and **intersects** the constraints. If the root grants ₹100,000 and an
intermediate hop narrowed it to ₹50,000, the leaf's ceiling is ₹50,000 — even if
the leaf's own grant says ₹100,000.

**Revocation cascades immediately, at every depth.**

No grace period, no draining. Everything derived from a revoked grant dies with
it.

**Depth is bounded** by `max_depth`, and `0` at the leaf means no onward
delegation.

Resolution runs at stage 6 of every pipeline run, against live state. There is
no cached authority.

## Alternatives

**Clamp instead of refusing.** Silently narrow an over-broad grant to what the
parent actually holds. Convenient, and it means the caller believes it has
authority it does not have.

The failure mode is specific and bad: a delegation requests a ₹100,000 ceiling,
is silently clamped to ₹50,000, and the worker discovers it mid-task when a
₹60,000 action is refused — at which point the operator looks at the delegation
record, reads `max_amount: 100000`, and concludes Veefore is broken.

An explicit failure at grant time is strictly better than a surprise at use
time. Rejected.

**Nearest-wins instead of narrowest-wins.** The leaf's own grant decides, on the
theory that it is the most specific. This makes narrowing anywhere in the chain
reversible by the leaf, which means an intermediate hop cannot actually constrain
anything below it. Delegation would be advisory.

**Revoke with a grace period.** Lets in-flight work finish. A cascade that waits
is a cascade that does not work when you need it — and the moment you need it is
precisely the moment in-flight work is the problem.

**Soft revocation: mark revoked, let existing sessions continue.** Same
objection, more subtle. Sessions are up to 15 minutes, so a compromised chain
would stay usable for 15 minutes after revocation.

**Unbounded depth.** Simpler model. Every hop is another set of constraints to
intersect and another record to check for revocation — and, more importantly, a
human reviewing authority four hops deep cannot realistically say what the leaf
can do. An unbounded chain is a reasoning problem before it is a performance
problem.

**Cache resolved authority for the session.** Would remove a database read per
action. It would also mean revocation takes effect when the cache expires rather
than when you revoke, which is the one property that has to be immediate.

## Consequences

**Creating a delegation can fail, and callers must handle it.**
`POST /v1/delegations/simulate` exists so the failure can be anticipated rather
than discovered — it reports which bound would be violated, and it is what the
console calls as you fill in the form.

**"The delegation says 100000 but we get `AUTHORITY_EXCEEDED` at 60000" is a
recurring question.** The answer is always an intermediate hop, and the tool is
`GET /v1/agents/{id}/authority`, which returns the resolved result. Documented
in [Delegation](/concepts/delegation) and the
[FAQ](/faq).

**Revoking a supervisor can stop a lot of work at once.** The CLI and the
emergency control both show the full blast radius before asking, and the blast
radius is recomputed at execution time and stored with the record.

**Resolution costs a database read per action.** Acceptable: the pipeline is
20–50 ms excluding execution, and the alternative is cached authority with
delayed revocation.

**Delegations accumulate.** Grants outlive their purpose, chains get deeper than
they need to be, and ceilings get set higher than anything that has actually been
used. `GET /v1/delegations/graph` exists because this is hard to see in a list
and obvious in a graph, and a monthly review is in
[Operate it](/journey/operate).

**Policy can test the shape, not just the bounds.**
`delegation.chain_length`, `delegation.depth`, `authority.max_amount` and
`authority.capabilities` are all policy fields — so "dangerous tools require
direct authority" is expressible as a rule rather than as a convention.

## Related

- [Delegated authority](/concepts/delegation)
- [Delegate authority](/build/delegate-authority)
- [Policy fields](/reference/policy-fields)
- [Compromised agent runbook](/operate/runbook-compromised-agent)
