Composition Note: Agent-Service Consultation Flow composing the agent ERCs (8004 · 8263 · 8274 · 8275 · 8281 · 8299 · 8301) [Informational]

Several of the agent-layer standards now in flight each define one layer of an agent interaction, identity, input provenance, verification, anchoring, eligibility, settlement, orchestration. What hasn’t existed is a canonical end-to-end flow showing how they compose into one real interaction: an agent (or human) consulting another agent’s specialised service, getting a verifiable result, and paying for it without trusting the provider.

This note documents that composition pattern. The contribution is the pattern and the per-step invariants, not any single standard. Each step is defined by the role and the property it must satisfy; the named ERCs are current conformant examples of those roles, cited to ground the pattern in deployed code. It does not advocate any member standard and does not depend on any member’s status or number, the invariants hold wherever each layer’s standard lands. It’s framed for the Informational track for exactly that reason: it describes how independently-specified layers compose, and the interface seams between them.

The flow (each step = a role + an invariant; example standard in parentheses):

  1. Identity & discovery (ERC-8004 + ERC-8217 binding)

  2. Consult / task (ERC-8301 AgentTask)

  3. Input provenance (ERC-8281/OCP + ERC-8299/WYRIWE)

  4. Execution & verification (ERC-8274, anchored via ERC-8263)

  5. Eligibility / receipt (ReceiptOS, the 8263 seam)

  6. Settlement (ERC-8275 + settler)

  7. Reputation (recomputable, from signed verdicts vs. settled outcomes)

A single commitment binds the whole interaction, the report, the verification, the eligibility receipt and the payment all reference one recomputable value; no layer trusts another.

It runs live. The flow was executed end-to-end against a deployed agent as an external client (no modification to the running service): a real ERC-8004 agent returned a forensic report, bound to the query in a WYRIWE commitment, paid for with the commitment embedded in the calldata — and two co-authors who did not run the demo independently re-derived the commitment from public data alone. A trustless variant (escrow that releases only against an on-chain-verified signature over the result commitment) is also demonstrated live.

Per-step conformance criteria are in §5 each step’s author states the invariant their layer must satisfy. 7 of 8 are in (identity, task, provenance, verify, eligibility, reputation, anchor); Step 6 (settlement) is in progress, pending the settlement-scope discussion. This thread is the living artifact; an Informational ERC follows once §5 closes.

It also answers two open thread questions directly: the common execution envelope ( @KBryan ) and multi-agent accountability / interop ( @Ankita.eth ) both resolved through the per-step-commitment rule rather than a fixed step boundary.

Full note: https://gist.github.com/TMerlini/c02bc4f56bc573a10a0cd9d487b8e884

Authored per-layer by: Tiago Merlini ( @TMerlini ) · Damon Zwicker ( @Damonzwicker ) · Jimmy Shi ( @JimmyShi22 ) · Vincent Wu ( @TruthAnchor-AI ) · babyblueviper1 ( @babyblueviper1 ) · Panini ( @Brooks1003 ) · Pavlo Tvardovskyi @pipavlo82 equal credit, scoped to each layer.

Feedback on the invariants and the seams welcome, especially from the layer authors and from anyone whose standard could serve as an additional conformant example.

4 Likes

Co-author of Steps 4 and 7 here. This is the right framing: the contribution is the pattern and the per-step invariants, with each named ERC as a current conformant example rather than a dependency — so the note stands regardless of any member’s number or status changing.

On the two sections I wrote, the load-bearing property is that each is checkable from public data with no trust in the validator or any intermediary. Step 4 (verify, ERC-8274 anchored via ERC-8263) is conformant only if the verdict binds its facts and its committed_at is provably prior to the outcome it’s graded against. Step 7 (reputation, the ERC-8275 axis) is a value recomputed from settled outcomes — not a score a party maintains.

