jcp §4.7: an amendment may only tighten against what the grant has LEFT #165
Merged
dcharlot
merged 1 commit from 2026-10-08 19:55:19 -04:00
feat/checkpoint-energy into main 2026-10-08
jcp §4.7: an amendment may only tighten against what the grant has LEFT
All checks were successful
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m15s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m5s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m37s
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Successful in 27s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 6m40s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 13s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 12m59s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 24s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 46s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m44s
WAI HTTP delivery / HTTP corpus · falsification and differential (pull_request) Successful in 1h19m13s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m4s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m3s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m7s
wai-pack / wai-pack · linux (pull_request) Successful in 1m4s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 1m40s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 22s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m6s
WAI section references / cited sections exist (pull_request) Successful in 10s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 4m21s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 2m42s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 3m3s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 5m1s
wai cross-architecture byte-equality / macos-arm64 (reference) (pull_request) Successful in 30s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 10m35s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 29s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 3m33s
wai-pack / wai-pack · macos (pull_request) Successful in 6m13s
Both `amend` and `verify_amendment` compared the amended budget against `grant.budget_uj` — the budget as ISSUED. On a 1 000 µJ grant whose run had already spent 900, an amendment of 1 000 passed as a "tightening" while handing the run ten times its remainder, contradicting the module's own guarantee that "steering can never escalate a running agent's authority". The hole was not that the check was missing; it was that the checkpoint had no way to say what had been spent, so there was nothing for the check to measure against. `Checkpoint` now carries `spent: Option<Spend>` — a cumulative microjoule figure with its §5 provenance grade. Cumulative rather than per-interval, so one checkpoint answers "how much is left" without the verifier holding the whole chain and without a missing link silently understating the total. `remaining_uj` derives the remainder and returns `None` when the checkpoint is silent: unknown is not zero, and conflating them is how an amendment hands back a whole grant. The ceiling is now the remainder where the checkpoint states its spend, and the issued budget where it does not. The fallback is deliberately the old, weaker rule rather than a refusal — a checkpoint written before the field existed is still a valid checkpoint, and rejecting it would break running deployments to fix a hole it cannot express. Enforced on both sides: `amend` refusing is not enough, because an enforcement point handed a signed amendment never calls `amend`. What the figure is worth, stated rather than implied: the checkpoint is authored by the agent, so its declared spend is a signed claim, not an independent measurement. Two things make it hard to shrink — it is attributable, and `checkpoint_follows` catches a later checkpoint that declares less than an earlier one or drops a field it once carried, which would otherwise let an agent recover its full ceiling by going quiet. Wire change is additive: `spent: None` is skipped, so `Checkpoint::id()` and every sealed vector are byte-identical to before the field existed. Regenerating the pack proves it — `standing.json` gains one entry and no published id or signature moves. The new `checkpoint_with_spend` vector publishes the issued budget alongside the spend so a third party can redo the arithmetic, and its id necessarily differs from `checkpoint`'s, which is what makes the additivity claim non-vacuous. The remainder rule itself is a refusal, and a refusal has nothing to sign, so it is pinned by C21 and unit tests instead. SPEC §4.7 and C21 updated: the remainder is normative, both sides MUST enforce it, an absent spend MUST NOT be read as zero, and a declared spend MUST NOT decrease. Co-Authored-By: Claude Opus 5 <[email protected]>