open-standards/joule-code/SPEC.md
Transaction Science fca3f76e51 specs: a vendor counter is a hardware reading only while it is demonstrably live
The monorepo's IOReport energy backends now decline unless the CPU energy
rail keeps advancing: on macOS 27 an unprivileged reader sees the CPU rails
frozen or republished only in rare lumps, so a meter that trusted a present
counter reported CPU work as GPU-only energy, or as zero, while tagging it a
reading. The owner's decision is that a vendor energy counter is a real
reading (the trust gap is provenance, not accuracy), so a LIVE reading is
graded as a hardware reading, and every spec that grades vendor counters now
carries the same rule:

  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). 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.

Joule Code
- spec/receipt.md §2 (REQUIRED): HwShunt now reads "an external shunt, or a
  vendor energy counter (RAPL, NVML, Apple SMC/IOReport) while that counter
  is live"; the rule above is added verbatim, and in this receipt the
  hardware grade is a present measured_uj and the HwShunt tag, so a counter
  that is not live supplies neither. The §1 comment and §5 say "live".
- SPEC.md §6: the provenance definition now names IOReport and NVML beside
  RAPL/SMC, measured_uj comes only from an interface live for the domain it
  claims, and a paragraph states the MAY/MUST NOT, pointing to receipt.md §2
  for the test. The §9 readiness row says "live" and "not live".
- ROADMAP.md v0.2 "Measured energy": a vendor counter feeds the HwShunt path
  only while live; where it is present but not live (IOReport's CPU rails to
  an unprivileged reader on macOS 27) the receipt stays on the estimator.
- examples/l3-jouleclaw/README.md: the claim that the receipt is "a real
  local measurement ... (HwShunt on RAPL/NVML hosts; Estimator on Apple
  Silicon until IOReport is wired)" was wrong both ways: run.rs wires only
  Apple Silicon's counter, and other hosts fall to the token Estimator. It
  now says so, that the counter's own tag is carried, and that HwShunt needs
  a live counter.
- joule-code-receipt: the Provenance::HwShunt doc comment says the same.
- CHANGELOG.md [Unreleased] ### Changed: the rule; no wire or vector change.

Sense
- SPEC.md §7 (REQUIRED): measured_uj comes only from a live interface; the
  rule is added verbatim. The Sandbox PowerMeter was described as "(real
  RAPL/IOReport)"; it is now described as grading a reading HwShunt only
  while its counter is live and falling back to its estimator otherwise,
  which is what origin/sandbox-meter/cpu-rail-liveness implements. §10's
  Sandbox edge says the same in brief.
- sense-schema: the HwShunt, Energy and Energy::measured doc comments say a
  vendor counter is a hardware reading only while live.
- Sense keeps no CHANGELOG, so none is added.

Other specs that grade vendor counters
- map/spec/receipt.md §2: the HwShunt row read "RAPL/SMC/shunt"; it now
  names a counter "while it is live", and the rule is added verbatim, noting
  that Receipt::seal cannot check liveness (the meter's duty, upstream).
  map/SPEC.md §6 states the MUST NOT and points there. CHANGELOG.md gains an
  [Unreleased] ### Changed entry; no wire or vector change.
- arl/ARL-S.md, Telemetry: physical telemetry is what gates tiers above 0,
  and it said energy is "measured directly via RAPL ... NVML". The rule is
  added in ARL-S's own terms and lower-case keywords (ARL uses no RFC 2119
  capitals): a counter that is not live does not produce physical telemetry,
  the energy it would have covered is reported unmetered, and the Supervisor
  must have observed the counter advance. No version bump.
- smart-byte treatise §8.6: "Where RAPL or equivalent hardware energy
  counters are available, the measurement is read from the hardware" now
  requires the counter to be demonstrably live, and a frozen or lump-
  republished counter yields the same honest zero as an absent one.

Text and doc comments only: no code path, wire format, or conformance
vector changes. joule-code-rs (joule-code-receipt, joule-code-conformance)
and sense-rs (sense-schema, sense-conformance) build and test clean, their
rustdoc builds under -D warnings, map-rs (map-receipt, map-conformance)
tests pass, `joule-code-conformance verify ../conformance/v1` passes
24/0/0, the no-vanity-metrics check passes, and every relative link in the
changed Markdown resolves.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 01:10:36 -04:00