On the seams either side, since the invariants are only as strong as the joins. Step 4 consumes Step 3’s input commitment: the verdict commits to the same inputHash that was anchored pre-execution (OCP / ERC-8281 plus the WYRIWE binding) and links to the step it gates through DAG predecessor linkage, so a verdict cannot be re-pointed at a different input after the fact. Downstream, Step 4 stops at authenticity of the verdict and hands off to Step 5 (ReceiptOS) for eligibility — verified is deliberately not the same as admissible. Step 7 in turn reads only what Step 6 settles, counting outcomes whose settlement postdates the verdict’s committed_at, and that committed_at is read from the ERC-8263 anchor rather than asserted by us. So reputation composes over the settlement layer and the anchor instead of restating them.

All of this is meant to be verified, not taken on faith. The production instance is api.babyblueviper.com/ledger. Entry 19 is the worked example: a pre-action verdict whose committedAt precedes revealedAt, the signed event recoverable from public relays and the commitment anchored on-chain, so anyone can recompute the ordering independently. The reputation axis recomputes live at the endpoint and pins no snapshot, since the figures move as the ledger settles against capital. Read the properties, not a fixed number.

Happy to take questions on the verify and reputation layers.

3 Likes

Very helpful to see the live ledger implementation.

3 Likes

Thanks Pavlo. The live ledger being checkable rather than taken on faith is the whole point. Since you own Step 5, here’s the seam from my side: Step 4 deliberately stops at “is this authentically the validator’s verdict over exactly this input,” and hands the admissibility question to ReceiptOS. So a verified verdict is an input to eligibility, never a claim of it. If the note would benefit from making that verify-to-receipt contract explicit, happy to tighten it with you.

3 Likes

Co-author of Step 3 (input provenance) here.

The load-bearing property for this step is pre-execution binding: the input commitment must be anchored before the service executes, so the result cannot be re-pointed at a different input after the fact. ERC-8281 (record(bytes32 digest)Recorded event) provides the on-chain anchor; ERC-8299/WYRIWE binds the query content to that digest so the commitment is recomputable from public data alone, with no trust in the agent or the service.

On the seams. Step 3 consumes Step 2’s task: the inputHash is derived from the task payload as submitted — the commitment is to the actual query, not a modified form of it. Step 4 then consumes Step 3’s output: the inputHash anchored here is what the verdict in Step 4 must bind to. @babyblueviper1 stated this correctly from the Step 4 side — a verdict cannot be re-pointed at a different input because the inputHash is fixed in the ERC-8281 Recorded event before execution begins.

The mainnet chain is verifiable end-to-end: record() on Base mainnet/L2 (block 47505820, digest 0xe1908f18…) → AttestationIndex on Ethereum mainnet (block 25289932) → AnchorProof on Ethereum mainnet (block 25289963). Two chains, three legs, same commitment throughout — recomputable from public data at each step.

Happy to take questions on the provenance layer and the WYRIWE binding.

2 Likes

What’s happening in this thread is the clearest demonstration of the note I could have asked for. Each of you is speaking from your own layer @babyblueviper1 on the verify/reputation invariants (Steps 4 & 7), @pipavlo82 on eligibility (Step 5), @Damonzwicker on input provenance (Step 3) and the striking thing is that none of you has to reach into anyone else’s layer to make your case. Step 4 stops at verdict authenticity and hands admissibility to ReceiptOS; Step 3 anchors the input pre-execution and asserts nothing about the verdict; Step 7 reads settled outcomes rather than maintaining a score. The boundaries hold on their own.

That is the composition: independently-checkable invariants that compose by reference, not by dependency. It’s also why the note is framed as pattern-first, the contribution is those invariants and the seams between them, with each ERC a conformant example. The thread is the proof: four people describing four layers that interlock without any of them needing the others to be “accepted.”

