open-standards/jouleclaw/SPEC.md
Transaction Science 04086d2e38
All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
wai-quantum WebGPU member / does this change touch it (pull_request) Successful in 8s
energy meters on real hardware / RAPL and NVML on jetson-hub (pull_request) Successful in 41s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 52s
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 1m11s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 1m31s
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Successful in 2m15s
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Successful in 3m20s
wai-quantum WebGPU member / member · integrated GPU, Vulkan (framework-128gb) (pull_request) Successful in 7m22s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 8m24s
wai-quantum WebGPU member / member · DX12 and Vulkan (cbio-windows) (pull_request) Successful in 12m15s
wai-quantum WebGPU member / member · discrete GPU, Vulkan (jetson-hub) (pull_request) Successful in 18m16s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 13m56s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 6m34s
wai-quantum WebGPU member / member · Metal (macos) (pull_request) Successful in 5m7s
wai-quantum WebGPU member / member · browser WebGPU (macos) (pull_request) Successful in 3m10s
jouleclaw: bound a GPU energy counter from below, not only above
`GpuPlausibility` judged an NVML cumulative-energy counter against the board's
own telemetry in one direction only. Its three verdicts were `Plausible`,
`CounterOverRate` ("ran faster than the board can draw") and
`BoardTelemetryUnusable`. Nothing caught a counter reading **low**.

That is the wrong direction to guard. By this family's own doctrine (jcp/SPEC
§5): "Under-reporting is the unsafe direction at a ceiling, because it admits
work the budget cannot cover." A counter running fast fails safe — it spends a
budget sooner. A counter reading low is graded `HwShunt` and then spends an
energy ceiling it is not measuring. jouleclaw/SPEC §1.3 already refused a
counter "republished in lumps", but nothing implemented it: such a counter
*advances*, so the sustained-advance liveness probe calls it live while it
accrues a fraction of the energy.

`CounterUnderRate` closes it, bounded by the **same** board telemetry the
ceiling bound already uses, so no threshold is invented:

    floor = (mean_usable_draw - GPU_DRAW_SLACK_MW) / GPU_UNDER_FACTOR

The slack comes off the draw *before* the division, so the floor collapses to
zero at or below 5 W of mean draw: on an idle board a correct counter accrues
almost nothing, and refuting it would be noise rather than a finding. The
factor is deliberately looser than `GPU_DRAW_FACTOR` because the draw readings
are one-second averages, so a bursty load idle between samples really does
integrate to less than its sampled mean. The verdict carries the yardstick it
was judged against, so the judgement can be re-made against a different factor.

It ranks **above** a proven overrun: both refute, but only this one admits work
a budget cannot cover, so where one GPU of a probe over-reports and another
under-reports, the under-report is what an operator must act on. Among two
under-reporting GPUs the ordering is by shortfall, not by rate.

Two things found while doing it, beyond the reported gap:

- **`_ => CounterLiveness::Live` in the verdict mapping** meant a newly added
  verdict would silently become *live* — and "unrecognised verdict is
  admissible" is the unsafe default. That match is now exhaustive, so a future
  arm must be graded deliberately or the crate does not compile.
- **The wiring was untested.** The existing test covered
  `plausible_gpu_counter` and the over-rate path through `GpuWatch::liveness`,
  but a verdict that never reaches `CounterLiveness` changes nothing. Added a
  test driving an under-reporting GPU through the probe, whose discriminating
  half is the *same slow counter beside an idle board* — which must stay live,
  because nothing about the counter changed, only the yardstick.

`mode_for` needed no change: `Implausible` already falls back to the vendor
power integral and grades `ModelBased`, so the fix completes itself once the
verdict exists and maps. SPEC §1.3 now states the bound is two-sided, that it
refutes and never verifies, that an indeterminate is not hardware-graded, and
that it must not fire near idle. Doc comments that described the bound as
one-directional are corrected.

Figures throughout are the jetson-hub RTX 4050's own, as the existing test's
already are.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-19 20:26:38 -04:00

59 KiB
Raw Permalink Blame History

JouleClaw v1 — Energy-Optimised AI Runtime

Status: Draft Standard. Reference implementation: jouleclaw-rs/ (Rust workspace, Apache-2.0). Spec text: CC-BY-4.0.

Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119.


1. Scope and doctrine

JouleClaw is a runtime + harness + agentic-layer standard for energy-optimised AI. It applies to:

  • text and code generation (LLMs, SSMs, state-space hybrids)
  • multimodal understanding and generation (vision, audio, video, 3D)
  • diffusion-based image / video synthesis (DDPM / LCM / Euler / Heun / DPM++ / CFG++ / Rectified Flow and friends)
  • speech recognition (Whisper-class)
  • the developer-facing harness that drives the above

The doctrine is one sentence: capability per joule, not capability per parameter.

Three normative consequences follow from the doctrine.

1.1 The cascade

A conforming runtime MUST dispatch every resolution through an explicit energy-tiered cascade and MUST stop at the first tier that closes the query. The tiers are:

Tier Wire tag Named tag Joule class What it is
L0 L0 Cache picojoules content-addressed cache hit
L1 L1 Lawful nanojoules deterministic primitive (text / code only)
L2 L2 Embed sub-millijoules embedding + hybrid retrieval
L3 L3 Model joules local SSM / ternary / multimodal / diffusion
L4 L4 Wire tens of joules remote frontier RPC (escape hatch)

L1 (Lawful) is meaningful only for text and code modalities. For image / audio / video / 3D generation the cascade collapses to {L0, L2, L3, L4} — there is no deterministic compute path that produces a high-quality image from "draw me a cat".

A conforming runtime MUST NOT invoke a higher-cost tier before the lower-cost tiers have returned Unresolvable. Inference is the last resort, not the entry point.

1.2 Recent knowledge over frozen weights

A conforming runtime MUST prefer fresh, provenance-stamped retrieval over synthesis from frozen model weights whenever:

  • the cost of the fetch + extract is below the cost of the inference, AND
  • the retrieved source's trust tier is above the operator's configured threshold.

This is the L3.5 stage in the cascade implementation — between L2 (local index) and L3 (local model). The retriever MUST emit a ClaimProvenance envelope (see §4) for every fact that contributes to the resolution.

1.3 Honest energy provenance

Every energy reading MUST carry a Provenance tag declaring how the value was obtained:

Provenance Meaning
HwShunt Hardware reading: a shunt / coulomb counter (Jetson INA3221), or a vendor energy counter (RAPL MSR, NVML cumulative-energy counter, Apple IOReport) while it is live for the domain it claims (below)
ModelBased Vendor-provided estimate from freq / voltage / utilisation (ROCm SMI, NVML power.draw)
Estimator JouleClaw static cost model from arch × precision × batch tables

