jcp §4.7: an amendment may only tighten against what the grant has LEFT #165
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/checkpoint-energy"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The hole
jcp-grant's checkpoint module promises, in its own words, that "an amendmentmay only tighten … so steering can never escalate a running agent's authority."
Both
amendandverify_amendmentenforced that with:That compares against the budget as issued. On a 1 000 µJ grant whose run
has already spent 900, an amendment of 1 000 passes as a "tightening" and hands
the run ten times its remainder. The steering mechanism built to re-bound a long
run could re-fund it instead.
The sweep that found this framed it as "
Checkpointcarries no energy field",which understates it. The missing field is why the check could not be written
correctly: there was nothing for it to measure against.
What changed
Checkpointgainsspent: Option<Spend>— a cumulative microjoule figure withits §5 provenance grade. Cumulative rather than per-interval, so one checkpoint
answers "how much is left" on its own, without the verifier holding the whole
chain and without a missing link silently understating the total.
remaining_uj(grant, cp)derives the remainder, and returnsNonewhen thecheckpoint is silent. Unknown is not zero, and conflating them is exactly 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 in
order to fix a hole those checkpoints cannot express. The guarantee is only as
strong as the checkpoint — which
remaining_ujreturningNoneis how averifier finds out.
Enforced on both sides.
amendrefusing is not enough: a steward can sign anover-budget amendment with its own key and hand it to an enforcement point,
which never calls
amend.What the figure is actually worth
Stated in the module docs rather than left implied: the checkpoint is authored
and signed by the agent — the party the remainder constrains — so its
declared spend is a claim, not an independent measurement. The
provenancegrade travels with it so the amender can see which kind of claim it is. Two
things make the claim hard to shrink: it is signed, so understating it is
attributable, and it is cumulative, so the new
checkpoint_follows(prev, next)refuses a successor that declares less than its predecessor or drops a field it
once carried — otherwise an agent recovers its full issued ceiling simply by
going quiet. What this layer does not do is independently meter the run.
The wire change is additive, and that is checked
spent: Noneis skipped, soCheckpoint::id()and every sealed vector arebyte-identical to before the field existed. Regenerating the pack is the proof:
standing.jsongains one entry and no published id or signature moves,checkpointincluded.skip_serializing_ifturned out to be load-bearing rather than tidy — the JCR-1signed core forbids nulls, so removing it makes
Checkpoint::id()fail outrightwith
DisallowedType("null")on every checkpoint that states no spend. Omissionis the only encoding the canonical form permits, and the field's doc comment now
says so where an editor would see it.
The new
checkpoint_with_spendvector publishes the issued budget beside thespend 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. Theremainder rule itself is a refusal, and a refusal has nothing to sign, so it is
pinned by C21 and unit tests rather than by a vector.
Spec
§4.7 and C21 now make the remainder normative: both sides MUST enforce it, an
absent spend MUST NOT be read as zero, and a declared spend MUST NOT decrease.
Verification
cargo test --workspaceinjcp/jcp-rs: 407 passed, 0 failed. No new clippywarnings (the one
jcp-schemawarning predates this branch).Six falsifications run from the committed baseline, each reverting one thing and
confirming a test dies:
a_silent_checkpoint_keeps_the_older_weaker_ceilingsaturating_sub→wrapping_suba_spend_beyond_the_budget_leaves_nothing_rather_than_wrappingamend)verify_amendment_enforces_the_remainder_toocumulative_spend_may_not_fall_or_go_silent_across_a_runskip_serializing_ifremoved🤖 Generated with Claude Code
9f0cfd74be9248799a6a9248799a6a936d26761apaths:matches the push delta #191