The meters count an IOReport interval only within three of the probe's ticks, and the texts that state the rule said nothing of it, so an implementation following any of them would call a lump-refreshed rail live once load stretched its intervals. Each now says what an interval is (from one sample in hand to the next), that only one no longer than three of the probe's ticks (75 ms at its 25 ms tick) counts, that a longer one counts as nothing (not among the intervals, not as an advance, not towards the 300 ms), and that the 300 ms is the summed length of the intervals that count. The normative clauses in arl/ARL-S.md, jcp/SPEC.md, joule-code/spec/receipt.md, joule-ui/SPEC.md, jouleclaw/SPEC.md, JCR-1-spec.md, map/spec/receipt.md, mesh/SPEC.md (a block quote), proof/SPEC.md and sense/SPEC.md; proof-schema's quotation of proof/SPEC.md's; jouleclaw-energy's conformance README; and the proof and sandbox READMEs, which say the cap is IOReport's alone. Map's and Joule Code's unreleased changelog entries, which record the rule as it was added, are amended, since neither release has gone out. No wire or conformance-vector change. Co-Authored-By: Claude Opus 5.5 <[email protected]>
15 KiB
JouleClaw Receipt Specification (JCR-1) — Draft
Status: Draft · Version: 1 (jc_receipt: "1") · License: CC-BY-4.0 (text), Apache-2.0 (vectors)
An open, implementation-independent format for a signed, per-resolution thermodynamic receipt: proof that a given output cost a given number of joules, on hardware of a stated measurement honesty, verifiable by a third party who never ran the cascade.
This document formalizes the jouleclaw-prov receipt shape and closes the gap
the reference crate leaves open: it defines (a) a canonical serialization, (b) a
dependency-free signed envelope, and (c) a verification flow — so conformance does
not depend on any JouleClaw code.
Key words MUST / SHOULD / MAY per RFC 2119.
1. Design invariants
- Honesty over precision. A receipt MUST NOT claim accuracy finer than the worst energy counter in its span can deliver.
- Determinism. The signed bytes MUST be reproducible bit-for-bit from the receipt fields. No field that cannot be canonically encoded may enter the signed core.
- Producer/verifier separation. A producer mints and signs; a verifier needs only this spec, the public key, and (for joule re-validation) the conformance vectors. Verification MUST NOT require re-running proprietary code.
- Additive evolution. Unknown fields MUST be ignored, never rejected. v1 only adds optional fields.
2. The Receipt object
Units are fixed: energy is microjoules as an unsigned 64-bit integer
(joules_uj); floating point is forbidden in the signed core. Timestamps are
RFC 3339 UTC. Hashes are lowercase hex BLAKE3-256. Tier tags are L0–L4.
2.1 Top-level fields
| Field | Type | Req | Meaning |
|---|---|---|---|
jc_receipt |
string | MUST | Schema version. "1" for this spec. |
id |
string | MUST | Stable receipt id, monotonic per steward. |
closed_at |
string (RFC3339) | MUST | When the cascade walk closed. |
input_hash |
string (blake3-hex) | MUST | BLAKE3 of the normalized input that started the walk. |
tier |
enum L0..L4 |
MUST | Tier that closed the query. |
joules_uj |
u64 | MUST | Total microjoules across all tiers walked. |
energy_provenance |
enum | MUST | Honesty tier of the worst counter in the span (§2.3). |
steward |
string | MUST¹ | Signing identity (KERI AID or did:key). Binds receipt to issuer. |
tools_touched |
array⟨ToolTouch⟩ | MAY | Per-tool energy, in call order. |
claims |
array⟨ClaimProvenance⟩ | MAY | Sources that grounded the resolution. Empty for L0/L1. |
tool_receipts |
array⟨ToolReceipt⟩ | MAY | Gateway-HMAC'd attestations (§2.6). |
eoc_stage |
string | MAY | EOC cascade stage label, if driven by one. |
citations |
array⟨Citation⟩ | MAY | Span→source grounding (advisory). |
token_attributions |
array⟨TokenAttribution⟩ | MAY | Per-token saliency (advisory, not in signed core — §3.3). |
¹ steward is added by this spec; the reference crate carried the issuer in the
outer Smart Byte envelope. Carrying it inline makes the receipt self-describing.
2.2 CascadeTier
L0 Cache (picojoules) · L1 Lawful/deterministic (nanojoules) · L2 Embed
(sub-mJ) · L3 Model (joules) · L4 Wire/remote frontier (tens of J+). Wire tags
L0–L4 are stable across versions.
2.3 Provenance (the honesty tag) — normative
Every energy reading carries one of:
HwShunt— hardware reading: a shunt (Jetson INA3221), or a vendor energy counter (x86 RAPL MSR, NVIDIA cumulative-energy counter, Apple IOReport) while it is live for the domain it claims (below). Honest to the counter's resolution.ModelBased— vendor model estimate from freq/voltage/utilization (NVMLpower.draw, ROCm SMI). Millijoule-quantized at best.Estimator— JouleClaw static cost model. Wide tolerance by construction.
A vendor energy counter's reading is a real reading; the trust gap is
provenance (which counter, which domain, whether it was live), not accuracy.
Hence a live vendor counter is HwShunt, under this condition:
Liveness (MUST): A reading from a vendor energy counter (RAPL, NVML, Apple
IOReport, …) MAY be graded as a hardware reading only while the counter is
demonstrably live for the domain the figure claims: the implementation MUST have
observed the counter covering that domain advance under load (for Apple IOReport:
the CPU energy rail itself advancing in at least 5 sample intervals, in at least
4 of every 5, over at least 300 ms while the probing thread burns CPU; an interval
runs from when one sample is in hand to when the next is, and only one no longer
than three of the probe's ticks, 75 ms at its 25 ms tick, counts: a longer one
counts as nothing, neither among the intervals, nor as an advance, nor towards
the 300 ms, which is the summed length of the intervals that count). A counter
that is present but not live — frozen, or republished in lumps — MUST NOT produce
a hardware-graded figure; the implementation falls back to its estimator or
reports the work unmetered, and SHOULD record why. A figure MUST NOT claim
coverage of a domain its counter does not read; where the format has a coverage
field, such a figure is Partial. (JCR-1 v1 has no coverage field: a figure for a
domain its counter does not read is not a HwShunt figure for that work at all.)
Apple IOReport's GPU rail is machine-wide (display compositing moves it with
nothing of the metered work running), so it is not a partial reading of CPU work:
where only the GPU rail is live, the reference implementation declines the
counter and the CPU work is graded Estimator.
Worst-counter rule (MUST): Receipt.energy_provenance = the least-honest
provenance among all readings contributing to joules_uj, ordered
HwShunt > ModelBased > Estimator. A receipt whose span mixed a HwShunt GPU read
and an Estimator NPU read MUST report Estimator.
Resolution floor (MUST): joules_uj MUST NOT be reported at finer resolution
than the worst counter's resolution_uj. For ModelBased/Estimator the
realistic floor is ~1000 µJ (1 mJ); values SHOULD be rounded to that quantum and
the receipt MUST NOT imply sub-mJ precision it cannot support.
2.4 ClaimProvenance
source (string: URL/DOI/did) · content_hash (blake3-hex of claim bytes at
fetch) · fetched_at (RFC3339) · trust_tier (u8, higher = more trusted).
PROV-O mapping: each claim is a prov:Entity; source is the IRI, content_hash
the wasGeneratedBy fingerprint.
2.5 ToolTouch
tool_id (string, e.g. mcp:filesystem/read, iac:fs.read,
model:gemma4-9b-q5_k_m) · joules_uj (u64) · energy_provenance (enum).
2.6 ToolReceipt (gateway-attested)
Proves a tool was invoked through the gateway, not asserted by the model.
tool_id · joules_uj · energy_provenance · minted_at (RFC3339) ·
gateway_id (string) · hmac_sha256_hex (64 hex chars).
The HMAC (§5) is keyed by a gateway secret the model never holds.
2.7 Citation / TokenAttribution
Citation: text_span {start:u32, end:u32} (half-open byte range over the
output the consumer holds) · source_chunk_id · exact_quote (verbatim,
findable in the chunk).
TokenAttribution: token_idx:u32 · chunk_scores: map<string,float>
(provider-defined, ordinal not absolute) · optional method. Advisory only.
3. Canonicalization (the signed core)
3.1 Signed core vs advisory
The signed core is every MUST/MAY field in §2.1 except token_attributions
(provider-defined floats, ordinal, not reproducible across methods). citations
are in the core (strings/ints, deterministic, and grounding-relevant).
token_attributions are carried alongside, outside the signature.
3.2 Canonical encoding
The signed core MUST be encoded as deterministic CBOR per RFC 8949 §4.2:
- Map keys are the field names as text strings, sorted by byte-wise lexicographic order of the UTF-8 key.
- Integers use the shortest form;
joules_uj,start,end,token_idx,trust_tierare unsigned. - Absent optional fields are omitted, not encoded as null.
- Arrays preserve producer order (
tools_touched,claims,tool_receipts,citationsare order-significant). - No floats appear in the signed core (see §3.1).
A JSON projection (RFC 8785 JCS) MAY accompany the CBOR for debugging, but the signature is ALWAYS over the deterministic CBOR bytes.
3.3 The bytes to sign
CORE = det_cbor(signed_core_fields). The envelope signature (§4) is computed
over CORE. Recomputing CORE from the parsed fields MUST yield identical bytes;
a verifier that cannot reproduce CORE MUST treat the receipt as invalid.
4. The signed envelope
Receipts are sealed in a COSE_Sign1 structure (RFC 9052) so they interoperate with the RATS/CoRIM attestation tooling JouleClaw already uses.
COSE_Sign1 = [
protected: bstr .cbor { 1: alg, 4: kid }, ; alg = -8 (EdDSA) or -7 (ES256)
unprotected: { },
payload: bstr, ; = CORE (det-CBOR signed core)
signature: bstr ; over Sig_structure per RFC 9052
]
- alg (MUST): EdDSA/Ed25519 (
-8) is the default; ES256 (-7) permitted. - kid (MUST): the
stewardidentity — a KERI AID (recommended; supports key rotation/witnessing) or adid:key. The verifier resolveskid→ public key out of band. - payload: the deterministic-CBOR signed core (§3.3).
Key management is explicitly out of scope. KERI AID rotation is the RECOMMENDED
substrate; any resolvable kid → public key mapping conforms.
5. Tool-receipt HMAC (sub-signatures)
Each ToolReceipt.hmac_sha256_hex is HMAC-SHA-256(gateway_key, payload),
lowercase hex, where payload is the NUL-delimited canonical byte string:
tool_id ‖ 0x00 ‖ ascii(joules_uj) ‖ 0x00 ‖ prov_tag ‖ 0x00 ‖ minted_at ‖ 0x00 ‖ gateway_id
prov_tag ∈ {HwShunt,ModelBased,Estimator}; joules_uj as decimal ASCII.
Verifiers look up the gateway key by gateway_id and recompute. Comparison MUST
be constant-time. This sub-signature is independent of the envelope: it survives
replay into a different context, attesting the gateway — not the model — observed
the cost.
6. Verification flow
A verifier processes a received envelope in this order; failure at any step makes the receipt invalid (steps 1–4) or unverified-but-structurally-valid (step 5, when vectors are unavailable):
- Structural. Parse COSE_Sign1; parse payload as det-CBOR; reject unknown
jc_receiptmajor versions; ignore unknown fields. - Canonical re-encode. Recompute
COREfrom parsed fields; it MUST equal the payload bytes byte-for-byte. - Envelope signature. Resolve
kid → public key; verify the COSE_Sign1 signature overCORE. - Tool receipts. For each
tool_receipts[i], look upgateway_id's key and verify the HMAC (§5). A receipt asserting gateway-metered tools whose HMAC fails is invalid. - Honesty consistency. Check
energy_provenanceequals the worst provenance acrosstools_touched[*].energy_provenanceandtool_receipts[*]; checkjoules_uj ≥ Σ tools_touched.joules_uj; check the resolution floor (§2.3). - (Optional) joule re-validation. If the verifier holds the conformance
vector for this
input_hashclass, re-execute the cascade and confirmjoules_ujfalls within the drift band for the receipt's provenance tier (§7). Absent vectors, the receipt is signature-valid but joule-unverified.
7. Conformance
7.1 Drift bands (joule re-validation tolerance)
Re-execution will not reproduce joules exactly; the permitted band scales with honesty:
| Provenance | Drift band on joules_uj |
|---|---|
HwShunt |
±10% |
ModelBased |
±35% |
Estimator |
±100% (order-of-magnitude only) |
(Bands are the v1 defaults and are themselves part of the conformance vector; publish measured bands as data accrues rather than asserting these forever.)
7.2 Conformance levels
- Producer-conformant: emits receipts whose signed core re-encodes
identically (§3) and whose
energy_provenance/resolution obey §2.3. - Verifier-conformant: implements steps 1–5 and reproduces published vectors.
- Vector-conformant standard: an independent implementation round-trips all 10 published conformance vectors (verify + re-encode), proving the spec — not the reference code — is the source of truth.
7.3 Vector slots (to populate + sign)
1 L0 cache hit · 2 L1 deterministic (no model) · 3 L1 IaC/tool-only · 4 L2 retrieval-grounded · 5 L3 local model · 6 L3 with citations · 7 L4 wire with claims · 8 mixed-span worst-counter (HwShunt+Estimator → Estimator) · 9 gateway tool-receipt HMAC · 10 promoted-skill (L3-derived → L1 cost). (Reference repo currently ships 3 of 10 — the gating work for "standard" status.)
8. Versioning & extensibility
jc_receipt is the schema major. Within "1", only optional fields are added,
guarded so older verifiers ignore them. A breaking change increments to "2";
verifiers reject unknown majors at step 1. The L0–L4 tags and field semantics
in §2 are frozen for v1.
9. Security & honesty considerations
- A receipt proves cost + provenance, not output correctness. Pair with the calibrated escalation gate so the answer is trustworthy, not just the bill.
- The signed core deliberately excludes advisory floats; do not infer that
token_attributionsare attested. - The worst-counter rule is the spec's spine: a system that quietly upgrades an
Estimatorspan toHwShuntto look precise is non-conformant and defeats the entire purpose. Honest meters are the whole product. - HMAC keys are per-gateway secrets; envelope keys are per-steward. Compromise of one does not forge the other.
10. Worked example (JSON projection; signature over det-CBOR of the core)
{
"jc_receipt": "1",
"id": "rcpt-000128",
"closed_at": "2026-05-31T18:04:22Z",
"input_hash": "b3:9f2c...e1",
"tier": "L1",
"joules_uj": 4200,
"energy_provenance": "HwShunt",
"steward": "did:keri:EJ9...",
"tools_touched": [
{ "tool_id": "iac:aws.ec2.describe", "joules_uj": 4200, "energy_provenance": "HwShunt" }
],
"claims": [],
"tool_receipts": [
{
"tool_id": "iac:aws.ec2.describe", "joules_uj": 4200,
"energy_provenance": "HwShunt", "minted_at": "2026-05-31T18:04:22Z",
"gateway_id": "gw-edge-7", "hmac_sha256_hex": "3f1a...c0"
}
]
}
A deterministic motif (an IaC describe call) closed the query at L1 for 4.2 mJ, HwShunt-honest, with a gateway HMAC proving the gateway — not a model — ran it. No tokens burned; the receipt proves it.