@TMerlini Following up on the consumption gap I raised above: here is the per-step invariant, and an implementation that runs it.
The flow agrees a cap in ERC-8001 (spend cap, provider set, asset, duration), then draws against it: ERC-8281/8299 fix the input, @JimmyShi22 (ERC-8301 executes, ERC-8263/8274 commit and verify, ERC-8275 settles. The agreement bounds the total; nothing bounds the running sum the steps have drawn. So two steps that each look within the cap can together exceed it. The cap is agreed but never enforced.
The consumption step, in the same per-step format:
Bounded action (ERC-8312) reads the agreed cap and exposes a cursor the drawing steps advance. A step that spends reserves against the cursor; the reservation commits before the next step reads it, so a second step that would cross the cap reverts instead of racing past it. Reserve, then confirm on settle or cancel on revert, so an aborted step returns its room.
Why a write and not a re-check: recomputing “have we spent too much?” from reads cannot hold an aggregate across steps. At check time the sibling step has written nothing the check can see, so both pass and the sum overshoots. Enforcing the cap needs each step to commit its claim before the next reads it. On one chain the L1 serializes that, which is the part that works today.
I built a reference that runs this end to end: the race (a stateless re-check blows a 150 cap to 200 with no revert; the cursor holds the same cap), wired into a standing/escrow/provenance loop, with the metering contracts adversarially audited and a reverted transaction on Base Sepolia
If the note wants the consumption invariant in the flow, I’ll slot it between the agreement gate and settle, in the format the other steps use. The open question is placement: does the cursor check belong at execute (ERC-8301), at settle (ERC-8275), or as its own gate the executing step calls? Feedback welcome. ![]()