open-standards/jcp/jcp-rs
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Transaction Science 3005307df1
All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 42s
standards workspaces build + test / jcp-rs (jcp-conformance, jcp/jcp-rs, -p jcp-energy --features nvml, jcp-rs, linux) (pull_request) Successful in 1m38s
standards workspaces build + test / joule-ui-rs (joule-ui/joule-ui-rs, joule-ui-rs, linux) (pull_request) Successful in 1m9s
standards workspaces build + test / joulehook-rs (joulehook/joulehook-rs, joulehook-rs, linux) (pull_request) Successful in 1m10s
standards workspaces build + test / sandbox-rs (sandbox-conformance, sandbox/sandbox-rs, -p sandbox-tee --features amd-kds,intel-pcs, sandbox-rs, linux) (pull_request) Successful in 2m40s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 3m12s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 3m55s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 59s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 7m50s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 3m2s
jcp-x402: refuse a payment scheme this crate does not implement
`ingest_requirements` parsed `scheme`, defaulted an empty value to `"exact"`,
and then **nothing ever read the field** — `git grep '\.scheme\b' -- jcp/`
returns zero hits. So a requirement naming any other scheme was gated exactly
as if it were `exact`.

That matters most for x402's `upto`, which means "charge up to
`maxAmountRequired`, settle for the actual amount". Accepted as `exact`, its
per-request **maximum** is debited as the price: `spent_minor` accumulates
`price.minor` at authorization (`jcp-runtime` lib.rs ~315 and ~931), and
`seal_settlement` passes `Price::new(&req.asset, 0)` — its own comment says
"debits nothing, reads nothing". Nothing ever reconciles authorized down to
settled, so a session settling at a tenth of its cap exhausts a money ceiling
ten times too fast.

The fix is to refuse, not to reconcile. This crate implements `exact`, where
the authorized price *is* the settled price — so `spent_minor` accumulating
`price.minor` at authorization is exact by construction and there is nothing to
reconcile. Honouring `upto` would need a settle-down debit that does not exist,
and inventing one would mean making `spent_minor` non-monotonic, which is a
change to the ceiling's soundness model rather than a bug fix. Supporting
`upto` is a feature; proceeding under semantics the code does not implement is
the defect.

`X402Error::UnsupportedScheme` is a new variant rather than `Malformed`,
because the document is well formed — this crate simply does not honour what it
asks for. An absent scheme stays `exact`, which is the v1 default and the
semantics the money path implements; an existing test that omits the field
proved that is load-bearing when a mutation removed it.

The check is an allowlist, not a denylist of `upto`, and is ordered **before
any figure is parsed**. A caller that fixed a broken amount would otherwise be
led to retry into semantics this code does not implement.

That ordering was wrong in my first version and a test caught it: I wrote
"settled before any figure below is read" in the comment while placing the
check after `maxAmountRequired` was parsed, so the document reported a
malformed amount instead of the unsupported scheme. The claim was false until
the check moved above every figure.

Falsification, three mutations, all killed by their named test: the pre-fix
behaviour (any scheme accepted as exact); refusing an absent scheme too
(over-strict — also breaks an existing test that omits it); and a denylist of
one name instead of an allowlist.

Found by the 2026-10-22 landscape sweep, which ranked it against EMVCo's
agentic-payments framework draft. The EMVCo draft itself is log-in gated and
its licence excludes derivatives, so it was not retrieved or used; the shipped
counterpart x402 (Apache-2.0, spec v2) is what this reads.

Verified: workspace check 0 errors, 66 test binaries green, 0 failures, clippy
`-D warnings` clean, `check-spec-refs` 1773 citations across 16 standards,
47 lockfiles current.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-22 07:27:44 -04:00
..
conformance/v1 jcp: JCR-1 receipts bind their payload — jcp/2 + version dispatch (SPEC §8, C23) 2026-07-18 03:04:19 -04:00
crates jcp-x402: refuse a payment scheme this crate does not implement 2026-10-22 07:27:44 -04:00
Cargo.lock jcp-wire: a caller-signed challenge, and endpoint evidence bound to the answer 2026-10-21 10:26:42 -04:00
Cargo.toml jcp-action-receipt: AR-1, the composition envelope 2026-08-28 08:44:07 -04:00