mesh/1 + AR-1: receipts commit to the output; deterministic serves replay #378
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/receipts-bind-the-output"
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?
Sweep 2026-10-19 item #6. A mesh receipt bound what was asked (
request_id) and what it cost, and nothing about what came back, so no one could later show which answer a receipt was for. AR-1 had the same gap besideinput_hash.mesh/1 (SPEC §6.4)
output_commitment. A salted BLAKE3 commitment over:It is a commitment rather than a hash, because a short output (a one-token answer) can be reversed from its hash.
The payload is bound.
prompt_hashaddresses the prompt's bytes, while an engine is handed token ids, sorequest_idalone cannot confirm what a replay runs on. Without this binding, an honest disclosed output replayed on the wrong tokens would read as the steward's divergence.ServingEngine::deterministic. The default isfalse; the reference engine returnstrue.mesh_core::replay. It re-executes a sealed serve and returns one of three verdicts:Verified: the re-run opens the commitment.Diverged { first_difference }: returned only when a disclosed output opens the commitment on the same payload and opening. That confirms all three, so the mismatch is the serve's.NotReplayable(why): the engine samples; the backend, recipe or weights are not the ones the receipt names; the request is not the receipt's; the receipt commits to no output; or no disclosed output confirms the inputs, so nothing attributes the mismatch.Conformance pack regenerated. The reference receipt gains the field, and the envelope grows from 663 to 747 bytes.
AR-1
output_hash. An optional field afterinput_hash, sealed only when bound (§2.3).output_commitmentas one.ar-verifylint.len() % 2 == 0becomesis_multiple_of(2). This clippy error predates this change; fixing it makes the crate clippy-clean.Verification (build host)
-D warnings) and rustdoc are clean on the touched crates.jcp-conformancebinary.Left for later
From the same sweep item, as follow-ups:
cra.rs;🤖 Generated with Claude Code
A mesh receipt bound what was asked (request_id) and what it cost, and nothing about what came back, so no one could later show which answer a receipt was for. AR-1 had the same gap beside input_hash. mesh/1 (SPEC §6.4): - output_commitment: a salted BLAKE3 commitment over the request id, the digest of the prompt payload the engine was handed, and the output tokens. It is a commitment, not a hash, because a short output is reversible from its hash. The opening is derived per request from a key drawn from the steward's signing key, so a restarted steward can still disclose it. The field is absent for a typed decision, whose answer the engine interface does not carry, and omitted when absent, so older receipts keep their bytes. - The payload is bound because prompt_hash addresses the prompt's bytes while an engine is handed token ids, so request_id alone cannot confirm what a replay runs on. - ServingEngine::deterministic (default false; the reference engine true). - mesh_core::replay re-executes a sealed serve. Its verdicts: - Verified: the re-run opens the commitment. - Diverged { first_difference }: only when a disclosed output opens the commitment on the same payload and opening, so the mismatch is the serve's and not the replayer's input. - NotReplayable(why): the engine samples; another backend, recipe or weights; another request; no commitment; or a mismatch nothing attributes. - The conformance pack is regenerated (the reference receipt gains the field; the envelope grows from 663 to 747 bytes). AR-1: output_hash, an optional field after input_hash, sealed only when bound (§2.3). It recommends a commitment over a plain hash and names mesh's output_commitment as one. The published AR-1 vectors regenerate byte-identical. Also: ar-verify's `len() % 2 == 0` becomes `is_multiple_of(2)`, a clippy error that predates this change, so the crate is clippy-clean. Tests: - mesh: the commitment binds request, opening, payload and tokens; a generation commits and a decision does not; deterministic replay verifies and locates a drift; replay refuses what it cannot settle, including a wrong payload with the honest output disclosed; a restarted steward reopens. - AR-1: output_hash sealed when bound and absent otherwise. - Mutation testing: 20 mutants, all killed (13, then 7 more after binding the payload; one of the 13 targets code since replaced). Verified on the build host: - mesh-rs: 94 tests plus 19 behind features; clippy and rustdoc clean. - jcp-rs: 565 tests and the conformance binary; jcp-action-receipt clippy-clean. - Repo checks pass. Co-Authored-By: Claude Opus 5.5 <[email protected]>