A vendor energy counter's reading is a real reading. What separates one such reading from another is provenance — which counter, over which domain, and whether it was live when read — not accuracy. So a live vendor counter is graded HwShunt, and liveness is the 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). 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.

The bound is two-sided (MUST). Where an implementation judges a vendor energy counter against an independent yardstick — the board's own power telemetry, a datasheet envelope — it MUST apply the bound in both directions. A counter that accrues far less than the yardstick says the device drew is as refuted as one that accrues far more, and it is the more dangerous of the two: under-reporting is the unsafe direction at an energy ceiling, because it admits work the budget cannot cover, while a counter running fast fails safe by spending a budget sooner. A counter republished in lumps, sampled across its republish period, reads low rather than frozen — it advances, so a liveness probe alone calls it live.

Such a judgement refutes, never verifies. The yardstick is itself usually ModelBased (a vendor power estimate), so a counter inside both bounds is not refuted, which is not a finding that it is correct. Where the yardstick is absent or itself unusable the result is an indeterminate, and an indeterminate MUST NOT be graded as a hardware reading either: erring toward declining is the safe direction. A bound MUST NOT fire where the device is near idle and the yardstick leaves no room for a finding — at idle draw a correctly reporting counter accrues almost nothing, and refuting it would be noise, not a defect.

Apple IOReport's GPU rail is not a partial reading of CPU work. It is machine-wide — it meters every client of the GPU on the host, display compositing among them, and moves while nothing of the metered work runs — so where the CPU rail is frozen and only the GPU rail advances, the reference implementation declines the counter and estimates the work rather than reporting the GPU rail as Partial: the rail does not cover part of the work, it covers other work.

The thermodynamic circuit breaker MUST enforce at the granularity of the worst counter in the request's span. Implementations MUST surface resolution_uj() and min_window_ns() so callers can refuse to claim microjoule accuracy on platforms that cannot deliver it.

Realistic floors:

  • Intel / AMD x86 RAPL: ~1 μJ, ~10 ms window. HwShunt.
  • Jetson INA3221: ~10 mW (integrate for energy). HwShunt.
  • NVIDIA discrete (NVML cumulative-energy): ~1 mJ, ~100 ms. HwShunt — with a caveat measured across 588 runs by Dauner et al., Evaluating the Influence of Measurement Frequency on Energy Readings Using Intel RAPL and NVIDIA NVML, ACM SIGENERGY Energy Informatics Review 6(2), July 2026. The cumulative counter does not update faster than roughly 100 ms on any device they tested: below that it mostly returns the preceding value (a stale-read fraction of 93.4 % at 0.5 ms, 86.3 % at 10 ms, 1.0 % at 100 ms, zero from 500 ms). Accuracy against integrated power is then device-class dependent: a data-center part (A100) agreed to ±0.2 % at every interval, while an unvalidated consumer part (RTX 4090) was still 13.3 % low at 100 ms and came within 1.6 % only at 1 s. So on a GPU whose counter has not been validated against integrated power, prefer the power integral — which this standard's reference implementation already falls back to, graded ModelBased. A counter read below its own update rate is not a reading of the span, whatever the interface.
  • Apple Silicon IOReport: ~1 mJ, ~10 ms. HwShunt while its CPU energy rail is live. On macOS 27.0.1 an unprivileged reader's CPU rails are frozen (observed on an M5 Max and an M3 Ultra), so the counter is declined there and the host is estimated (Estimator). Marketing claims of microjoule precision on Apple Silicon are sales talk; the spec is honest about this.
  • Apple Silicon, per process (macOS 27.0.1, unprivileged): the process's own CPU energy (proc_pid_rusage, nJ, live) is HwShunt. The kernel adds a thread's energy to that count only when the thread leaves a core, and a process's read of its own count does not take the reading thread off its core, so such a read is short of what that thread spent since it last left one: up to a scheduling quantum, missing from a span that ends there and, spent before it, inside a span that starts there (measured: of 40 spans over 1 ms of the reading thread's CPU, 25 to 31 read nothing or under three quarters of it). An implementation MUST take each read of its own process only once it has checked that the reading thread left its core just before it — the reference counter sleeps, and reads only once that thread's own energy count (proc_pidinfo, PROC_PIDTHREADCOUNTS) rose across a sleep — and a span with an end not so checked MUST NOT be graded a hardware reading: it is estimated. Its GPU energy is HwShunt in two cases only: an exact zero when its own GPU time (I/O Registry) did not move, and the IOReport GPU Energy rail (nJ, live) when it had at least 99% of every GPU client's GPU time over the span. A shared GPU gives no figure: the rail MUST NOT be split by GPU time, which is not energy-proportional (measured: ~1.9 W vs ~17 W per GPU-second for two jobs). Without a GPU figure, the process's CPU figure alone is Partial. No live source covers the ANE: a figure for work that used it is Partial.
  • Consumer AMD GPU, ARM PMU: no usable counter. Use a calibrated Estimator and surface the wider tolerance band.

2. The receipt

Every cascade walk MUST produce one Receipt:

{
  "jc_receipt": "1",
  "id": "<uuid v4>",
  "closed_at": "<rfc 3339>",
  "input_hash": "<blake3 hex of normalised input>",
  "tier": "L3",
  "joules_uj": 3500000,
  "energy_provenance": "ModelBased",
  "tools_touched": [
    {
      "tool_id": "model:gemma4-9b-q5_k_m",
      "joules_uj": 3500000,
      "energy_provenance": "ModelBased"
    }
  ],
  "claims": [
    {
      "source": "https://en.wikipedia.org/wiki/Gemma_(model)",
      "content_hash": "<blake3 hex>",
      "fetched_at": "<rfc 3339>",
      "trust_tier": 9
    }
  ],
  "eoc_stage": null
}

Receipts are shaped to seal cleanly inside a Smart Byte signed envelope (see the sibling Smart Byte standard). The Smart Byte signature attests to receipt integrity; the receipt itself is the auditable thermodynamic record.

A receipt's energy_provenance is the worst counter seen across all tools_touched — not the best. This is normative.


3. The .jc.toml sidecar

A model file on disk (GGUF / safetensors / MLX) tells you tensor shapes and quant schemes. It does NOT tell you what one forward pass costs in joules on real hardware. The cascade auction cannot pick the cheapest backend if every backend lies about its cost.

A .jc.toml sidecar travels next to the model file and declares the energy contract. See jouleclaw-pack for the schema. Backends loading a model with a .jc.toml are bound to honour the declared cost within the per-measurement drift_factor tolerance; the runtime trips CostDrift and down-weights the backend in future auctions when measured > declared × drift_factor.

Without a declared-cost contract, "energy-optimised inference" is marketing. With one, it is an engineering claim a third party can verify against the published reference-hardware corpus (see §6).


4. Provenance

Every retrieved claim that contributes to a resolution MUST carry a ClaimProvenance envelope:

