All checks were successful
standards workspaces build + test / aac-rs (pull_request) Successful in 39s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 45s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m41s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 37s
standards workspaces build + test / map-rs (pull_request) Successful in 32s
standards workspaces build + test / mesh-rs (pull_request) Successful in 54s
standards workspaces build + test / openpay (pull_request) Successful in 1m26s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m51s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m17s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m16s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m3s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 2m34s
standards workspaces build + test / arl-rs (pull_request) Successful in 10m10s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 10m1s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 10m30s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 10m17s
standards workspaces build + test / sense-rs (pull_request) Successful in 10m27s
The energy field is contested, not empty. The prescriptive half is a decade old and ratified — ISO/IEC 23001-11 carries decoding-operation-reduction metadata whose purpose is to make a decoder do less work, and a companion carriage part now moves it. WAI's half is the measured one. Neither half currently scores against the other, and that gap is where a joule figure stops meaning anything. DEGRADATION-BLINDNESS (§7.1). A receipt that records joules spent, and nothing about how much work the decode was asked to do, rewards the wrong behaviour: a sink can always spend fewer joules by decoding worse. energy-measurement.md §5's recomputable-work-unit rule blocks the substitution at the byte-exact tier, but not at `entropy-consistency`, and not for the conventional codecs WAI already carries. So the receipt has to carry the operating point, not only the cost. REQUEST / COMMITMENT / DELIVERY (§7.2). Three distinct fields, because the interesting cases are exactly the ones where they differ. A receipt MUST NOT carry `op_delivered` alone — that is the degradation-blind case. `op_committed` MUST be what the receiver stated even where it differs from the request, since a commitment that silently becomes the request is not a commitment. And a sink that honoured a reduction request MUST NOT claim `decode-equivalence`, per the tier rule. This converts a recorded number into a number measured against a promise. The prescriptive standards say what should be spent; the measurement standards say what was; nobody scores the second against the first. THE RESIDUAL (§7.3). Where a complexity descriptor and a measured binding cover the same reconstruction, the receipt MUST carry the signed difference between predicted and measured energy — over the same work unit, never without the acquisition class of the measured term, and never suppressed for being large. The large ones are the informative ones, and suppressing them turns a falsifiable claim into an unfalsifiable one. A complexity descriptor is a prediction about energy, and until something records what actually happened against it, the prediction can never be wrong. §7.3 closes that loop inside the artifact rather than in a report. COMPANION CAPABILITY (§7.4). Green-metadata semantics register the way wai.meta.hdr10plus and wai.meta.dovi do — name the descriptor class, sink supplies the decoder, no carriage adopted. ISOBMFF/DASH carriage is somebody else's layer. NETWORK-LAYER ALIGNMENT (energy-measurement §2.1). WAI's HwShunt/ModelBased/ Estimator is a private vocabulary, and coarser than the graded accuracy hierarchy an adopted IETF GREEN draft defines for device energy. An implementation reporting under both SHOULD derive rather than assign independently, MUST say which identity it derived from, MUST NOT let a derivation improve the class, and MUST declare the tolerance the class implies — a class without a tolerance is a label. WAI does not adopt that model; the scopes differ (device vs per-object) and conflating them would breach §4. What is required is that two vocabularies for one property do not contradict each other. Ingest queue item 3 and item 8 from the landscape survey (#80 §5.3 a–e). Co-Authored-By: Claude Opus 5 <[email protected]>
250 lines
12 KiB
Markdown
250 lines
12 KiB
Markdown
# WAI Extension: Energy Binding
|
||
|
||
> Status: Draft. Binds the **energy a reconstruction cost** to *that*
|
||
> reconstruction, as a companion to C2PA 2.4's
|
||
> `c2pa.environmental-sustainability` assertion — supplying the acquisition
|
||
> class, the coverage, and the outcome binding the standard assertion has no
|
||
> field for. Reference impl: the `energy_binding` module of `wai-rs`
|
||
> (feature `provenance`), emitted into a real signed manifest by `c2pa_emit`
|
||
> (feature `c2pa_emit`). Companion to
|
||
> [Reproducible-Reconstruction Binding](reconstruction-binding.md) and the
|
||
> acquisition protocol in [Energy Measurement](energy-measurement.md).
|
||
> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
|
||
|
||
## 1. Why a companion assertion
|
||
|
||
C2PA 2.4 defines `c2pa.environmental-sustainability`, carrying `energy_kwh`
|
||
(per ISO/IEC TR 20226:2025) alongside carbon and water figures. The dominant
|
||
signed-provenance container in media now has a place to put joules.
|
||
|
||
Three properties it does not have, and this extension supplies:
|
||
|
||
1. **It is self-declared.** `measurementMethod` is optional, and an
|
||
unattributed number cannot be compared with any other number. In practice
|
||
the optional field is the one that stays empty.
|
||
2. **It carries no acquisition class.** A hardware counter reading and a
|
||
modelled constant occupy the same field and are indistinguishable to a
|
||
reader, though they are different claims about the world.
|
||
3. **It is not bound to any reproducible output.** The assertion is about an
|
||
asset; a validator can check every signature in a manifest and still not
|
||
know what the figure was measured *over*.
|
||
|
||
The third is the load-bearing one. A signature proves who said a number, never
|
||
that the number is about anything checkable.
|
||
|
||
## 2. What the binding is
|
||
|
||
An energy binding is the tuple
|
||
|
||
```
|
||
{ reconstructionHash, alg, microjoules, acquisition, coverage, workUnits, method }
|
||
```
|
||
|
||
carried as a third-party C2PA assertion under the reverse-domain label
|
||
`science.transaction.wai.energy.reconstruction`, **alongside** — never instead
|
||
of — the standard `c2pa.environmental-sustainability` assertion.
|
||
|
||
`reconstructionHash` is the SHA-256 of the canonical decoded pixels, the same
|
||
digest [reconstruction-binding](reconstruction-binding.md) commits to. Both
|
||
assertions in one manifest therefore name the same decode by construction, and
|
||
a manifest whose two digests disagree is self-refuting.
|
||
|
||
## 3. What this makes checkable, and what it does not
|
||
|
||
Because a WAI reconstruction is byte-exact and reproducible on every
|
||
architecture, a verifier holding the codestream can:
|
||
|
||
- re-decode under the pinned descriptor,
|
||
- hash the pixels and confirm the energy figure is about **those** bytes,
|
||
- recompute `workUnits` from the descriptor rather than trusting it,
|
||
- and re-derive the rate.
|
||
|
||
What remains is **exactly one** unverifiable term: the joules. That is the
|
||
point of the construction, and the honest limit of it. An energy claim about an
|
||
output nobody can reproduce is not checkable at all. An energy claim about an
|
||
output anyone can reproduce is checkable except for one number — and knowing
|
||
precisely which number is the difference between a measurement and an
|
||
assertion.
|
||
|
||
An implementation **MUST NOT** describe an energy binding as proving the energy
|
||
figure. It binds the figure to a reproducible outcome; it does not attest the
|
||
measurement.
|
||
|
||
## 4. Normative rules
|
||
|
||
- The binding **MUST** carry an acquisition class (`HwShunt` / `ModelBased` /
|
||
`Estimator`, per [energy-measurement](energy-measurement.md) §2) and a
|
||
coverage statement (`Whole` / `Partial`, §5 there).
|
||
- `method` **MUST** be present and name the published protocol the figure was
|
||
obtained under. This is deliberately stricter than the standard assertion's
|
||
optional `measurementMethod`.
|
||
- A figure of zero **MUST NOT** be recorded. A reconstruction that measured
|
||
0 µJ did not consume nothing; it failed to measure, and the honest artifact is
|
||
the absence of an energy assertion rather than a zero in one.
|
||
- `microjoules` is an integer and is authoritative. `energy_kwh` in the standard
|
||
assertion **MUST** be treated as a derived interop value: one microjoule is
|
||
2.8 × 10⁻¹³ kWh, so a whole image decode lands near 10⁻⁹ kWh, where the
|
||
trailing digits of the float are artifacts of the conversion rather than of
|
||
the measurement.
|
||
- An implementation **MUST NOT** populate `carbon_kgco2e` or `water_litres`
|
||
from an energy figure and a grid-average factor while presenting the result
|
||
as measured. Those are modelled quantities; emitting them beside a measured
|
||
joule figure, in the same assertion, with no per-field provenance, is how a
|
||
model comes to be read as a measurement.
|
||
- A `Partial` figure **MUST NOT** be presented as the reconstruction's total.
|
||
|
||
## 5. Relationship to the standard assertion
|
||
|
||
Interoperability is the reason both are emitted. A validator that understands
|
||
only C2PA 2.4 reads `energy_kwh` and a populated `measurementMethod`, which is
|
||
already better than the common case. A validator that understands this
|
||
extension additionally learns how the figure was acquired, how much of the work
|
||
it covers, and which reconstruction it describes — and can check the last of
|
||
those itself.
|
||
|
||
## 6. Emitting a manifest
|
||
|
||
The assertion shapes above are emitted into an actual signed C2PA manifest by the
|
||
`c2pa_emit` module of `wai-rs`. Four decisions in that emitter are normative for
|
||
anyone writing their own, because each is a place where the obvious
|
||
implementation produces a manifest that validators reject, or that overstates
|
||
what a decoder knows.
|
||
|
||
### 6.1 The inception action is `c2pa.opened`, not `c2pa.created`
|
||
|
||
A manifest **MUST NOT** describe a reconstruction with `c2pa.created`.
|
||
|
||
C2PA 2.x requires every `c2pa.created` action to carry a `digitalSourceType`, and
|
||
that vocabulary describes how the *content* came to exist — captured, drawn by a
|
||
human, generated by a model. A decoder does not know that. It reconstructed
|
||
pixels from a codestream, and whatever was encoded could have been any of them.
|
||
Selecting `trainedAlgorithmicMedia` because a codec has a neural stage would
|
||
assert that a compressed photograph is AI-generated content, which is false, and
|
||
the vocabulary has no member meaning "decoded; origin not visible from here".
|
||
|
||
A decode is in any case not a creation. It is a conversion of an existing asset
|
||
into another representation, which C2PA already models: the codestream is a
|
||
`parentOf` ingredient, the manifest **opens** it, and `c2pa.converted` records
|
||
what was done. No action asserts a `digitalSourceType`, so no claim about the
|
||
original's origin is made anywhere — which is precisely the position a decoder is
|
||
in.
|
||
|
||
### 6.2 The codestream is carried as the parent ingredient
|
||
|
||
An emitted manifest **MUST** carry the codestream as a `parentOf` ingredient.
|
||
|
||
§3 turns on a verifier being able to re-decode. A manifest that carries the
|
||
reconstruction digest but does not name what produces it hands the verifier a
|
||
digest and no way to reach it. The digest says *which* decode the joules were
|
||
measured over; the parent ingredient says *what to decode to get there*. Both
|
||
halves, or the check §3 describes is not actually available.
|
||
|
||
### 6.3 The bindings are `created` assertions, not `gathered`
|
||
|
||
The bindings **MUST** be marked as attributed to the signer.
|
||
|
||
C2PA distinguishes assertions the signer stands behind from material gathered
|
||
elsewhere and carried along — the same distinction between a claim and hearsay
|
||
that the acquisition ladder draws inside the figure itself. These are first-party
|
||
statements: the signer measured the joules and hashed the pixels.
|
||
|
||
This is load-bearing rather than editorial. A validator looks for the inception
|
||
action among the created assertions, so an actions assertion left gathered yields
|
||
a manifest that signs without complaint and every validator then rejects as
|
||
`assertion.action.malformed` — a failure that surfaces only on the far side of a
|
||
signature.
|
||
|
||
### 6.4 What a signature does not settle
|
||
|
||
An emitted manifest signed by an untrusted certificate reaches
|
||
`ValidationState::Valid` — well-formed, signature intact, asset unmodified — and
|
||
not `ValidationState::Trusted`, which additionally requires a certificate
|
||
chaining to a known authority. An implementation **MUST NOT** present the first
|
||
as though it were the second.
|
||
|
||
The gap between them is the whole of *who says so*, and it is orthogonal to
|
||
everything §3 makes checkable: a perfectly reproducible reconstruction signed by
|
||
nobody in particular is still a claim from nobody in particular.
|
||
|
||
## 7. The operating point, and why a joule figure alone is not enough
|
||
|
||
### 7.1 Degradation-blindness
|
||
|
||
A receipt that records the joules a decode spent, and nothing about how much work
|
||
it was asked to do, is **degradation-blind**. A sink can always spend fewer joules
|
||
by decoding worse, and a figure that cannot distinguish *efficient* from
|
||
*degraded* rewards the wrong behaviour precisely where the number is meant to
|
||
carry weight.
|
||
|
||
This is not hypothetical. ISO/IEC 23001-11 carries decoding-operation-reduction
|
||
metadata whose purpose is to make a decoder do less; the sender requests a
|
||
reduction, and the receipt as specified today records only what was spent.
|
||
`energy-measurement.md` §5's recomputable-work-unit rule blocks the substitution
|
||
at the byte-exact tier, but not at `entropy-consistency`, and not for the
|
||
conventional codecs WAI already carries.
|
||
|
||
The rules below make the operating point part of the claim, so the joule figure
|
||
is scored against something rather than merely reported.
|
||
|
||
### 7.2 Request, commitment, delivery
|
||
|
||
Where a sender requests an operating point and a receiver acts on it, the receipt
|
||
**MUST** seal all three of:
|
||
|
||
| field | meaning |
|
||
|---|---|
|
||
| `op_requested` | the operating point the sender asked for |
|
||
| `op_committed` | the operating point the receiver said it would use |
|
||
| `op_delivered` | the operating point actually used |
|
||
|
||
An operating point is a class-scoped descriptor — frame rate, spatial resolution,
|
||
a complexity target — and this extension does not define its vocabulary. What it
|
||
fixes is that the three are **distinct fields**, because the interesting cases are
|
||
exactly the ones where they differ.
|
||
|
||
- A receipt **MUST NOT** carry `op_delivered` alone. A delivered figure with
|
||
nothing to score it against is the degradation-blind case §7.1 describes.
|
||
- `op_committed` **MUST** be recorded as what the receiver stated, even where it
|
||
differs from the request. A commitment that silently becomes the request is not
|
||
a commitment.
|
||
- Where `op_delivered` differs from `op_committed`, the receipt **MUST** record
|
||
both and **MUST NOT** claim the commitment was met.
|
||
- A sink that honoured an operation-reduction request **MUST NOT** claim
|
||
`decode-equivalence` for the result — see [determinism-tiers](determinism-tiers.md)
|
||
§2, *What a tier covers*.
|
||
|
||
This converts a recorded number into a number measured against a promise. Neither
|
||
the prescriptive standards nor the measurement standards provide that pair: one
|
||
says what should be spent, the other what was, and nobody scores the second
|
||
against the first.
|
||
|
||
### 7.3 The residual
|
||
|
||
When a declared complexity or operating-point descriptor and a measured energy
|
||
binding both cover the same reconstruction, the receipt **MUST** carry the
|
||
**residual** — the signed difference between the energy the descriptor implies
|
||
and the energy measured.
|
||
|
||
- The residual **MUST** be computed over the same work unit as the measurement
|
||
(`energy-measurement.md` §5), or it compares two different things and means
|
||
nothing.
|
||
- A residual **MUST NOT** be reported without the acquisition class of the
|
||
measured term. A residual against an `Estimator` figure is a difference between
|
||
two predictions.
|
||
- An implementation **MUST NOT** suppress a residual because it is large. The
|
||
large ones are the informative ones; suppression converts a falsifiable claim
|
||
into an unfalsifiable one.
|
||
|
||
The residual is what makes the predictive half checkable. A complexity descriptor
|
||
is a prediction about energy, and until something records what actually happened
|
||
against it, the prediction is never wrong. This closes that loop in the artifact
|
||
rather than in a report.
|
||
|
||
### 7.4 Companion capability
|
||
|
||
Green-metadata semantics are registered the way
|
||
[`wai.meta.hdr10plus`](../research/media-codec-registry.md) and `wai.meta.dovi`
|
||
are: the capability names the descriptor class — complexity metrics, quality
|
||
recovery, display adaptation — and the sink supplies the decoder. **No carriage
|
||
is adopted**: ISOBMFF and DASH carriage of green metadata is somebody else's
|
||
layer, and WAI naming a descriptor does not make WAI responsible for moving it.
|