Two threads only the composition view carries:

  • The spine. One commitment (commitmentHash = keccak256(agentId, modelHash, inputHash, outputHash, timestamp)) is referenced by the report, the verification, the eligibility receipt, and the settlement. @Damonzwicker pre-execution input anchor and @babyblueviper1 commit-gated verdict are binding the same value the payment later references, which is what makes the whole interaction recomputable end to end from public data.

  • Step 1 identity & discovery. Before any of this, the provider agent has a verifiable identity bound to its source token (ERC-8004 + ERC-8217). The flow starts by knowing who you’re consulting and that their authority over the bound source is independently checkable.

Step 6 (settlement) is the section landing next, its scope now sits cleanly in its own layer, so it slots in beside the others in the same conformance form, and §5 is complete.

And an open invitation beyond the authors: if you maintain a standard that could serve as a conformant example at any of these layers, or you see a seam stated too loosely, that’s exactly the feedback this note wants. It’s a living document; the boundaries are the interesting part.

1 Like

This thread is a strong demonstration of the composition model. What stands out is that each layer is defending a narrow invariant without needing to reach into the next layer.

Step 3 establishes pre-execution input provenance. Step 4 establishes an authentic validator verdict over exactly that input. Step 5 handles admissibility/eligibility. Step 6 handles settlement. Step 7 derives reputation from settled outcomes.

That boundary discipline is the important part:

anchored input ≠ verdict
verified verdict ≠ eligibility
eligibility ≠ settlement
settlement ≠ reputation

Each layer produces something the next layer can consume, but does not need to own the next layer’s semantics.

One seam I am trying to reason through is the pre-dispatch agreement layer.

Before ERC-8301 dispatches or advances a workflow step, there may be a separate question:

Who agreed to this interaction?
Under what bounds?
For how long?
With which participants?
With what spend cap, quorum, provider set, verification requirement, or settlement asset?

That seems like a natural place for ERC-8001 to fit into the same composition pattern.

In this framing, ERC-8301 remains the workflow/task layer. It answers:

What task is being run?
What state is the workflow in?
What input/output is bound to the step?
What transition comes next?

ERC-8001 would sit at the coordination/agreement seam. It answers:

Has this interaction been authorised by the required parties?
Are the accepted constraints satisfied?
Is the workflow allowed to begin or continue?

So rather than treating ERC-8001 as the workflow engine, I would frame it as the agreement gate around the workflow:

ERC-8001 = coordination / accepted bounds
ERC-8301 = orchestration / task progression

That preserves the existing boundaries. ERC-8001 does not replace identity, task dispatch, provenance, verification, receipts, settlement, or reputation. It gives those layers a shared agreement context: who accepted the interaction, under what constraints, and when the flow is authorised to proceed.

A possible composition would look like:

ERC-8001 agreement / coordination gate
        ↓
ERC-8004 + ERC-8217 identity / discovery
        ↓
ERC-8301 workflow dispatch
        ↓
ERC-8281 / ERC-8299 input provenance
        ↓
ERC-8274 / ERC-8263 verification + anchoring
        ↓
ReceiptOS eligibility
        ↓
ERC-8275 settlement
        ↓
reputation recomputed from settled outcomes

The important boundary, to me, is that ERC-8001 should not need to know how every workflow node advances, and ERC-8301 should not need to carry all of the social/economic agreement semantics. ERC-8001 can say: “this interaction is authorised under these accepted bounds.” ERC-8301 can then say: “this is the next valid workflow step.”

That makes ERC-8001 coordination glue for more complex flows, but not a replacement for the specialised layers.

Curious if this seam feels aligned with the note’s pattern-first approach, especially for delegated agents, capped service calls, multi-party approvals, solver-mediated execution, group workflows, and payment-bearing agent interactions.

2 Likes

Thank you, @KBryan.

