open-standards/jouleclaw/jouleclaw-rs/crates/jouleclaw-jcr1/docs/JCR-1-spec.md
Transaction Science 84768074ca
Some checks failed
energy meters on real hardware / RAPL and NVML on jetson-hub (push) Has been cancelled
energy meters on real hardware / sink decode table · RAPL on jetson-hub (NVML surveyed) (push) Has been cancelled
energy meters on real hardware / sink decode table · per-task energy and the GPU rail on macOS (push) Has been cancelled
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (push) Has been cancelled
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (push) Successful in 2m15s
wai-app and Create / wai-app · does this change touch it (push) Successful in 1m45s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Has been cancelled
joule-code conformance gate / Build + round-trip C1-C4 vectors (push) Successful in 5m43s
joule-code conformance gate / joule-moq-ingest, every target (push) Has been cancelled
joule-code conformance gate / joule-moq-relay, every target (push) Has been cancelled
Every text that states the IOReport liveness rule states it as the meters apply it
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]>
2026-11-07 08:20:02 -05:00

15 KiB
Raw Permalink Blame History

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

  1. Honesty over precision. A receipt MUST NOT claim accuracy finer than the worst energy counter in its span can deliver.
  2. 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.
  3. 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.
  4. 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 (NVML power.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_tier are unsigned.
  • Absent optional fields are omitted, not encoded as null.
  • Arrays preserve producer order (tools_touched, claims, tool_receipts, citations are 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 steward identity — a KERI AID (recommended; supports key rotation/witnessing) or a did:key. The verifier resolves kid → 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):

  1. Structural. Parse COSE_Sign1; parse payload as det-CBOR; reject unknown jc_receipt major versions; ignore unknown fields.
  2. Canonical re-encode. Recompute CORE from parsed fields; it MUST equal the payload bytes byte-for-byte.
  3. Envelope signature. Resolve kid → public key; verify the COSE_Sign1 signature over CORE.
  4. Tool receipts. For each tool_receipts[i], look up gateway_id's key and verify the HMAC (§5). A receipt asserting gateway-metered tools whose HMAC fails is invalid.
  5. Honesty consistency. Check energy_provenance equals the worst provenance across tools_touched[*].energy_provenance and tool_receipts[*]; check joules_uj ≥ Σ tools_touched.joules_uj; check the resolution floor (§2.3).
  6. (Optional) joule re-validation. If the verifier holds the conformance vector for this input_hash class, re-execute the cascade and confirm joules_uj falls 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_attributions are attested.
  • The worst-counter rule is the spec's spine: a system that quietly upgrades an Estimator span to HwShunt to 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.