159 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Joule Code v0.2 — Energy-Attributed Federated Coding Operations
Status: **Draft Standard**. Reference implementation: [`joule-code-rs/`](joule-code-rs/) (Rust workspace, Apache-2.0). Specification text: CC-BY-4.0.
The keywords **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **SHOULD**, **SHOULD NOT**, **MAY**, and **OPTIONAL** are to be interpreted as described in RFC 2119.
---
## 1. Scope and doctrine
Joule Code specifies how a **coding operation** — a unit of agentic change to a source tree — is identified, authorized, resolved through an energy-tiered cascade, and reported with its energy cost. It is the coding cargo class of the Transaction Science substrate.
The **doctrine** is one sentence: *capability per joule, not capability per token*. Two normative consequences follow.
### 1.1 The cascade (REQUIRED)
A conforming runtime **MUST** dispatch every coding request through an explicit energy-tiered cascade and **MUST** stop at the first tier that closes the request. The tiers are inherited from JouleClaw:
| Tier | Wire tag | Named tag | Joule class | What it is for a coding request |
|------|----------|-----------|----------------|------------------------------------------------------------------|
| L0 | `L0` | Cache | picojoules | content-addressed cache hit (identical request → identical op) |
| L1 | `L1` | Lawful | nanojoules | deterministic primitive (rename, format, mechanical refactor) |
| L2 | `L2` | Embed | sub-millijoules| embedding + hybrid retrieval (symbol/snippet lookup, recall) |
| L3 | `L3` | Model | joules | local model (SSM / ternary / open-weight, e.g. vLLM) |
| L4 | `L4` | Wire | tens of joules | remote frontier coding agent over ACP (escape hatch) |
A runtime **MUST NOT** invoke a higher tier when a lower tier closes the request. A runtime **MAY** omit any tier it does not implement, but **MUST** record in the receipt the tier that actually closed the request.
### 1.2 The receipt (REQUIRED)
Every coding operation **MUST** carry a receipt reporting its energy cost as a two-part record (`measured + estimated`, §6), and **MUST** tag every reading with a `Provenance` value. A runtime **MUST NOT** report a `measured` figure it did not obtain from a hardware energy interface. Where no hardware interface is available, the `measured` field **MUST** be absent and the `estimated` field **MUST** carry the figure with `Provenance: Estimator` or `Provenance: ModelBased`.
### 1.3 No capture (REQUIRED)
The protocol carries **no token**. A conforming endpoint **MUST** perform its core function (resolve a coding operation, emit a receipt) without contacting any single steward's servers as a condition of operation. Where a tier requires a remote frontier agent (L4), the credential to that agent **MUST** reside in the vendor's own client (e.g. a logged-in CLI driven over ACP) and **MUST NOT** be transported by the Joule Code protocol.
---
## 2. The coding operation (cargo)
A **coding operation** is a signed transition that transforms a source tree from a prior state to a successor state. Its normative type is in [`spec/cargo.md`](spec/cargo.md); this section fixes the wire-load-bearing fields.
A `CodingOp` **MUST** contain:
- `prior` — the content address (§3) of the tree state the operation builds on. Binds the operation to exactly one base.
- `edits` — an ordered, non-empty list of `Edit`s. Each `Edit` names a `path`, an `anchor` (a byte range or a content-addressed hunk), and a `replacement`.
- `author` — the Ed25519 verifying key (32 bytes) that authorizes the operation.
- `intent` — a UTF-8 string describing the request that produced the operation. Advisory; not load-bearing for identity beyond being part of the canonical form.
- `tier` — the cascade tier that closed the request (§1.1).
A `SignedOp` is a `CodingOp` plus a `signature`. The signature preimage **MUST** be `op_id ‖ prior` (§3, §4), so a signature is scoped to exactly one operation on exactly one base and cannot be replayed onto a different base. The schema **MUST** carry a one-byte algorithm identifier (`0x01` = Ed25519, RFC 8032) so a post-quantum successor can be introduced without a flag-day migration.
---
## 3. Identity and content addressing
Every load-bearing object (`CodingOp`, tree state, receipt) is identified by the **content address** of its canonical serialization (§4): `id = BLAKE3-256(canonical_bytes)`, rendered as unpadded base64url. Identity is independently computable by any party; no central authority assigns it.
The `op_id` of a `CodingOp` is the content address of its canonical form **excluding** the signature. The signature therefore binds the `op_id`, not the other way round.
---
## 4. Canonical serialization
The canonical form is **deterministic CBOR** (RFC 8949 §4.2 core deterministic encoding): map keys are sorted, shortest-form integers, no indefinite-length items. A conforming implementation **MUST** produce byte-identical canonical encodings for equal objects across platforms. Floats **MUST NOT** appear in any canonical form or decision path; energy figures are integer microjoules.
---
## 5. The cascade binding
A `Cascade` is an ordered list of `Stage`s, one per implemented tier. Each `Stage` exposes `try_resolve(request) -> Option<Resolution>`. The runtime calls stages in tier order and returns the first `Some`. A `Resolution` carries the produced `CodingOp` (or a non-mutating answer) and a `Receipt` (§6). The trait surface is normative in [`spec/cascade.md`](spec/cascade.md); the **agent schema** that implements L1–L4 is [JouleClaw](../jouleclaw/).
L4 stages bind to remote frontier coding agents over the **Agent Client Protocol (ACP)**. The Joule Code runtime is an ACP client; the frontier agent is an ACP server launched by the vendor's own CLI. The runtime **MUST** treat token usage reported by the ACP agent as input to the receipt's `estimated` energy (§6) when no measured figure is available.
### 5.1 Grant-gated consultation (OPTIONAL)
A deployment **MAY** gate the cascade behind a [JCP](../jcp/) delegation chain, turning "cheapest sufficient tier" into "cheapest sufficient **and authorized** tier". When it does, the binding is:
- **Tier as action.** Each tier is a JCP action verb (`l0`…`l4`). A stage is consulted only if the chain's leaf grant names its verb; in particular, a chain that does not name `l4` can never reach a remote frontier agent — structurally, not by policy prose.
- **Energy as budget.** Each consultation debits the tier's attempt cost from **every** link of the chain before the stage runs. The reference per-tier costs are the §1.1 class markers in µJ (`l0`=1, `l1`=10, `l2`=10³, `l3`=10⁶, `l4`=10⁷), tagged honest `Estimator`; a deployment with a meter substitutes measured figures.
- **Denial as fallthrough.** A denied tier behaves exactly as a tier that could not close: the cascade falls through. A request whose only closing tier is denied resolves to nothing rather than overspending.
- **Every consultation seals.** Allow and deny alike seal as chained JCR-1 receipts carrying the full grant-id chain and, on deny, the machine-readable reason (`action-not-granted`, `budget-exceeded`, …).
The reference binding is the `joule-code-jcp` crate (`JcpGate::wrap` over any `Stage`). Conformance class **C5** (§8) exercises this binding against the published vectors.
### 5.2 Contracted operations (OPTIONAL)
A deployment MAY run coding operations under a **JouleContract** (the sibling contract standard), turning the operation's implicit promises into a five-obligation contract with a signed receipt. When it does, the binding is field-for-field, not analogical:
- **The edit set is the frame.** The contract's declared mutable footprint is a path set; every `Edit.path` MUST fall within it. An out-of-frame edit is an out-of-frame effect — caught at the boundary, and recorded as an `undischarged` frame naming the offending path rather than suppressed (a breach recorded honestly beats a breach driven underground).
- **The tier cost is the ceiling.** The cascade's per-tier joule class prices the contract's EnPI ceiling; an overrun is a recorded deviation (negative residual), never a block — receipt-time enforcement, amend-or-fix resolution.
- **Provenance maps downward only.** `HwShunt` → `Metered` (with a meter binding), `ModelBased` → `ModelBased` (with a calibration anchor), `Estimator` → `Unaccounted`. The binding can never promote an energy category.
- **Receipts grade honestly.** The binding emits receipts that pass JouleContract's receipt-local validation (at most JR-2 under its two-stage rule); composing to JR-3+ with sealed evidence, a key log, and anchored intervals is the deployment's verifier-of-record work.
The reference binding is the `joule-code-joulecontract` crate (`contract_for_op` / `frame_check` / `Binder::receipt_for_op`).
---
## 6. The receipt (JCR-1)
A `Receipt` accounts for one coding operation and **MUST** carry:
- `op_id` — the operation it accounts for (§3).
- `tier` — the tier that closed the request (§1.1).
- `energy` — a record `{ measured_uj: Option<u64>, estimated_uj: u64, provenance: Provenance }`. `measured_uj` is present only when obtained from a hardware energy interface that is live for the domain the figure claims. `estimated_uj` is always present.
- `provenance` — one of `HwShunt` (read from a hardware energy interface: an external shunt, or a vendor energy counter — RAPL, NVML, Apple SMC/IOReport — while it is live), `ModelBased` (computed from a calibrated per-operation model), `Estimator` (a coarse constant estimator). A reading tagged `HwShunt` **MUST** correspond to a present `measured_uj`; a reading tagged `Estimator` **MUST NOT** carry one.
- `sequence`, `nonce` — monotonic sequence and per-receipt nonce.
A reading from a vendor energy counter (RAPL, NVML, Apple IOReport, ...) **MAY** be tagged `HwShunt` only while the counter is demonstrably live for the domain the figure claims — observed advancing under load, by the test in [`spec/receipt.md`](spec/receipt.md) §2. A counter that is present but not live — frozen, or republished in lumps — **MUST NOT** supply an `HwShunt` tag or a `measured_uj`; the reading falls back to the estimator, and a figure **MUST NOT** claim coverage of a domain its counter does not read.
### 6.1 Signed form (JCR-1)
The receipt's signed, on-the-wire form is a **JCR-1 envelope** — the signed-receipt format shared across the Transaction Science family. As of **v0.2** Joule Code adopts JCR-1 rather than a bespoke preimage, so a Joule Code receipt verifies under the family's existing JCR-1 tooling (and its cross-language Python/Go verifiers).
- **Canonical core.** The signed bytes are the canonical det-CBOR (RFC 8949 §4.2.1, **length-first** key order, shortest-form integers, no floats/bools/nulls) of the `joule-code/1` profile of the JCR-1 wire object: `{ jc_receipt: "joule-code/1", op_id, tier (the wire tag "L0".."L4"), estimated_uj, measured_uj (only when present), energy_provenance ("HwShunt"|"ModelBased"|"Estimator"), sequence, nonce (lowercase hex), steward }`. Null-valued fields are dropped from the core.
- **Envelope.** A **COSE_Sign1** envelope (RFC 9052), **EdDSA / Ed25519, `alg = -8`** only, over the canonical core. The endpoint identity is carried in the COSE `kid` (the `steward`). A verifier **MUST** reject any other `alg`, a `kid` other than the expected steward, and signature failure.
The estimator of last resort (when only token counts are available, e.g. from an L4 ACP agent) computes `estimated_uj` from per-token coefficients and **MUST** tag the reading `Estimator`. Reference coefficients are non-normative and live in [`spec/receipt.md`](spec/receipt.md).
---
## 7. Federated collaboration (Research)
Multiple endpoints **MAY** collaborate on a shared tree by replicating coding operations. When they do, an operation is structurally a [Smart Byte](../smart-byte/) envelope whose cargo is the `CodingOp`, replicated by lockstep deterministic simulation with BFT supermajority commit among a known, signed-membership cluster; session and transport bind to CommunicationOS (MLS group state, FROST threshold signing, MoQT presence). This binding is specified at the interface level only in [`spec/collab.md`](spec/collab.md) and is classified **Research** (§9). v0.1 conformance does **not** require it; a single-endpoint runtime is fully conformant.
---
## 8. Conformance
A Joule Code implementation is **conformant** if it round-trips the published wire vectors in [`conformance/v1/`](conformance/v1/) (the vector pack is per spec major version; v0.x share pack `v1`):
- **C1 — content addressing.** Reproduce the `op_id` for each vector in `coding_op_vectors.json` from its canonical CBOR.
- **C2 — signing.** Verify (and, given the seed, reproduce) each signature in `signature_vectors.json`; reject every negative vector (wrong base, tampered edits).
- **C3 — receipt.** Verify each receipt's JCR-1 COSE_Sign1 envelope in `receipt_vectors.json` against the steward + endpoint key, confirm its payload is the receipt's canonical signed core, and honor the `Provenance`/`measured_uj` coupling in §6; reject every negative vector.
- **C4 — cascade.** Given the scripted stage outcomes in `cascade_vectors.json`, select the same closing tier as each vector (stop-at-first-close).
- **C5 — gated cascade** *(only for implementations claiming §5.1)*. Given the grants, budgets, and scripted stage outcomes in `gated_cascade_vectors.json`, reproduce each vector's closing tiers, total debit, and the sealed receipt verdict sequence (deny reasons included). The fixture identities and per-tier costs are fixed in the vector pack so runs are deterministic end to end.
Reference implementations are conformant by construction. Third-party implementations certify themselves by running the public suite.
---
## 9. Readiness classification
Per the family discipline, each part is classified and the classification is respected when sequencing work:
| Part | Class | Note |
|---|---|---|
| §2 cargo, §3 identity, §4 canonical form | **Solid** | content addressing + deterministic CBOR are well-trodden |
| §6 receipt (`estimated`, `Estimator`) | **Solid** | the meter exists in the reference consumer today |
| §6 receipt (`measured`, `HwShunt`/`ModelBased`) | **Engineering** | requires a hardware energy interface that is live for the domain it claims; honest absence when unavailable or not live |
| §1.1/§5 cascade binding | **Engineering** | the agent schema (JouleClaw) exists; binding L0–L4 to coding requests is real integration work |
| §5.1 grant-gated consultation | **Solid** | the JCP runtime and chained receipts exist today; the binding is composition, exercised by C5 |
| §7 federated collaboration | **Research** | interface-level only in v0.1; not required for conformance |
---
## 10. Versioning
Joule Code versions independently of its sibling standards. Release tags follow `joule-code-vX.Y.Z` (current: `joule-code-v0.2.0`). A change here does not bump the others. Conformance vector packs are per-spec-major-version (`conformance/v1/`, ...); historical packs are never removed.