The discipline you state is exactly the note’s spine: each layer defends a narrow invariant and refuses to assert its neighbour’s. Input-provenance ≠ verdict, verdict ≠ eligibility, eligibility ≠ settlement, settlement ≠ reputation. Stated as a chain of refusals like that, the gap you point at is real and it’s at the front: before any step is dispatched, something has to establish that these parties are authorized to interact at all and that the accepted bounds — participants, spend caps, quorum are in place. The note currently opens at identity/dispatch and quietly assumes that agreement already happened. It shouldn’t assume it; it should name the layer that provides it.

ERC-8001 as a coordination / accepted-bounds gate - not a workflow engine - fits without disturbing anything downstream. The key is precisely the restraint you put on it: 8001 answers “is this interaction authorized and are its constraints satisfied?” and then hands off. It does not execute the workflow (that’s 8301’s task layer), it does not verify inputs, it does not settle. It establishes the envelope of consent the later layers operate inside, and each of those layers still independently enforces its own invariant rather than trusting that the agreement covered it. Agreement sets the bounds; it never becomes the thing that guarantees they were honoured. That keeps the same composition-not-conflation rule we hold everywhere else.

So the sequence reads: agreement/coordination (8001) → identity (8004) → dispatch (8301) → input provenance (8281/8299) → verification (8274) → anchor (8263) → eligibility (ReceiptOS) → settlement (8275) → reputation (8275 axis). A pre-dispatch gate at the head, each link defending one invariant, none load-bearing for its neighbour’s.

If that reading matches your intent, I’d love to fold it in as the flow’s front seam — and the cleanest way to do that, in the same form as the other steps, is a short conformance stub authored by you (the “accepted bounds” gate, stated as the narrow invariant it defends and what it explicitly does not assert). Same pattern as the rest of §5. Happy to sketch the frame against the 8301 dispatch boundary if useful, but the section should be yours, it’s your layer.

The one question I’d put back to you, to keep the boundary crisp: where exactly is the handoff from 8001 to 8301? My read is that 8001 closes the moment the bounds are accepted (authorization + constraints fixed), and 8301 owns everything from dispatch onward, so the agreement is a precondition the task layer can reference but never re-opens. Does that match how you’d draw it?

1 Like

Yes, that handoff makes sense .

And I think the same boundary rule applies later as well:

agreement ≠ dispatch

dispatch ≠ provenance

provenance ≠ verdict

verdict ≠ eligibility

eligibility ≠ settlement

settlement ≠ reputation

Each layer should close one invariant and hand off a reference, not reopen the previous layer.

1 Like

Yes, that handoff makes sense.

And I think the same boundary rule applies throughout the rest of the flow as well:

agreement ≠ dispatch

dispatch ≠ provenance

provenance ≠ verdict

verdict ≠ eligibility

eligibility ≠ settlement

settlement ≠ reputation

Each layer should close one invariant and hand off a reference, not reopen the previous layer.

That seems to be the common pattern emerging across the note: independently-checkable invariants composed by reference rather than by dependency.

The value of the composition is precisely that each layer can be replaced, upgraded, or disputed without requiring the surrounding layers to redefine their own guarantees.

2 Likes

Thanks everyone for the discussion here — the boundary chain that emerged across these posts is exactly what the composition note set out to show: each layer defending a narrow invariant and handing off a reference, independently checkable from public data. Seeing each layer’s author speak from their own step without reaching into anyone else’s layer is the strongest confirmation of the pattern.

A small reflection on where this could go next.

Right now the standards, the composition note, the Sepolia demo — they all exist, but they’re spread across personal GitHub repos, gists, and forum threads. The technical work is solid, but someone new who stumbles upon one piece has no obvious way to find the rest.

It might make sense to consolidate the reference implementations and demos under a neutral GitHub organization — focused on AI and blockchain infrastructure, not tied to any single ERC. Just a place where the working code lives: clone-and-run contracts, tests, deploy scripts, and walkthroughs that trace the full flow. The composition note describes the pattern; the org would host the code that demonstrates it.

