open-standards/jcp/jcp-rs/crates
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
..
jcp-a2a jcp-a2a: an unverified AP2 mandate could set the ceiling, and name any payee 2026-10-05 07:22:11 -04:00
jcp-action-receipt mesh/1 + AR-1: receipts commit to the output; deterministic serves replay 2026-10-21 04:35:32 -04:00
jcp-bridge jcp: WithinWindow, a sliding-window caveat over calls, payloads and measured joules 2026-10-21 07:30:20 -04:00
jcp-channel jcp: a ModelIn caveat says which model a grant authorizes, and the frame names the model it runs 2026-10-17 04:21:21 -04:00
jcp-cite jcp: a ModelIn caveat says which model a grant authorizes, and the frame names the model it runs 2026-10-17 04:21:21 -04:00
jcp-cli jcp: a ModelIn caveat says which model a grant authorizes, and the frame names the model it runs 2026-10-17 04:21:21 -04:00
jcp-conformance jcp-wire: a caller-signed challenge, and endpoint evidence bound to the answer 2026-10-21 10:26:42 -04:00
jcp-efficiency efficiency/1: a partial energy figure is sealed as partial and never headlines as a task total 2026-10-20 13:58:36 -04:00
jcp-energy energy meters: a GPU counter reading low is refuted in sandbox-meter, eoc-meter and jcp-energy too 2026-10-20 04:15:36 -04:00
jcp-flow jcp-flow: Compute propagated provenance from tool bytes 2026-07-22 02:09:29 -04:00
jcp-gateway jcp-gateway: everything a gated request carries to the server is sealed and flow-checked 2026-10-19 11:23:23 -04:00
jcp-grant jcp: a chained decision enforces caveats, and a chain cannot drop one 2026-10-17 10:44:16 -04:00
jcp-intercept jcp-intercept: a reading meter meters a seam as one span, divided among its steps by CPU time 2026-10-13 02:41:41 -04:00
jcp-orchestrate jcp: a ModelIn caveat says which model a grant authorizes, and the frame names the model it runs 2026-10-17 04:21:21 -04:00
jcp-policy jcp-policy: a receipt sealed the policy's name, so the rules could be swapped under it 2026-10-05 07:22:12 -04:00
jcp-prompt jcp-prompt: a signed, content-addressed prompt registry 2026-06-27 19:57:46 -04:00
jcp-receipt jcp-gateway: replay our own receipt stream at startup (SPEC §8.1) 2026-10-17 11:42:06 -04:00
jcp-runtime jcp: WithinWindow, a sliding-window caveat over calls, payloads and measured joules 2026-10-21 07:30:20 -04:00
jcp-schema jcp: WithinWindow, a sliding-window caveat over calls, payloads and measured joules 2026-10-21 07:30:20 -04:00
jcp-threshold jcp-wire: the endpoint decides at its own clock, and a captured request is decided once 2026-10-18 13:40:16 -04:00
jcp-trace jcp-trace: an undefined wedge metric is not zero 2026-10-17 04:54:47 -04:00
jcp-wire jcp-wire: a caller-signed challenge, and endpoint evidence bound to the answer 2026-10-21 10:26:42 -04:00
jcp-x402 jcp-x402: refuse a payment scheme this crate does not implement 2026-10-22 07:27:44 -04:00