{
  "source":       "<url, did:plc, doi, ...>",
  "content_hash": "<blake3 hex of bytes as fetched>",
  "fetched_at":   "<rfc 3339>",
  "trust_tier":   9
}

trust_tier is 0..10. Bootstrap data comes from the Wikipedia perennial-sources list (machine-readable via the Wikimedia Enterprise parsed-references endpoint); operators MAY extend the table.

A retriever MUST NOT present a synthesised fact as a retrieved claim. If the runtime falls back to model inference because no retrieval closed the query, the receipt's claims array MUST remain empty for that tier and the resolution carries the L3:Model tag, not L2:Embed.


5. The MCP tool surface

The standard tool dispatch protocol is MCP (Model Context Protocol). A conforming runtime SHOULD speak MCP for interop with the Claude Code / Codex / Goose ecosystem.

Every MCP tool call MUST be wrapped in jouleclaw-mcp::dispatch_metered, which brackets the call with energy counter reads and pushes a ToolTouch entry onto the running receipt's tools_touched ledger.

5.1 The joule-mcp profile

Two JouleClaw-aware endpoints MAY opt into a CBOR transport profile by advertising the capability tag x-jouleclaw/joule-mcp@1 in their handshake. When both sides advertise it, the wire encoding switches from JSON-RPC to length-prefixed CBOR (~30–50% lower serialisation tax per call). When either side does not advertise, the encoding MUST fall back to standard MCP JSON-RPC.

Non-JouleClaw MCP clients (Claude Code, Codex, etc.) see plain JSON-RPC. The CBOR profile is a negotiated extension, never a replacement.


6. Conformance

A conforming runtime MUST produce a Receipt for every published conformance vector in conformance/v1/ that matches the canonical receipt's tier, tools_touched[].tool_id, and claims[].content_hash.

The joules_uj field in a conforming receipt MUST fall within the platform-specific drift band declared in the .jc.toml sidecar for each tool / model touched. Drift beyond the band is a non-conformance signal, not a hard failure — the runtime SHOULD emit DriftAlert and let the operator decide whether to demote the backend or pause the deployment.

Conformance vectors are signed at release time. Implementations self-certify by round-tripping the public vectors and publishing their receipts.


7. Wire format versioning

  • The cascade tier wire tags (L0–L4) are stable across versions. A future major version MAY add tiers (e.g. L5:Quantum) but MUST NOT renumber existing ones.
  • The jc_receipt field on a receipt is the schema version. This document defines "1" (the cascade receipt of §2) and "policy/1" (the policy receipt of §10). Unknown major → reject. Unknown minor → accept by ignoring unknown fields. New jc_receipt schemas are added under their own prefixed namespace ("<name>/<version>"); the bare numeric form "N" is reserved for the cascade-walk receipt.
  • The jc_pack field on a .jc.toml sidecar follows the same rule.
  • The jc_workspace field on a workspace manifest (§11) follows the prefixed-namespace rule ("workspace/1").

8. Agent identity

A long-running JouleClaw agent is identified by a stable handle bound to an Ed25519 public key. The canonical derivation is W3C did:key over multicodec Ed25519:

handle = "did:key:z" || base58btc(0xed 0x01 || raw_public_key_32)

A conforming AgentIdentity carries (handle, public_key, optional EAT attestation, optional created_at). A verifier MUST confirm that handle == did:key_handle(public_key) before accepting any signed material from that identity. Attestation envelopes (RATS / EAT per RFC 9711) MAY be bound to the identity by placing the same handle in the EAT cti claim.

Where this identity flows:

  • Receipt.steward (§2): the cascade-receipt steward identity is the handle form when self-describing.
  • PolicyReceipt.steward (§10): same handle, same key.
  • WorkspaceManifest.owner (§11): same handle, same key, with the pubkey embedded so a third-party verifier needs no external mapping.
  • COSE_Sign1 kid header on any signed envelope: same handle.

Identity rotation is out of scope for v1. KERI-based AID rotation is the recommended substrate; this spec does not normatively constrain the rotation mechanism.


9. The policy engine

JouleClaw runtimes MAY consult an out-of-process policy engine before executing an Action. When they do, the engine MUST be deny-by-default and operate at filesystem / network / process granularity.

A conforming engine exposes the following surface:

  • Action — Filesystem { path, mode } | Network { host, port, method } | Process { binary, argv }.
  • Decision — Allow { rule } | Deny { reason }, where DenyReason is NoMatchingAllow (deny-by-default) or ExplicitDeny { rule }.
  • Policy — ordered list of rules, plus a monotonic version. A Rule is (effect, agent_scope, action_predicate, name).
  • Evaluation rule — explicit Deny rules short-circuit before any Allow. First matching Allow wins. No matching Allow ⇒ deny-by-default. MUST record an AuditEvent per evaluation.
  • AuditEvent — (sequence, policy_version, agent, action, decision). Sequence is monotonic within the engine instance.
  • Live policy update — install_policy(new) accepts only when new.version > current.version.

A conforming out-of-process transport is line-delimited JSON over a duplex byte stream. One request per line, one response per line. Operations: evaluate, audit, audit_since, policy_version, install_policy. The server treats a malformed line as an error response and keeps the stream open.

The reference engine is jouleclaw-policy::InMemoryPolicyEngine (in-process) plus jouleclaw-policy-ipc::PolicyClient / jclaw-policyd (out-of-process).


10. The policy receipt

A PolicyReceipt is the signed audit record for one policy decision. It is a sibling of the cascade receipt in §2: same COSE_Sign1 envelope (alg = -8 EdDSA over canonical det-CBOR), same steward identity, but its own schema id ("policy/1") and its own wire shape.

{
  "jc_receipt": "policy/1",
  "id": "<uuid v4>",
  "closed_at": "<rfc 3339>",
  "steward": "<did:key handle>",
  "engine_id": "<id>",
  "audit_sequence": 7,
  "policy_version": 2,
  "policy_digest": "<blake3 hex, OPTIONAL>",
  "agent": "<did:key handle>",
  "action": { "kind": "filesystem", "path": "/workspace/x", "mode": "read" },
  "decision": { "kind": "allow", "rule": "read-workspace" }
}

10.1 Binding the receipt to the rules

policy_version is an installation counter, not a content address. A conforming engine SHOULD refuse a non-increasing install, which makes the number identify a ruleset within one engine instance; across a restart, a replica, or a different backend it does not, because each starts its own count. decision.rule likewise names the rule that decided by name. A receipt carrying only those is a pointer into state that only its producer holds: a verifier must be told what engine-A's version 2 contained, by the party whose decision is under audit.

A receipt therefore MAY carry policy_digest, a BLAKE3 hex digest of the rules themselves, and an implementation that emits one MUST compute it as:

BLAKE3( "jouleclaw.policy/1" || rule_count(8, BE) || per rule:
          len(name) || name
          "allow" | "deny"
          "agents:any"  |  "agents:one_of" || count(8, BE) || (len||id)*   [ids SORTED]
          "action:filesystem" || len(path_glob) || path_glob || count || (len||mode_tag)*
        | "action:network"    || len(host_glob) || host_glob || from(2,BE) || to(2,BE)
                              || count || (len||method_tag)*
        | "action:process"    || len(binary_glob) || binary_glob )

Three rules make it a digest of the policy rather than of a serialization:

  • Rule order is included. Evaluation scans Deny rules first and short-circuits, so reordering can change the outcome: two orderings are two policies.
  • The agent list is sorted before hashing. agents:one_of is matched by membership, so two policies differing only in that order are the same policy and MUST share a digest.
  • A port range is hashed as written, not normalised. A range whose from exceeds its to matches nothing, which is a different policy from the same pair the other way round.

version is excluded from the digest: the digest answers "which rules", the version travels beside it answering "which installation", and folding the counter in would make one ruleset hash differently per engine.

Every variable-length part is length-prefixed, so no two distinct policies can share a preimage by moving a field boundary. The mode and method tags are written out above rather than derived from a serializer, so the digest does not move if a serde rename or a variant reordering ever lands.

The digest MUST be the one in force when the decision was made, not the engine's current policy — the two differ across an install, and attributing a decision to rules installed after it was made is the error the field exists to prevent. Implementations SHOULD record it on the audit event at decision time.

When absent, the field MUST be omitted from the signed core entirely, not emitted as a null or an empty string: a receipt without the binding then has a signed core byte-identical to one produced before the field existed, which is why the three policy/1 vectors published before it are unchanged and policy/1 verifiers keep working. A consumer that requires the binding MUST check for the field's presence rather than defaulting it.

  • The canonical signed core is the det-CBOR (RFC 8949 §4.2.1 length-first map ordering) of the receipt as JSON.
  • The COSE_Sign1 envelope is identical in shape to the JCR-1 v1 envelope on the cascade receipt: protected = {1: -8, 4: steward}, unprotected = {}, payload = canonical signed core, signature = Ed25519(Sig_structure).
  • Verifiers reject envelopes whose kid (in the protected header) disagrees with the embedded steward.
  • Conforming implementations MUST byte-match the four reference vectors in jouleclaw-rs/crates/jouleclaw-policy-receipt/conformance/vectors-policy.json. Reference verifiers in Rust, Python, and Go ship alongside the vectors; all three produce byte-identical canonical bytes for the same receipt. Vectors 1-3 omit policy_digest and keep the bytes they shipped with; vector 4 is vector 1's decision with the binding, so the two differ by exactly that key.

Policy receipts and cascade receipts share the same JSONL "unified log" file format: readers dispatch on the jc_receipt schema tag ("1" → cascade, "policy/1" → policy, unknown → forward-compat skip).


11. The agent workspace

A persistent, content-addressed workspace MAY be attached to a long-running agent. The workspace's wire form is a WorkspaceManifest:

{
  "jc_workspace": "workspace/1",
  "owner": { "handle": "<did:key>", "public_key": "<hex32>" },
  "entries": [
    { "path": "notes/x.md", "content_hash": "<blake3 hex>", "size": 17, "kind": "text" },
    ...
  ]
}
  • Path normalisation — paths are relative /-joined segments. Absolute paths, empty paths, empty segments, . and .. segments, and NUL bytes are MUST rejected on write.
  • Content addressing — content_hash is BLAKE3 hex of the bytes; the underlying backend stores bytes keyed by content_hash so identical content is deduplicated.
  • Entry order — entries in the manifest are sorted lexically by path.
  • Manifest content-address — the manifest's own content hash is BLAKE3 over its canonical JSON serialisation. Identical workspace state → identical manifest hash → identical signature.
  • Signing — a SignedWorkspaceManifest carries an Ed25519 signature over the canonical manifest bytes. Verifiers MUST check both that the embedded owner.handle matches the embedded owner.public_key under §8 derivation, AND that the signature verifies.

The workspace deliberately does NOT specify encryption, conflict resolution, or multi-writer merge. Backends are single-writer; if multi-writer is needed it composes behind a future WorkspaceBackend impl with a lock service. Encryption is the caller's job — the manifest signature covers what is observable, not what is decrypted.


12. Skill interoperability — SKILL.md

JouleClaw skills are portable to the broader open-skills ecosystem (Claude Code, OpenAI Codex, Gemini CLI, GitHub Copilot, Cursor, et al.) via the agentskills.io SKILL.md format. Conformance:

  • A JouleClaw-emitted SKILL.md MUST carry the agentskills.io required frontmatter (name ≤ 64 chars matching ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$; description ≤ 1024 chars).
  • The deterministic JouleClaw procedure (the Template and Procedure that let a JouleClaw cascade resolve the skill at lookup energy) travels under metadata.jouleclaw as a vendor extension. Non-JouleClaw consumers treat the Markdown body as natural-language instructions; JouleClaw-aware consumers reconstruct the typed Skill.
  • The body is required by emitters — empty bodies are rejected unless the caller opts in explicitly via a _with_default_body helper (intended only for drafts).
  • Unknown vendor metadata keys are preserved on round-trip.

13. Vocabulary (JSON-LD + Turtle)

JouleClaw publishes a stable IRI vocabulary so a JSON-LD parser, a SPARQL store, or a generic third-generation agent client can read any JouleClaw receipt as RDF without bespoke integration.

  • Namespace: https://jouleclaw.transaction.science/vocab/v1# (prefix jc: by convention).
  • JSON-LD context: https://jouleclaw.transaction.science/vocab/v1.jsonld (every field name in §§2, 10, 11 maps to a jc:-prefixed IRI with the typed range below).
  • Turtle ontology: https://jouleclaw.transaction.science/vocab/v1.ttl (classes, enumerations, properties, ranges; CC-BY-4.0).
  • Human index: https://jouleclaw.transaction.science/vocab/v1.
  • Canonical source: jouleclaw/vocab/ in this repository.

The vocabulary is purely additive:

  • A v1 cascade or policy receipt remains a valid JouleClaw receipt on the wire with or without an @context field.
  • Adding "@context": "https://jouleclaw.transaction.science/vocab/v1.jsonld" to a receipt expands it into typed RDF triples (e.g. tier: "L3" becomes <receipt> jc:tier jc:Model, energy_provenance: "ModelBased" becomes <receipt> jc:energyProvenance jc:ModelBased) without changing any other field.
  • The canonical signed core of a JCR-1 envelope MUST NOT include @context — the JSON-LD context is metadata, not payload. Producers that want to publish a JSON-LD form alongside the signed receipt SHOULD do so in a separate field, or fetch the context out-of-band from the published URL.