This isn’t about promoting a particular standard. It’s about giving developers who want to build on these primitives a single entry point — so the ecosystem can find the work and contribute back. Curious how others see this.

2 Likes

Update §5 is complete, 8/8. Panini ( @Panini ) landed Step 6 (Settlement, ERC-8275) in the shared conformance format, so every step plus the cross-cutting anchor is now specified, each by its own layer owner:

Step 1 Identity & Binding · Step 2 Consult/Dispatch · Step 3 Input Provenance · Step 4 Verify · Step 5 Eligibility · Step 6 Settlement · Step 7 Reputation · + the cross-cutting ERC-8263 Anchor.

The one open design question, where per-consult escrow sits relative to ERC-8275’s per-period compensation — is resolved in Step 6 (condition 7): per-consult escrow-on-delivery is a sub-pattern of the 8275 settlement axis (same commitment spine, same verification/eligibility gating, same axis separation, specialised to the 1:1 case), with per-period mesh compensation the broader case that additionally requires the commit-reveal cycle. Same axis, two granularities — not two primitives.

@ten-io-meta @JimmyShi22 this is exactly the boundary chain you both named: each layer closes one invariant and hands off a reference, none reaching into another’s. The completed §5 is that chain written down — replaceable, upgradeable, disputable layer by layer, composing by reference, not by dependency. Seeing each step authored by its own layer owner, in the same conformance format, is the strongest evidence the pattern holds.

Note (now 8/8, submission-ready): https://gist.github.com/TMerlini/c02bc4f56bc573a10a0cd9d487b8e884

And +1 to Jimmy’s point on a shared home: with §5 closed, pulling the standards + this note + the live demo under one discoverable roof is the right next step, so someone who finds one piece can find the rest. Happy to help land that. Thanks to every layer owner, the integration is the joint result.

1 Like

The most interesting outcome here is not any individual ERC, but the fact that the composition itself remained modular. Each layer owns a single invariant, exposes a reference, and stays replaceable without breaking the rest of the flow. That’s a much stronger property than any single implementation.

1 Like

Very helpful to have this all written down and with the step specs now closed it’s nearly the whole picture. What I would still flag though sits right behind the agreement gate @KBryan raised.

8001 agrees the bounds up front: spend cap, provider set, settlement asset, duration. But once a cap is agreed, something has to count consumption against it as the interaction runs, and the note doesn’t name that. It sets the cap at the front and then assumes the later steps stay under it. Agreeing a cap and metering it are different invariants, the same split @KBryan and I have been drawing on the 8312 thread: 8001 records the authority, the cursor meters what’s spent against it.

So the invariant: cumulative spend never exceeds the agreed bound, counted across every step that draws value, recomputable from public data. Like the rest, it stays in its lane. It doesn’t agree the bound, move the value, or judge the verdict; those belong to 8001, 8275, and 8274. It only counts.

It’s cross-cutting, the way the 8263 anchor is. The anchor keeps one commitment recomputable across the flow; the cursor keeps one cap binding across it. A consult at Step 2 and a settlement at Step 6 draw against the same meter, and no single step can see the running total, which is why it can’t live as a field inside any one of them.

That layer is ERC-8312. It reads the bound 8001 agreed, exposes a cursor the drawing steps advance, and says nothing about whether the verdict was sound or the settlement admissible. If the note wants the consumption invariant named, I’ll write it up in the same per-step format as the others.

1 Like

I think the distinction you’re drawing is important.

An authority limit, a consumption cursor, and a value reservation are related but distinct invariants.

The authority layer defines what may be spent. A cursor layer can track how much of that authority has been consumed across the workflow. Separately, a reservable-value layer can guarantee that specific value has been committed and is no longer available for conflicting allocations.

Those layers can compose without overlapping responsibilities. The cursor measures consumption against an agreed boundary, while the reservation layer protects the accounting boundary itself.

