Skip to content

Delegation and Sub Permits

Marcus Richards edited this page Oct 6, 2026 · 1 revision

Delegation and Sub-Permits

A permit holder can carve a sub-permit for another agent. Delegation subdivides spending power. It never adds to it.

Rules (PermitStore.delegate)

Checked in this order. Each failure writes a BLOCKED receipt.

Check Reason
cap_cents is a positive int invalid_amount
Parent exists unknown_parent
Parent not revoked parent_revoked
Parent not expired (effective expiry) parent_expired
Depth ≤ MAX_DELEGATION_DEPTH (8; root = 0) delegation_too_deep
cap_cents ≤ parent's effective remaining over_parent_remaining
Child allowlist ⊆ parent's effective allowlist allowlist_escalation
Child expiry ≤ parent's effective expiry expiry_beyond_parent

On success the carve is reserved on the parent (parent.reserved_cents += cap_cents), and a DELEGATED receipt is written. Siblings cannot oversubscribe the parent.

Money flow

  • Child spend: the child reserves inside its own cap. The parent's books do not change, because the carve already covers it.
  • Child capture: every ancestor moves the amount from reserved to captured (_rollup_capture).
  • Lineage gate: a child spend is blocked if any ancestor is revoked, expired or missing (ancestor_*).

Cascade revoke

flow.revoke_cascade(parent) / POST /api/permits/<id>/revoke-cascade:

  1. Revokes the root (E-STOP receipt) and every descendant (REVOKED_CASCADE).
  2. Voids in-flight holds across the subtree.
  3. Releases unspent carves post-order, children first (CARVE_RELEASED). This is idempotent.

After its carve is released, a child's parent_id is cleared. GET /api/permits/<child> then shows parent_id: null.

⚠️ POST /api/permits/<id>/estop is not a cascade in code. See E-Stop and Revocation.

Notes

  • A new child does not copy the parent's approval threshold. A later tighten on the parent does cascade to children.
  • Concurrency: delegate() racing revoke_subtree() must be serialized by the caller. This is documented in the code.
  • Demos: demo.py beat 4, demo_delegation.py, demo_sla_escrow.py. Tests: tests/test_delegation.py (22).

Clone this wiki locally