Production default. Conformant producers SHOULD emit @context set to the v1 vocabulary URL on every receipt by default, so any downstream JSON-LD parser treats the document as typed RDF without configuration. The reference implementations do this in ReceiptBuilder::seal and PolicyReceiptBuilder::build; the without_context() opt-out is reserved for conformance-vector regeneration and backward-compatible wire-form replay.

The vocabulary subclasses W3C PROV-O where the alignment is exact:

  • jc:ClaimProvenance &rsubeq; prov:Entity
  • jc:AuditEvent &rsubeq; prov:Activity
  • jc:AgentIdentity &rsubeq; prov:Agent

PROV-O consumers can therefore reason about a JouleClaw deployment as a provenance graph using this one IRI mapping — no JouleClaw-specific code beyond the standard PROV-O semantics.

Versioning. A future major bump publishes under /vocab/v2#. v1 IRIs remain resolvable forever per the open-standards "names are final" rule.


14. Hydra ApiDocumentation

A JouleClaw service publishing a tool surface (MCP server, the out-of-process policy daemon, an HTTP endpoint) SHOULD serve a Hydra Core Vocabulary hydra:ApiDocumentation document at a stable discovery endpoint. Hydra is the W3C CG draft that solved the "tool schemas live in the client's context window" pathology for the third-generation web: the API describes itself in a machine-readable form, a generic client reads the description once, and the client calls every operation without ever loading a schema into its context.