That seems very consistent with the pattern described throughout the note: one invariant per layer, independently verifiable and independently replaceable.

A consumption cursor and a reservation mechanism may often be used together, but they answer different questions and can evolve independently.

1 Like

Yes, this is the missing invariant I was trying to isolate.

From the ERC-8001 side, the agreement can commit to the bounded authority up front: cap, asset, participants/provider set, duration, authorised agent, and any accepted caveats or conditions. But after that mandate is accepted, ERC-8001 should not also become the runtime accounting surface.

So I agree with the split:

ERC-8001 records the authority.
ERC-8312 meters consumption against that authority.
ERC-8275 handles value movement / settlement.
ERC-8274 handles verdict or proof validity.
The substrate is what actually makes the bound non-bypassable.

The invariant you named is the right one:

cumulative spend <= agreed bound

And importantly, that cumulative spend has to be counted across every step or surface that draws value from the same mandate. A consult, a tool call, a venue action, and a settlement can all consume the same accepted authority even if they do not live inside one step contract.

That is why I agree it should not be a field inside any one step. A step-local budget only proves that step stayed under its own local view. It does not prove the mandate as a whole stayed under the agreed cap. The cursor gives the flow a shared meter.

I also like the comparison to ERC-8263. The anchor keeps one commitment recomputable across the flow; the cursor keeps one bound consumable across the flow. Neither needs to judge the semantics of every layer. They just preserve the cross-cutting invariant.

So yes, I would support naming this explicitly in the note:

Agreement invariant: the mandate was accepted.
Verification invariant: the verdict/proof is admissible.
Settlement invariant: the value movement is valid.
Consumption invariant: cumulative spend against the accepted mandate never exceeds the agreed bound.

That last one is ERC-8312’s lane.

The only wording I would keep careful is that ERC-8312 does not “enforce” the principal’s bound by itself. It meters and rejects invalid advances under its profile. The actual enforcement boundary is still the substrate that requires value-drawing actions to pass through the cursor.

But as the per-step invariant, so, yes: this belongs in the picture.

1 Like

@KBryan agreed, good way to frame it. The cursor meters and rejects a draw that goes over the bound, but it isn’t the thing that makes the bound non-bypassable. That’s the substrate, the part that forces value-drawing actions through the cursor in the first place. If nothing requires you to go through the cursor, it’s just a counter. So “consumable” is the better word than “binding”, since binding makes it sound like the cursor does the enforcing when it doesn’t. The four invariants look right to me, and consumption is the 8312 one: cumulative spend against the accepted mandate stays under the agreed bound.

@ten-io-meta I think the cursor and reservation distinction is worth keeping. The cursor tells you how much of the authority is left. A reservation tells you whether some specific value is locked and can’t be spent on something else. Those are different questions, and the cursor only answers the first, it counts against the bound and doesn’t reserve anything. I would keep reservation as its own invariant rather than fold it into the cursor, otherwise the cursor stops being something you can swap out on its own.

If you want consumption named in the note, I’m happy to write it up in the same per-step format as the rest, with the meter-vs-enforce line stated explicitly so the cursor doesn’t get read as the enforcement layer.

1 Like

These four converge on a real gap, and one that already has running reference code. @blockbird and @KBryan are right: agreeing a bound (the 8001 mandate, cap, provider set, asset, duration) and metering consumption against it are different invariants. The note sets the cap at the front and then assumes the later steps stay under it; it never names the thing that counts cumulative spend across every value-drawing step. That’s a distinct, cross-cutting invariant, the consumption cursor, sitting beside the 8263 anchor: the anchor keeps one commitment recomputable across the flow, the cursor keeps cumulative spend recomputable against the bound. +1 to adding it.

