Repository navigation
The Four Clause Gate
Marcus Richards edited this page Oct 6, 2026
·
1 revision
Attempt a against permit P is authorized iff:
amount(a) <= remaining(P)
AND merchant(a) IN allowlist(P)
AND now < expiry(P)
AND NOT revoked(P)
remaining(P) = cap(P) − reserved(P) − captured(P)
Four clauses. No discretion. Code: PermitStore._evaluate() in permit/permit.py.
-
Amount guard (
_validate_amount). The value must be anint, must not be abool, and must be> 0. Otherwise the result isinvalid_amount.check()writes a BLOCKED receipt and never raises. -
Permit lookup. A missing permit gives
unknown_permit. - Clauses, in this order: revoked → expiry → merchant → amount. The first failure is the reason.
- Lineage gate. For a sub-permit, every ancestor must exist, be unrevoked, and be unexpired. See Delegation and Sub-Permits.
The clauses use effective values after any tighten: the lower cap, the intersected allowlist, the sooner expiry.
eligible() |
check() |
|
|---|---|---|
| Used by |
POST /api/permits/<id>/check, the approval probe |
the spend pipeline |
| Reserves cap | No | Yes, on ALLOWED (adds to reserved_cents, records an auth_id) |
| Writes a receipt | No | Yes: ALLOWED or BLOCKED
|
| Concurrency | — | Re-evaluates under the per-permit lock, so parallel attempts cannot exceed the cap |
| Reason | Meaning |
|---|---|
invalid_amount |
Not a positive int |
unknown_permit |
No such permit id |
revoked |
Permit revoked |
expired / tightened_expiry_passed
|
now >= expiry (granted / tightened) |
merchant_not_allowed |
Merchant not in the effective allowlist |
over_remaining_cap / tightened_cap_exceeded
|
Amount exceeds remaining (granted / tightened cap) |
ancestor_revoked / ancestor_expired / ancestor_missing
|
Lineage gate failed |
The pipeline adds merchant_not_bound, invalid_approval and approval_not_approved. See Spend Pipeline.
- A BLOCKED attempt never reaches PayPal, not even the authorize call.
-
permit/permit.pymust not import any PayPal client (tests/test_permit.py::test_no_paypal_imports_in_permit_module). - All money is integer cents.
/check and /spend reject a non-int or non-positive amount_cents with 400 before the gate runs. POST /api/permits and /delegate coerce cap_cents with int() first. See HTTP API Reference.
Permit · payment authority for AI agents · MIT · Wiki facts verified against commit 9900817 on 2026-10-07 (America/Edmonton). Where this wiki and the code disagree, the code wins.
Concepts
- Overview and Problem
- The Four-Clause Gate
- Spend Pipeline
- Delegation and Sub-Permits
- Principal Approvals
- Tighten-Only Narrowing
- E-Stop and Revocation
- Claim Ledger
- UNKNOWN and Reconcile
Using it
Design and status
Reference