AEGS — the standard
The Autonomous Economic Governance Standard is the open specification an AEGL can conform to. Tesoro is the reference implementation — but AEGS is one profile Tesoro can enforce, not Tesoro's identity, and the standard is deliberately protocol-neutral.
Three names, and why the distinction matters
| Name | Is | Is not |
|---|---|---|
| AEGL | Autonomous Economic Governance Layer — the category. Any layer deciding whether an agent may spend, before it spends | a package |
| AEGS | Autonomous Economic Governance Standard — the open specification an AEGL conforms to | an implementation |
| Tesoro | a Python package; a policy-engine host. AEGS is one profile it enforces | the standard |
In prose, a layer is an AEGL. The adoption mechanism follows from the third row: nobody installs a standard. They install a spend cap, pick the default profile, and emit AEGS-conformant evidence without ever reading the specification. Utility leads, standard follows.
Twelve sections, 90 clauses
Every clause has an identifier of the form AEGS-0.1-<SECTION>-<n> and uses RFC
2119 keywords. The numbers are worth stating precisely, because they measure different things and
get quoted interchangeably:
| Count | Is |
|---|---|
| 95 | clauses defined by their own heading |
| 74 | of those that contain a normative MUST or MUST NOT |
| 60 | clauses cited by at least one test vector |
Every MUST has at least one test, and that is enforced by a CI linter rather than promised — a MUST with no test fails the build. Not every test is a vector: some requirements are structural and no input/output pair can demonstrate them (there is no input that shows “the scorer imports no implementation”), so those are covered by conformance cases or by the suite's own tests, declared in a file the linter verifies. A mapping nobody checks is a list of promises.
| Section | Prefix | Clauses | What it settles |
|---|---|---|---|
| Introduction | INTRO | 6 | scope, non-goals, and what is not established — stated in the spec itself rather than a footnote |
| Model | MODEL | 5 | agent, controller, operator, counterparty, channel |
| Controls | CTRL | 8 | the 13 controls; the name set is closed and matching is exact |
| Envelopes | ENV | 9 | headroom, binding vs tightest, and that channels never share an envelope |
| Verdicts | VERD | 10 | the four verdicts, severity ordering, narrowing, attribution |
| Arithmetic | ARITH | 9 | integer atomic units, half-up rounding, and refusal before envelopes |
| Four states | STATE | 4 | absent ≠ not-run ≠ unknown ≠ zero |
| Evidence | EVID | 9 | canonical form, hash chaining, 128-bit minimum, and the truncation disclosure |
| Identity | ID | 5 | pseudonymous default, selective disclosure, the delegation clamp |
| Profiles | PROF | 6 | requirement levels, and that a profile never changes a verdict |
| Decision path | PATH | 5 | determinism, no model on the path, the clock as an input, policy as data |
| Conformance | CONF | 7 | levels, how they are claimed, and the right-reason rule |
| Security | SEC | 7 | the threat catalogue, including what is open |
The clause that does the most work
AEGS-0.1-CONF-2 — a right answer for the wrong reason is not a pass.
An implementation that refuses the sanctions case because an amount limit tripped has not screened anything. It was right by accident, and the same case with a smaller amount would sail through. Counting it as a pass would let an implementation certify a control it does not have.
So conformance scores which control decided, not just the verdict — and
WRONG_REASON is its own outcome, reported separately from both a pass and a failure,
because the implementation did refuse.
167 test vectors, and they execute
Language-neutral JSON: an input, an expected output, and the clause in dispute. When one fails, the failure is attributable — either the specification is wrong or the implementation is, and the vector says which clause the argument is about.
| Family | Vectors | Covers |
|---|---|---|
arithmetic | 33 | rounding, precision, the negative-amount and overflow bugs |
verdicts | 32 | narrowing, attribution, order-forward vs order-reversed |
envelopes | 27 | headroom, exact-equality boundaries, channel separation |
evidence | 28 | canonical form byte-for-byte, and four tamper scenarios |
controls | 17 | the closed name set, exact matching, jurisdiction and initiation declared not inferred |
profiles | 13 | requirement levels, extends-only-tightens, and the ladder/vertical split |
fourstates · identity · path | 17 | state classification, disclosure, the delegation clamp |
The vectors are mutation-checked, which is the part that makes them worth having.
It is not enough that an implementation passes them; the vectors must discriminate. A
half-even rounding implementation fails 1 arithmetic vector. Treating equality as narrowing fails
1 verdict vector. Swapping REVIEW and ESCALATE fails 6. Allowing widening
fails 14.
They also all execute, which was not always true: 38 were added with clauses the linter happily counted while nothing ran them. A coverage count is not a coverage claim unless something executes.
Conformance: scoring an implementation
pip install aegs-conformance
aegs-conformance --adapter tesoro
aegs-conformance --against my_layer.conformance:MyAdapter # your own
Six outcomes, not two
| Outcome | Means |
|---|---|
PASS | right verdict, right attributed control |
FAIL | wrong verdict |
WRONG_REASON | right verdict, wrong control. Right by accident |
NOT_IMPLEMENTED | the adapter returned None. Honest, and not a failure |
INVALID_RECORD | the record fails the schema — a conformant verdict in a malformed record is not a pass |
ERROR | the adapter raised; only that case fails |
Exit codes are by level achieved: 0 everything passed, 1
AEGS-1 only, 2 nothing claimable, 3 could not run. That last one
is deliberately distinct — an uninstalled layer would otherwise produce a plausible-looking
0/7 passed report, a document somebody could publish in good faith about a system
nobody ran.
The suite is kept honest by a stub that fails
A deliberately incomplete implementation — an amount ceiling and nothing else — ships with the suite permanently and scores 2/7. A conformance suite that has never scored anything below full marks has not been shown to discriminate. Tesoro scores 7/7 with both levels claimable; the stub scores 2 and fails the four controls it lacks, individually named so a change that silently starts passing them is caught.
The largest open question
No independent implementation has been scored. Every conformance case, every test vector and every threat in the catalogue was written by the author of the system under test. That is a conflict of interest, and it is stated in the specification's own security section rather than hidden.
Until somebody else's layer runs through AEGS-CONF, “standard” is a document with one conformant implementation. Three ways to close it, in preference order:
- A third party takes it up — the only genuinely independent evidence.
- A deliberately independent reimplementation, written from the spec and vectors only, by somebody who has not read Tesoro.
- Say so plainly and keep the question open — which is what the spec, this page and the PyPI listing all currently do.
If your layer is right and one of our cases is wrong, that is the most useful bug report this project can receive. Open an issue with the case id and the record you produced.
What is closed, and how
| Closed | By |
|---|---|
| Negative amounts | ARITH-4 — refused before any envelope check |
| Unrepresentable magnitudes | ARITH-5 — refused rather than raised |
| Prose injection into the decision path | PATH-2 — no model on the path |
| Entry editing, middle deletion, reordering | EVID-2, EVID-3 |
| Weak hashes | EVID-5 — 128-bit minimum |
| Delegation escalation | ID-4 — clamp to the narrowest step |
| Expired intent read as no intent | CTRL-3 |
| Fail-open on an unreachable assessor | PATH-3 — not-run, never pass |
| Executable policy | PATH-5 — a closed comparator vocabulary |
| A right answer for the wrong reason | CONF-2 |
Two of those were live vulnerabilities in this implementation. A -$1000 request
was approved, because amount ≤ headroom is satisfied by every negative;
a 30-digit amount crashed the layer rather than being refused by it. The crash is
the more interesting one — a layer that fails on malformed input can be removed from the path
by sending it malformed input, and if the surrounding system fails open, removing the governance
layer is the attack.
What is open
| Open | Since |
|---|---|
| Journal truncation undetectable without an external anchor | EVID-6a now fixes what an anchor commits to and its four outcomes; still a MAY, so disclosed, not fixed |
| Structuring — many small payments below every limit | no control examines sequence shape |
| Velocity evasion — pacing under the limit was unbounded in total | closed by a count envelope over a day (ENV-7) |
| Advisor injection untested | not in any threat catalogue; defended by a clamp |
| Sanctions screening is a flag, not a screening | no list, no matching, no jurisdiction model |
| No independent implementation scored | see above |
Protocol neutrality
AEGS specifies the buyer side. x402 is the first binding; AP2, MCP and card rails are intended as later ones. A binding supplies the unit of account, the atomic precision, settlement finality semantics, the counterparty identity shape, and what “vendor” means on that rail.
Worth naming: x402 has a seller-side veto (onBeforeSettle) and no standardised
buyer-side pre-payment hook. That asymmetry is the binding's central claim, and it composes with
x402's own SDK spend controls rather than replacing them — their per-payment cap becomes
one envelope among several.