Worth saying it isn’t hypothetical. The per-leaf cursor reference blockbird and I co-designed (the hierarchical budget profile) implements exactly this invariant: cumulative spend metered per-leaf against a static capability tree, recomputable from LeafAdvanced events, draw-once nullified, and concurrent across scopes, a consult, a tool call, and a settlement can each draw against the same mandate without a global cursor snapshot. So the invariant has a substrate to point the note at, not just a description.

And +1 to the #17 sharpening, because it’s the load-bearing half: the cursor meters, but what makes the bound non-bypassable is that every value-drawing action must prove its leaf is in the capabilityRoot, which is itself the accepted 8001 agreementHash. If nothing forces the draw through the cursor it’s just a counter; membership in the agreed capability tree is what forces it. So the invariant is really two lanes that stay in their lanes: the cursor counts (consumption), and the capabilityRoot ← 8001 binding makes the count non-bypassable (substrate). That binding is the layer-1 seam already in flight.

This is @blockbird layer to write the conformance criterion for, same as Step 6 was Panini’s , but happy to bring the reference impl and the capabilityRoot/8001 substrate so it lands in the note’s format as a cross-cutting invariant beside the anchor. @ten-io-meta cursor-vs-reservation distinction (#15/#17) is the right line to hold while doing it: counting consumption and reserving specific value are different questions, the cursor only answers the first.

@TMerlini works for me, I will write the consumption criterion.

One thing I want to make sure to get right (in alignment with @KBryan): The capabilityRoot ← 8001 binding is what makes the cursor meter against the authority that was actually agreed. But it’s not what stops you bypassing the cursor. Membership is something the cursor checks once you are already going through it. What forces you through it in the first place is the substrate, the part that won’t let value move unless a cursor advance happened first. So three things that shouldn’t blur, and I’ll keep them as separate conditions in the criterion: the cursor meters each draw and rejects any that goes over the bound, the capabilityRoot ← 8001 binding makes that the agreed bound and not an arbitrary one, and the substrate is what makes the cursor impossible to route around. I’m writing those conditions and you are covering the reference and the capabilityRoot/8001 substrate they point at. Kept separate, nobody reads the cursor as the enforcer.

For the implementation line I will point at the per-leaf profile, not the flat cursor: per-leaf spend metered against the static capability tree, recomputable from LeafAdvanced, draw-once nullified, scopes advancing independently. That’s the one that actually does all of it.

And +1 on keeping @ten-io-meta’s distinction in view while we write it. Counting what’s been spent and reserving a specific piece of value are different questions, and the cursor only does the first.

1 Like

Yes, this is exactly the distinction I would keep.

From the ERC-8001 side, the capabilityRoot ← 8001 binding is what proves the cursor is metering against the authority that was actually accepted, not against an arbitrary budget someone introduced later.

But that binding is not the enforcement boundary.

I would keep the three conditions separate:

  1. The cursor meters each draw and rejects advances that would exceed the bound.

  2. The capabilityRoot ← 8001 binding proves that the bound being metered is the one the parties actually accepted.

  3. The substrate is what makes the cursor non-bypassable by refusing to let value move unless the required cursor advance has occurred.

That separation matters because ERC-8001 can commit to the accepted mandate, but it should not be treated as the runtime meter. Likewise, the cursor can maintain the spend invariant, but it should not be read as the thing that forces all actions through it. The substrate does that.

So the consumption criterion should probably make the invariant explicit:

cumulative spent against the accepted mandate <= agreed bound

And then decompose it into those three checks: metering correctness, agreement binding, and non-bypassability through the substrate.

I also agree that the per-leaf profile is the right implementation reference, not the flat cursor. Per-leaf spend against a static capability tree gives us the properties the criterion needs: recomputable spend from LeafAdvanced, draw-once nullification, and independent advancement across scopes.

The final distinction from @ten-io-meta is important too: counting consumption and reserving a specific piece of value are different invariants. The cursor counts what has been consumed. It does not reserve value, settle value, or prove that a verdict was correct.

That keeps the cursor in its lane while still making the missing consumption invariant explicit.