jcp: a chain is bounded in money on every link, and a delegated grant is never decided alone #304

Merged
dcharlot merged 1 commit from fix/jcp-chained-money into main 2026-10-17 17:03:10 -04:00

2026-10-17

Transaction Science
jcp: a chain is bounded in money on every link, and a delegated grant is never decided alone
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 1m1s
standards workspaces build + test / joule-ui-rs (joule-ui/joule-ui-rs, joule-ui-rs, linux) (pull_request) Successful in 1m13s
standards workspaces build + test / jcp-rs (jcp-conformance, jcp/jcp-rs, -p jcp-energy --features nvml, jcp-rs, linux) (pull_request) Successful in 1m32s
standards workspaces build + test / joulehook-rs (joulehook/joulehook-rs, joulehook-rs, linux) (pull_request) Successful in 1m14s
standards workspaces build + test / sandbox-rs (sandbox-conformance, sandbox/sandbox-rs, sandbox-rs, linux) (pull_request) Successful in 2m19s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 6m18s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 1m4s
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 3m53s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 5m19s
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 9m23s
Two gaps in how JCP decides a delegated grant.

A chain could not be priced. The single-grant path has `decide_priced`,
which enforces the money ceiling beside the joule ceiling (§4.8). Chains
had no priced decision at all, so a delegated grant's money ceiling was
never consulted: not the leaf's, and not the parent's whose budget the
leaf draws on.

A delegated grant could be decided on its own. `decide`, `decide_priced`,
`authorize` and the flow variants accepted a grant with a `parent`,
decided it as a root, and never saw the chain. §4.2 says a delegated grant
MUST be decided with its full chain. Alone, nothing shows it narrows what
its issuer held, so its budget, caveats and expiry were taken at their
word.

- `decide_chained_priced` applies both ceilings to every link. Joules are
  checked first on every link, then the money ceiling of every link that
  has one, refusing a foreign currency. An allow debits both dimensions
  from every link, so siblings share their parent's money as they share
  its joules. A deny debits neither. A chain with no money ceiling ignores
  the price.
- The single-grant checks deny a grant with a `parent` `chain-broken`.
  Nothing in jcp-rs or its consumers relied on the old behaviour.
- SPEC §4.2 states both rules, and C22 covers a priced chain and a
  delegated grant decided alone.

Checked on the build host:
- jcp-rs: 504 tests pass, three of them new, and the conformance suite
  passes all checks.
- Every vector is byte-identical.
- jouleclaw-jcp, joule-code-jcp, sandbox-jcp, mesh-core and
  joule-ui-interaction pass their tests.
- Mutations each fail tests and C22: allowing a lone delegated grant,
  skipping the money check on chains, and debiting money on the leaf
  only (that one fails tests).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-17 11:42:12 -04:00