open-standards/jcp/jcp-rs/crates/jcp-x402/examples
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Transaction Science 86f130e3dc jcp-x402: upto holds its maximum and releases what it did not spend
The money hold existed in the runtime; `upto` was still paying through a
single-phase decision that debited the authorized maximum and never gave any
of it back. The crate's own documentation said so and told callers to size a
session's ceiling to the sum of its maxima. That is now obsolete.

`hold_upto` reserves the maximum in both dimensions before the agent pays,
debiting neither, and seals the reservation as a hold. `settle_upto` resolves
it with the measured joules and the settled amount, so the difference is
released: a session that settles at a tenth of its maxima keeps nine tenths of
its ceiling. The test asserts the thing that was previously impossible — after
a 100_000 settlement against a 1_000_000 authorization, a further 900_000 is
still authorizable, where the old path had spent the lot.

A refused resolution leaves the hold outstanding so the caller can retry rather
than lose the reservation; resolving twice is refused, because the hold is
gone; and `hold_upto` refuses a second hold while one is outstanding instead of
silently replacing it, which would leave the first unresolvable.

Supporting work, all of it required for the above to be honest:

- `jcp-receipt` gains `seal_hold` and `seal_settle`, the unlogged forms of
  `append_hold` / `append_settle`. Without them a gateway that seals without a
  hash-chained log could place a hold no receipt states — a reservation no
  replay can restore, so the enforcement point comes back from a restart with
  the interrupted charge payable a second time.
- `jcp-bridge` gains `hold_x402` and `settle_x402`.
- `X402Profile::new` takes a **per-call joule ceiling**. A hold reserves the
  stated per-invocation bound where the grant states one, so a metered session
  with a per-call ceiling admits concurrent charges while one without it is
  bounded by serialization. Passing `0` states none and keeps the old
  behaviour. `for_charge` passes its joule figure through, a single charge's
  session ceiling being its per-call ceiling by definition.
- `hold_upto` takes no cost estimate. The joule bound comes from the grant,
  because a ceiling may not admit work against an estimate — which is the same
  rule that makes the authorized maximum, not a guess at the outcome, the thing
  a money hold reserves.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-10 13:16:16 -05:00
..
pay.rs jcp-x402: upto holds its maximum and releases what it did not spend 2026-11-10 13:16:16 -05:00