A conforming ApiDocumentation:

  • Is JSON-LD using both the Hydra Core Vocabulary namespace (http://www.w3.org/ns/hydra/core#) and the JouleClaw vocabulary namespace from §13 (jc: prefix).
  • Carries @type: "ApiDocumentation" at the root, a stable @id, a human-readable title + description, and a supportedClass list.
  • Each Class in supportedClass carries supportedOperation — one Operation per published verb. An Operation declares method, expects (input class IRI; owl:Nothing for parameterless), returns (output class IRI), and statusCodes.
  • The JouleClaw extension fields jc_tool_id (stable tool id) and jc_mutating (mirror of MCP's mutation flag) MAY appear on each operation. They reference the JouleClaw vocabulary from §13 so a receipt emitted by that tool cross-links back to its Hydra description.

Default mappings the reference emitter uses:

Source field Hydra field Default value
mutating: false method "GET"
mutating: true method "POST"
(none) expects owl:Nothing
(none) returns jc:ToolResponse
(none) statusCodes 200, 400, 500
name jc_tool_id "jouleclaw:<name>"

The reference emitter is jouleclaw-hydra::ApiDocumentationBuilder in the workspace; the mcp-adapter feature provides From<&McpToolSchema> for ToolDescription so an existing MCP server emits a Hydra doc in one chained call.

A generic third-generation agent client fetches the ApiDocumentation, validates the @context, and is then free to call every tool by following the typed contract — no out-of-band tool prompts, no schema-per-tool context bloat. This is the structural fix for the generation-2 "72% of context window on tool schemas" pathology.


15. SHACL shapes

A JouleClaw service SHOULD publish SHACL Core shapes for every input/output class its Hydra ApiDocumentation (§14) references. The shapes let an agent validate a candidate payload before calling a tool — locally, without any model invocation, with deterministic results.

The canonical JouleClaw v1 shape graph lives at https://jouleclaw.transaction.science/vocab/v1.shapes.ttl and covers every class in §§2, 8, 10, 11 (Receipt, PolicyReceipt, WorkspaceManifest, WorkspaceEntry, AgentIdentity, Action with the three subclasses, Decision with Allow and Deny subclasses, ToolTouch, ClaimProvenance). The shapes use only SHACL Core constraints — no SPARQL, no qualified value shapes — so:

  • A full SHACL validator (pyshacl, Apache Jena) accepts the file directly and produces a sh:ValidationReport against any candidate document.
  • A lightweight in-tree validator (the reference impl is jouleclaw-shacl::ShapeGraph::jouleclaw_v1()) covers the same constraints in ~600 lines of Rust with no SPARQL engine. Compiles to WASM so an in-browser agent can validate locally.

Constraints in use: sh:minCount / sh:maxCount, sh:datatype (xsd:string, xsd:integer, xsd:nonNegativeInteger, xsd:dateTime, xsd:double, xsd:boolean), sh:nodeKind (sh:IRI, sh:Literal), sh:in (enumerations), sh:pattern (regex), sh:minInclusive / sh:maxInclusive, and sh:node (nested shape delegation).

The shape file is the contract a JouleClaw operator publishes alongside their Hydra ApiDocumentation; the lightweight validator is the agent-side counterpart. A tool input that fails validation MUST NOT be sent to the tool.


16. Validation contract

A validation contract is the planning artifact a multi-step JouleClaw run is judged against. It is authored before any implementation work begins, lives independently of the code, and is the only thing that decides whether a mission succeeded.

16.1 Shape

A contract is a JSON document with the fields:

  • jc_contract: "contract/1" (this version).
  • @context: optional JSON-LD context, defaults to https://jouleclaw.transaction.science/vocab/v1.jsonld.
  • title: free-form mission name.
  • authored_by: did:key:… of the agent or person who sealed the contract. May be empty for unsigned drafts.
  • assertions: an ordered list of Assertion. Ids MUST be unique within the contract.
  • features: an ordered list of Feature. Ids MUST be unique. Each feature's claims MUST reference only assertion ids that exist in the contract.
  • acceptance: optional metadata controlling ship-gate rules.

The contract's content hash is BLAKE3 over the canonical JSON serialisation; identical contracts → identical hashes. The content hash is what a JCR-1 receipt binds to when it claims to have run against this contract.

16.2 Assertion

Each assertion is one falsifiable claim:

  • id: stable string (e.g., "A-001").
  • title: one-line summary.
  • rationale: free-form why. Optional.
  • priority: one of must_have | should_have | nice_to_have.
  • check: one of:
    • { "kind": "tool", "tool_id": "…", "args_hash": "…"? }
    • { "kind": "artifact", "path": "…", "expected_hash": "…"? }
    • { "kind": "command", "command_hash": "…", "expected_exit": N }
    • { "kind": "checker", "checker_id": "…" }

A must_have assertion that does not roll up to verified MUST block ship. A should_have assertion that does not roll up to verified MUST NOT block ship unless acceptance.block_on_should_have is true.

16.3 Feature

Each feature is one unit of work that claims one or more assertion ids it intends to satisfy:

  • id: stable string (e.g., "F-001").
  • title + optional description.
  • claims: list of assertion ids this feature covers.

A worker dispatched against a feature SHOULD emit evidence for every assertion that feature claims; the verifier surfaces missing evidence as a gap.

16.4 Evidence

The verifier consumes a bag of evidence items the run produced:

  • tool_result { tool_id, args_hash?, passed }
  • artifact_present { path, hash }
  • command_run { command_hash, exit_code }
  • checker_result { checker_id, passed }

An evidence item matches an assertion when its discriminants match the assertion's check. A matching item with passed: true (or, for command, exit_code == expected_exit; for artifact, hash == expected_hash when supplied) raises the assertion to verified. Any matching failure raises the assertion to failed; the verifier surfaces the disagreement rather than silently allowing a later success to mask it.

16.5 Verification

The verifier is a pure function over (contract, evidence). It emits a ContractVerdict:

  • jc_verdict: "verdict/1".
  • contract_hash: hex BLAKE3 of the contract.
  • passed: boolean.
  • summary: human-readable one-liner.
  • coverage: a typed matrix with one row per assertion, one column per feature, plus a per-assertion rollup (verified | claimed_unverified | failed | gap).
  • blocking_gaps: must-have assertion ids not rolled up to verified.
  • should_have_gaps: should-have assertion ids not rolled up to verified.

Same inputs → same verdict. The verdict is the artifact a receipt links to when reporting a multi-day run's outcome.

16.6 Conformance

A conforming producer of a contract MUST:

  • Set jc_contract to "contract/1".
  • Reject duplicate assertion ids and duplicate feature ids.
  • Reject features whose claims reference unknown assertion ids.

A conforming verifier of a contract MUST:

  • Implement the rollup rules in §16.5 exactly: any matching failure → failed; otherwise any matching pass → verified; otherwise any claim → claimed_unverified; otherwise → gap.
  • Block ship on any must_have non-verified rollup.
  • Block ship on should_have non-verified rollups iff acceptance.block_on_should_have is true.

Reference: crates/jouleclaw-contract. SHACL shape: jc:ValidationContractShape at vocab/v1.shapes.ttl.

16.7 Verdict receipt

The §16.5 verifier emits a ContractVerdict as plain JSON. To land that verdict on the unified auditable log alongside cascade receipts ("1") and policy receipts ("policy/1"), wrap it in a verdict receipt — sibling schema "verdict-receipt/1", same canonical det-CBOR + COSE_Sign1 envelope every other JouleClaw sibling receipt uses, under the same steward identity.

{
  "jc_receipt": "verdict-receipt/1",
  "id": "<uuid v4>",
  "closed_at": "<rfc 3339>",
  "steward": "<did:key handle>",
  "engine_id": "<id>",
  "audit_sequence": 7,
  "contract_hash": "<hex BLAKE3 of the contract>",
  "verdict": { /* ContractVerdict, verbatim */ }
}

Wire-format rules:

  • The canonical signed core carries the verdict as a JSON-string field named verdict_json (not a nested object), with a sibling verdict_hash field set to hex BLAKE3 of the verdict_json bytes. This keeps the signed core inside the JCR-1 canonical-CBOR subset (which forbids bools and nulls) while still binding the verdict to the signature. The wire-form JSON object surfaced to consumers MAY carry verdict as a nested object for ergonomics; the signed core is normative.
  • The COSE_Sign1 envelope is identical in shape to JCR-1 v1: protected = {1: -8, 4: steward}, unprotected = {}, payload = canonical signed core, signature = Ed25519(Sig_structure).
  • contract_hash MUST equal the BLAKE3 content hash of the ValidationContract the verdict was produced against. Verifiers consuming the unified log MAY index by contract_hash without parsing the inner verdict.

Conforming producers + verifiers SHOULD reuse the existing JCR-1 envelope tooling (verifiers reject envelopes whose kid disagrees with the embedded steward, etc.).

Reference: crates/jouleclaw-contract-receipt.


17. Worker handoff

A worker handoff is the structured wire form an agent emits at end-of-feature-work. The handoff is what makes a multi-day run readable to the next worker (or the next session of the same worker) — it forces the agent to write down what actually happened rather than relying on conversational context.

17.1 Shape

A handoff is recorded as a RunEvent::HandoffRecorded variant on the run journal:

  • worker: stable worker id (typically did:key:…).
  • node_id: optional graph node this handoff closes.
  • feature_id: optional contract feature id this handoff claims to satisfy.
  • closed_at: epoch-seconds wall-clock.
  • completed: list of items reported done.
  • undone: list of items reported left undone.
  • commands: list of { command_hash, argv, exit_code } entries observed during the work window.
  • issues_found: list of issues the worker discovered.
  • procedures_followed: list of skills / runbooks the worker applied.

command_hash MUST be hex BLAKE3 over argv.join("\0"). The hash, not the argv array, is the command's identity; the argv is carried for human inspection only.

The handoff hash is part of the journal entry's hash chain, so editing handoff fields after the fact breaks chain verification.

17.2 Conformance

A conforming producer of a handoff MUST:

  • Set every field that is non-empty in the run; empty lists are acceptable but the discriminator MUST be present.
  • Compute command_hash as specified.

A conforming consumer of a handoff MUST:

  • Accept additive fields (the variant set is open under semver-compatible extension).
  • Verify the journal's hash chain before trusting the handoff's contents.

Reference: crates/jouleclaw-graph (WorkerHandoffEvent, HandoffCommand, RunEvent::HandoffRecorded). SHACL shape: jc:WorkerHandoffShape at vocab/v1.shapes.ttl.

17.3 A node in flight survives the process

The run journal records a node when it completes. A node whose process dies before it completes would otherwise leave no trace, and a restarted run would dispatch it again as if it had never begun, repeating any work it did outside the run: a message sent, a payment made, a record written.

A consumer that dispatches a node SHOULD therefore record the dispatch (RunEvent::NodeDispatched) before the node's work begins, with the node's replay rule:

  • safe: running the node again is harmless, because it is a read or its work is keyed so a repeat finds its first result.
  • never (the default): the node may have acted outside the run, and nothing in the journal says whether it did.

A dispatched node that is not yet recorded is in flight, and MUST NOT be dispatched again. After a restart, the consumer MUST mark every node still in flight as interrupted (RunEvent::NodeInterrupted) before dispatching anything, keeping the energy observed for the attempt as a lower bound on what it spent. An interrupted safe node is ready again, as a new attempt. An interrupted never node is held: whether its work took effect is not knowable from the journal, so it MUST NOT run again until it is settled, by recording what it did, by an approval to run it again (RunEvent::RerunApproved) that names who gave it, or by failing the run. It is not left to the model to decide: a model told only that a call "may have partly run" can repeat a write it cannot see.

Until a run is recovered, a node in flight stays out of the ready set, so a consumer that omits recovery stalls rather than repeating work. This is the run-journal form of JCP SPEC §4.11.

Reference: Run::dispatch, Run::recover, Run::approve_rerun, Replay, NodeAttempt in crates/jouleclaw-graph.


18. Mission orchestrator

The mission primitive composes §16 contracts

  • §17 handoffs + the run journal into a three-role pipeline: Orchestrator authors, Worker does, Validator judges.

18.1 Roles

  • The Orchestrator authors a ValidationContract and a feature plan. It does NOT execute work; it composes the plan and the validator's expectation in one artifact.
  • A Worker is dispatched per feature. It performs whatever work it does (opaque to this spec) and returns a WorkerOutcome { handoff, evidence }. Workers MAY be backed by any cascade tier — deterministic tools, models, or humans-in-the-loop.
  • The Validator runs the §16.5 verifier over the accumulated evidence and emits a ContractVerdict. The validator's only input is (contract, evidence) — pure data — so its verdict is reproducible and reviewable.

18.2 Dispatch

Workers MUST be dispatched in feature order, serially, when the features mutate shared state. Read-only fan-out (parallel search, parallel verifiers) MAY be parallel; the implementation is the caller's choice and the spec does not require it.

Each worker's handoff MUST be recorded on the run journal before the next worker is dispatched, so the chain stays chronological.

18.3 Strictness

A strict_workers mode MAY refuse worker outcomes that produce no evidence for at least one assertion the worker's feature claims, failing fast rather than letting the validator surface the gap later. The default behaviour is non-strict (let the validator rollup decide).

Reference: crates/jouleclaw-mission.


19. Value report

Where a JCR-1 receipt records what happened (the activity), a value report records what landed against the agent's declared intent. The two together close the activity-vs-value gap: activity is easy to count; value is what the user paid for.

19.1 Shape

A value report is a JSON document:

  • intent: free-form natural-language intent the agent was acting on.
  • tool_id: tool id the call addressed.
  • checks: per-check verdicts, each { check, passed, reason? }.
  • closure_rate: passed_count / checks.len() ∈ [0, 1]. 0.0 when checks is empty.
  • fully_closed: true iff checks is non-empty AND every check passed.

19.2 Check kinds

  • status { codes } — status code MUST appear in codes.
  • status_matches_contract — status MUST be in the operation's declared statusCodes menu (the Hydra contract).
  • output_hash_equals { hash } — canonical-JSON BLAKE3 of the body MUST equal hash.
  • json_pointer_equals { pointer, expected } — RFC 6901 pointer MUST resolve to expected.

Implementations MAY define additional check kinds; consumers MUST tolerate unknown kinds and treat them as passed: false with a reason that names the unknown kind.

19.3 Aggregation

The mean closure rate across a set of value reports is the system's honest "delivered / attempted" metric — denominated in user intent rather than joules. Reports with no checks declared MUST be skipped in the aggregate (they convey no value information).

Reference: crates/jouleclaw-hydra-client (ValueReport, ValueCheck, ValueCheckResult, mean_closure_rate).


20. What this spec deliberately does not say

  • How to build the model. That's the model-author's concern. JouleClaw measures and dispatches; it doesn't train.
  • Which retrieval API to use. Brave / Tavily / Exa / Serper all plug in through the SearchProvider trait. Pick whichever your deployment permits.
  • How to ship receipts. The receipt is produced. Transport (HTTP / lockstep / message queue) is the deployer's choice. Smart Byte's signed-envelope replication is the recommended substrate.
  • A specific signing key topology. Bring your own. Smart Byte's KERI-based AID rotation is the recommended path.

21. Adjacent techniques

This section names the architectural pattern JouleClaw implements and lists the research communities that have, separately, solved parts of it. The intent is not novelty-claiming. It is to make the assembly visible so an engineer arriving from any one of those communities can locate their work inside the cascade.

9.1 The architectural pattern

An LLM inference call is a render pass. A token is a frame. A reasoning chain is a sequence of frames. A context window is a scene graph. An agent loop is an NPC control loop. RAG is texture streaming. A model checkpoint is a level asset. The pipeline from prompt to response is — structurally — exactly the work a game engine does between input poll and presented frame.

The game-engine industry was forced to solve this problem under a fixed 150–200 W power budget twenty years ago. The five JouleClaw cascade tiers are direct translations of game-engine architectural primitives:

JouleClaw tier Game-engine primitive What the engine actually does
L0:Cache texture / asset cache Content-addressed; cheap to check; valid until invalidated
L1:Lawful pre-baked geometry, LUTs The work the engine refuses to run because the answer is already in the format
L2:Embed BVH / spatial query Find the closest match; do not compute from first principles
L3:Model procedural / runtime synthesis Invoked only when nothing baked or streamed will do
L4:Wire server-streamed asset / CDN The escape hatch when the local box cannot satisfy

Each game-engine technique listed below has a near-exact counterpart in modern AI inference that the AI industry has, so far, declined to deploy at the same architectural rigor:

Every lever below now has a shipped JouleClaw realization — the frame is no longer rhetorical; each row points at in-tree code:

Game-engine technique AI counterpart JouleClaw component (shipped)
Frustum culling Skip tiers whose estimate_cost returns None jouleclaw-cascade::Tier::estimate_cost
Level-of-detail (LOD) Route to the cheapest sufficient model — SLM before frontier jouleclaw-dispatch::ModelBankTier (cheapest capable slot by measured J)
Deferred rendering Do not forward-pass through 175B parameters for a token a 7B would produce identically jouleclaw-dispatch cost-table over backends declaring their J/op
Physically-based rendering One foundation model, derive specializations — not 12 full fine-tunes (consumer concern; the spec doesn't dictate)
Virtual texturing Retrieve only the context this token will attend to, not the whole 128k window jouleclaw-stack RAG pipeline (retrieve → enrich → rerank → read, top-k only) + jouleclaw-fresh
Temporal upsampling Reuse prior verified work; reconstruct from a small delta, not by re-running jouleclaw-promote (exact yang→yin) + jouleclaw-skill (whole query class)
Nanite-style mesh streaming Activate only the reasoner the input actually needs jouleclaw-dispatch routes to the one slot, not the whole bank
Hardware ray tracing + denoiser A few high-quality forward passes plus a verifier beats one large unconstrained pass jouleclaw-verify (OutputVerifier) + jouleclaw-approve gate before the pass
Agent / NPC control loop Bounded multi-step recursion — fan-out capped, depth bounded by the joule budget jouleclaw-agent (max_steps + per-branch budget clamp)
Frame budget JouleBudget walks the cascade like a render budget walks the scene graph jouleclaw-energy::EnergyQuota + breaker, jouleclaw-governor (global), jouleclaw-agent (nested)

The pattern is not new. The assembly — and the fact that every lever is a shipped, tested crate rather than a slogan — is.

9.2 Five communities, one architecture

Five research communities currently hold one face each of this architecture. They publish at different venues and do not, by and large, talk to one another. A conforming JouleClaw runtime composes all five of their primitives — that composition is the standard's contribution.

Community Representative work JouleClaw component
Constrained decoding Outlines (Willard & Louf), XGrammar (Dong et al. 2024), Guidance, LMQL, Pre³, OpenAI/Anthropic structured-output APIs jouleclaw-decode (shipped) — pure-Rust regex / CFG / JSON-schema → token-vocabulary mask
Compound AI systems / DSPy DSPy (Khattab et al., Stanford → MIT; CAIS 2026 inaugural ACM conference, May 2026) jouleclaw-program (shipped) — typed signatures + module compiler — and jouleclaw-skill, its deterministic skill-compilation realization
Small / specialist models NVIDIA Research (Belcak & Heinrich, 2025), Microsoft Phi team, TinyML, llama.cpp jouleclaw-cascade router + jouleclaw-pack declared-cost contracts
Neurosymbolic / verifier-in-the-loop Lean + LLM provers, BMC + LLM (LaM4Inv), SymCode, ProofNet++, VIRF, Eidoku jouleclaw-verify (OutputVerifier trait + VerifierChain + receipt integration)
Energy measurement / Green Software Patterson et al., ML.ENERGY Leaderboard, MDPI Sensors edge-computing surveys, GSF SCI specification, AI Energy Score jouleclaw-energy + the Provenance honesty contract + .jc.toml measured-cost rows

A conforming runtime SHOULD be able to point at concrete in-tree code or a registered adapter for each of the five primitives above. A runtime that solves only one face is a research project, not a JouleClaw implementation.

9.3 The three-lever ceiling

Energy reduction from a fully-naive monolithic baseline (~10¹⁸ above the Landauer floor for current generative inference per output bit) composes multiplicatively across three independent levers:

Lever Reduces by What does it
Route to the right cell 10⁸–10¹⁰× The cascade itself — L0 / L1 / L2 close most queries without invoking a model
Cache the prior work 10²–10⁴× Content-addressed cache (L0), prior-resolution history, MRL embeddings (L2)
Align silicon to primitive 10²–10⁴× The .jc.toml declared-cost contract is the input data hardware co-design needs

Stacked total: 10¹²–10¹⁸× below the naive baseline. The "90 % reduction" figure quoted on the marketing surface is the conservative floor of what the three levers permit when composed honestly.

The ceiling is not the Landauer bound — reaching the bound requires reversible logic and zero-impedance interconnect that nobody can engineer today. The ceiling is how disciplined the routing and the hardware choices are.

9.4 The receipt is the proof, not the marketing

A runtime that produces lower receipts than the conformance vectors demand without the per-tool-touch Provenance to back them is non-conformant. JouleClaw refuses the receipts-as-marketing failure mode that has accumulated around carbon offsets and software sustainability claims more broadly. Every joules_uj figure in a conforming receipt must trace back to either a real hardware counter (Provenance::HwShunt), a documented vendor model (Provenance::ModelBased), or a calibrated static estimator (Provenance::Estimator) with a wider tolerance band.

A hardware counter here means one that was live for the domain the figure claims (§1.3, Liveness). A counter that is present but not live — frozen, or republished in lumps — is not a hardware reading however real the silicon behind it: its span is the estimator's, or the work is reported unmetered, and the receipt says so. Grading a frozen counter's figure HwShunt is the receipts-as-marketing failure mode in its most literal form.

The breaker enforces at the granularity of the worst counter in the span. This is normative.


22. Transparency log (OPTIONAL)

A receipt proves what a runtime decided. It does not prove that the set of receipts you were shown is the set that exists: a stream held privately by the party that produced it can be pruned, re-ordered, or served differently to two auditors, and nothing in §2 or §10 detects that. A conforming runtime MAY publish its receipts into an append-only Merkle log, which closes the part of that gap a log can close.

22.1 Tree

The log is an RFC 6962 Merkle tree over receipt bytes, with BLAKE3 in place of SHA-256 — JouleClaw is BLAKE3-native — and the RFC's domain separators preserved so a BLAKE3-shimmed CT verifier can use the same proof shapes:

  • leaf hash: BLAKE3(0x00 || receipt_bytes)
  • internal node: BLAKE3(0x01 || left || right)
  • a tree of size N is built by the RFC 6962 method: the root is the node hash of the largest power-of-two subtree on the left and the recursive tree of the remainder on the right.

The leaf is the receipt's own bytes, so an auditor checks a proof against the receipt it holds rather than against a digest the operator computed for it.

22.2 Signed tree head

A tree head is (size, root, timestamp). A head that crosses a trust boundary MUST be signed, and the signature MUST cover all three fields over exactly these bytes:

0x02 || size (8 bytes, big-endian) || root (32 raw bytes) || timestamp (8 bytes, big-endian)

0x02 is a third domain separator, distinct from the leaf and node prefixes, so a tree head cannot be presented as an entry in its own log. Every field is fixed-width, so no two distinct heads share a preimage.

The key MUST be the same principal that seals the receipts (§8): a head signed by anyone else commits a party that did not make the decisions.

An unsigned root MUST NOT be used to verify a proof. This is the whole premise — an inclusion proof against an unsigned root proves only that the operator can produce a consistent story on demand, which it always can. A signed root makes two different roots at one size attributable equivocation: both carry the operator's signature, and the pair is evidence against one key.

A verifier MUST reject a head whose root is not 32 bytes of hex rather than treating it as absent or empty.

22.3 What the log proves, and what it does not

A runtime that publishes this log SHOULD state the boundary plainly, because the two halves are easy to conflate:

  • Proven. A given receipt is in the tree a given signed head commits to; the log has only grown between two signed heads (consistency proof); a receipt committed to under a published head cannot afterwards be removed or rewritten without equivocating under the operator's key.
  • Not proven. Completeness. An operator that never records a decision logs nothing, and no proof about the entries that exist can speak for one that was never written.

What narrows the gap is where the append happens. The entry SHOULD be written on the same code path that produces the verdict, before the verdict is returned to the caller. A caller that observed a refusal can then demand the proof of the entry that refused it, and an implementation that cannot record a decision MUST refuse the action rather than perform it unrecorded — an unrecordable allow is the one outcome the log exists to make impossible.

Conformance class C-TLOG: a runtime claiming it signs its head over all three fields, refuses an unparseable root, rejects a head signed by another key, and serves an inclusion proof that closes against the signed root for every entry — allow and deny alike.


23. References

  • JouleClaw Charter — stewardship pattern (shared across all five open standards)
  • Smart Byte open standard — signed envelopes
  • EOC open standard — the four-stage memoising cascade pattern JouleClaw embodies
  • WAI open standard — media transport + capability dispatch
  • OpenPay open standard — the typestate-enforced lifecycle pattern adopted by JouleClaw's cascade
  • W3C PROV-O — provenance vocabulary
  • RFC 9449 — DPoP (sender-constrained tokens, recommended for ClaimProvenance envelopes that carry a fetch credential)
  • Landauer, R. (1961). "Irreversibility and Heat Generation in the Computing Process." The thermodynamic floor under everything in this spec.