The owner's decision, applied: a vendor energy counter (RAPL, NVML, IOReport) is a real reading, and what separates one such reading from another is provenance, not accuracy. This crate gave RAPL and NVML `HwShunt` and gave the IOReport counter `ModelBased`, on the reasoning that Apple's Energy Model is a vendor model. That reasoning grades accuracy. What the counter could not establish was provenance: on macOS 27.0.1 its CPU rails are frozen for an unprivileged reader, and that is now caught by the liveness probe. A counter that has passed it is as much a reading as RAPL is. The grade. `AppleIoReportCounter` declares `HwShunt`, and stamps it on every reading through one constant, `READING_GRADE`, shared by `provenance()` and `read()`. It earns the grade by being live: the counter exists to read only where `admits()` let it through (CPU rail `Live`), and a declined counter produces no reading to carry any grade, so a frozen host still meters through the load-average estimator at `Estimator`. The rule, written once and shared (jouleclaw SPEC §1.3, §9.4; JCR-1 §2.3; the crate docs; vendor-energy PROTOCOL/README): a vendor counter's reading 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 IOReport: the CPU rail itself, in at least 5 intervals, 4 of every 5, over at least 300 ms while the probing thread burns CPU). A counter present but not live 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. No partial reading from the GPU rail. Where the CPU rail is frozen but `GPU Energy` still advances (the M5 Max), the counter stays declined. The GPU rail is machine-wide: every GPU client on the host moves it, display compositing included, with nothing of the metered work running. It does not cover part of the work; it covers other work, so no coverage field makes it honest. The rationale is in the module docs and SPEC §1.3. Docs and data that said otherwise: - SPEC §1.3 table and floors, §9.4; JCR-1 §2.3 and the crate README (toy vectors become measurements only off counters that were live). - JCR-1 vector 6's description said "measured on Apple IOReport". Its joules are toy values like every vector's. Only the `description` changed; it sits outside the signed core, which `verify.py` builds from `receipt` alone. Both verifiers pass 10/10 after the edit: `verify.py` (cbor2 6.1.4, cryptography 50.0.2, exit 0) and the independent `verify.go` (exit 0). `git diff` of the file is that one line; a field-by-field JSON diff finds only (6, description). The conformance README's slot 6 line follows. - vendor-energy conformance: README row 27 names `AppleIoReportCounter` and the `HwShunt` grade, with the liveness condition a filled fixture must meet; `apple-silicon-ioreport.json` is an unsigned, empty stub (`signed_by` null, every workload not run, no hash of it anywhere), so its `impl` and `provenance` are corrected in place. - MEASURED_ENERGY.md: a dated note that the 74.1 J / 25.5 W row was committed 2026-06-12, predates macOS 27, and recorded neither chip nor OS. The "reads CPU/GPU/ANE/DRAM with no sudo" claim is replaced by what macOS 27.0.1 does: the counter opens without sudo, but the CPU rails are frozen (all 645 rails on the M3 Ultra), so those hosts are estimated. - local-index / rerank tier SHOULDs, the CLI's `meter` help, meter.rs, apple.rs, energy_probe, Cargo feature comments, harness-econ docs. - l3-jouleclaw README: it claimed `HwShunt` on RAPL/NVML hosts, but the binding builds jouleclaw-energy with `ioreport` only, so off Apple Silicon the receipt is the token estimate. It now says what happens on each host. - mesh-schema's `HwShunt` definition includes vendor counters subject to liveness; mesh-meter, the mesh README and mesh-engine-gguf no longer say real silicon alone yields `HwShunt`. - The Live-branch assertions in mesh-meter, l3-jouleclaw and jouledesk-github expected `ModelBased` for IOReport; they expect `HwShunt`. jouledesk-github's fixtures that paired `apple-ioreport` with `ModelBased` now pair it with `HwShunt`, and keep a `ModelBased` case under a neutral meter name. Tests. `a_live_counters_readings_are_graded_as_hardware_readings` builds a counter on `Live` directly. That opens the real all-channel subscription, which opens here even though the gate declines this host. It reads it twice and asserts each reading is `HwShunt` over `SocTotal`. On this M5 Max (macOS 27.0.1): "an admitted IOReport counter: opens=true, 2 readings, each graded HwShunt", so the read path is covered on a frozen host. With `--features "ioreport rapl"`, `a_live_ioreport_reading_has_the_grade_of_a_rapl_reading` compares the grade with `RaplCounter`'s own. The used/declined tests assert `HwShunt` in their live branch. This host still takes the declined branch: "ioreport declined (CpuRailFrozen): 154 ms of CPU work metered by `apple-silicon` as 6200000 µJ, provenance estimator". Run on this M5 Max: jouleclaw-energy 24+1+1 (default), 76 lib + 1 + 1 (`ioreport`), 79 lib (`ioreport rapl`); jouleclaw-jcr1 50; harness-econ 14; local-index 41; rerank 37; cli 10; mesh-meter (`hw-meter-apple`) 10; mesh-engine-gguf 1; l3-jouleclaw 2 + 4 (2 ignored, need a model); jouledesk-github 12. All pass. Falsified, each mutant restored with `git checkout` and the tree confirmed clean: - `READING_GRADE` set back to `ModelBased`: the new test fails at the declared grade (left: ModelBased, right: HwShunt), 75 passed / 1 failed. - Only `read()`'s stamp set back to `ModelBased` (the declared grade left at `HwShunt`): the new test fails on the reading itself, "a live counter's reading is not graded as a hardware reading" (ModelBased, SocTotal) vs (HwShunt, SocTotal), 75 / 1. The read path is what the test pins. Co-Authored-By: Claude Opus 5.5 <[email protected]>
77 lines
3.9 KiB
Markdown
77 lines
3.9 KiB
Markdown
# JCR-1 Conformance Vector Suite
|
||
|
||
A reference test suite for the **JouleClaw Receipt Spec (JCR-1)**. Ten signed
|
||
receipt vectors plus a standalone verifier. A second implementation in any
|
||
language is **vector-conformant** when it reproduces these results — which is the
|
||
gate that turns JCR-1 from "a format JouleClaw uses" into "a standard."
|
||
|
||
## Files
|
||
- `jcr1-vectors.json` — the 10 vectors. Each carries the receipt (JSON
|
||
projection), the deterministic-CBOR signed core (hex), and the COSE_Sign1
|
||
envelope (hex).
|
||
- `jcr1-test-keys.json` — the fixed Ed25519 keypair and gateway HMAC keys. **Test
|
||
material only**, published for reproducibility.
|
||
- `jcr1-verify.py` — standalone reference verifier. Depends only on `cbor2` and
|
||
`cryptography` (no JouleClaw code).
|
||
|
||
## Run
|
||
```
|
||
pip install cbor2 cryptography
|
||
python3 jcr1-verify.py jcr1-vectors.json jcr1-test-keys.json
|
||
```
|
||
Expected: `10/10 vectors verified`.
|
||
|
||
## What each vector exercises (JCR-1 7.3 slots)
|
||
1. **L0** cache hit — picojoule class, no tools.
|
||
2. **L1** deterministic primitive (arithmetic) — no model.
|
||
3. **L1** IaC/tool-only — a `terraform`-style describe closes the query, **zero
|
||
tokens**, with a gateway HMAC. (The spec's worked example.)
|
||
4. **L2** retrieval-grounded — claim provenance + a span citation.
|
||
5. **L3** local model — joule class, HwShunt GPU.
|
||
6. **L3** retrieval + model on a **ModelBased** span, mJ-floored (toy figures,
|
||
like every vector here: not an IOReport or any other reading).
|
||
7. **L4** remote frontier RPC — **Estimator** (remote energy unmeasurable).
|
||
8. **Mixed span** HwShunt + Estimator → worst-counter rule forces **Estimator**.
|
||
9. **Gateway HMAC** — two metered tool calls, both signed by `gw-edge-9`.
|
||
10. **Promoted skill** — same `input_hash` as vector 5, now closing at **L1 for
|
||
9 µJ** instead of 2.5 J. The turnover/“enzyme” claim, made checkable.
|
||
|
||
Vectors 5 and 10 share an `input_hash` on purpose: side by side they show one
|
||
query class collapsing from L3 (2,500,000 µJ) to L1 (9 µJ) after promotion — a
|
||
~270,000× drop on that class, the per-deployment decay loop in a single diff.
|
||
|
||
## What the verifier checks
|
||
1. **Re-encode determinism** — the signed core must re-serialize to identical
|
||
bytes (RFC 8949 §4.2.1 canonical CBOR).
|
||
2. **Envelope signature** — COSE_Sign1 (RFC 9052), EdDSA/Ed25519, `kid` = steward.
|
||
3. **Gateway HMACs** — each `tool_receipt` HMAC-SHA-256 recomputed from the
|
||
NUL-delimited canonical payload.
|
||
4. **Honesty consistency** — `energy_provenance` equals the worst counter in the
|
||
span; `joules_uj ≥ Σ tools_touched`; ModelBased/Estimator values respect the
|
||
1 mJ resolution floor.
|
||
|
||
## It has teeth (negative tests, all DETECTED)
|
||
- Understating `joules_uj` in the body → re-encode mismatch.
|
||
- Claiming `HwShunt` on an Estimator span → envelope payload mismatch (can't
|
||
forge without the steward key).
|
||
- Forging a tool-receipt joule count → re-encode mismatch / HMAC fail.
|
||
- One-bit tamper of the envelope → Ed25519 verification fail.
|
||
|
||
## Canonicalization note (clarifies JCR-1 §3.2)
|
||
The signed core uses **RFC 8949 §4.2.1 core deterministic encoding**: map keys
|
||
sorted length-first then bytewise on the encoded key (as `cbor2 canonical=True`
|
||
emits). A second implementation MUST match this ordering exactly, or step 1 fails.
|
||
This is the precise reading of §3.2 and should be folded into the spec as an
|
||
erratum.
|
||
|
||
## Conformance levels
|
||
- **Producer-conformant** — emits receipts whose signed core re-encodes
|
||
identically and whose provenance/resolution obey §2.3.
|
||
- **Verifier-conformant** — implements checks 1–4 above.
|
||
- **Vector-conformant standard** — an *independent* implementation verifies all
|
||
10 vectors here. That is the milestone that makes JCR-1 a standard rather than
|
||
a house format.
|
||
|
||
> Reminder from the strategy: a receipt proves **cost + provenance, not output
|
||
> correctness**. Pair JCR-1 with the calibrated escalation gate so the *answer*
|
||
> is trustworthy, not only the bill.
|