Skip to main content

WAI Extension: Sink Energy

Mirrored from the canonical text at commit 260cbd09 ().

Status: Draft. Registers the record wai.sink.energy: what decoding cost at the sink, per stream and per segment, with the acquisition class of energy-measurement and its uncertainty, and how one viewing session’s energy splits into its origin, its relay, the sink’s decode and its display. Three signed records: a sink’s decode table (§4), a measured figure per registered capability, decode path and sink energy profile, produced by a pinned procedure and committed with its raw readings; a segment receipt (§5), the decode energy of one segment of one stream, measured, taken from the sink’s own table, estimated, or stated as unmetered; and a session receipt (§6), the per-hop split over the four hop roles a stream log uses (origin, relay, sink decode, display), each hop a figure with its own class, the unmetered marker where the hop took place unmeasured, or absent where the sink states nothing about it. The counters, scopes, idle baselines and windows are energy-measurement §9’s sink profiles. No new transport, no change to the wire format or to SPEC §4’s algorithm. The reference implementation is the sink_energy module of wai-rs (feature sink_energy), whose readers are in sink_meter and whose table procedure is the binary wai_sink_table; the corpus is live-conformance/sink-energy/, with the measured tables of the reference sinks under its tables/, and its second implementation is live-conformance/sink_energy_verify.py. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.

Texts read for this revision: RFC 8032 (Ed25519); RFC 8785 (JSON Canonicalization Scheme); RFC 8259; FIPS 180-4 (SHA-256); JCGM 100:2008 (GUM) §4.3.7 and F.2.2.1; Commission Delegated Regulation (EU) 2019/2013, for the on-mode power a display’s energy label states; arXiv 2402.09001, 2603.18305 and 2511.00707, for §4.6’s outside measurements of decode energy. A section number in this text is this extension’s unless it names another document.

1. Scope

In scope: the three records, their signatures and identities (§3); the decode table, the procedure that produces it, how each row’s status and figure follow from its rounds, and outside measurements of decode energy (§4); the segment receipt and its four methods (§5); the session receipt and its per-hop split (§6); verification (§7); the reasons (§8); and what a conforming implementation publishes (§9).

Out of scope: a transport; how a counter works, which energy-measurement §9 states per platform; the energy of networks, which no sink can read and this extension never attributes to a byte; and what a party does with a figure.

Relationship to other documents:

Relationship to the core spec: wai.sink.energy is a record (SPEC §5). It names no payload format and is not dispatchable.

2. Terms

3. The records, their signatures and identities

Each record is one JSON object (RFC 8259). Its body is the object without its sig member. A record is signed with Ed25519 (RFC 8032) by the key its signer member names, 64 hexadecimal digits, over

domain ‖ JCS(body)

where JCS is RFC 8785’s canonical form, and sig is the 64-byte signature as 128 hexadecimal digits. A signature is verified as WAI verifies every signature (SPEC §7, Signatures). The record’s identity is

SHA-256(id-domain ‖ JCS(body) ‖ signature bytes)
recordfirst memberdomainid-domain
decode table (§4)"wai_sink_table": 1wai:sink-table\x01wai:sink-table-id\x01
segment receipt (§5)"wai_sink_segment": 1wai:sink-segment\x01wai:sink-segment-id\x01
session receipt (§6)"wai_sink_session": 1wai:sink-session\x01wai:sink-session-id\x01

The first member names the record and its version; every member the tables below list is required, and a record with a member missing, a member they do not list, or a value of another type is refused (record_malformed). Terms are compared as exact strings.

4. The decode table

A decode table is a sink’s measured decode energy: for each registered capability and decode path, on each profile the sink can read, one figure per completion of a stated work item, from repeated bracketed measurements, with every round’s values in the record and every raw reading in a file it binds.

4.1 The record

membertypemeaning
wai_sink_tableinteger1
signer32 B hexthe key that signs the table
proceduretermwai-sink-table/1 (§4.4)
procedure_sha25632 B hexSHA-256 of the procedure text committed with the table
readings_sha25632 B hexSHA-256 of the readings file committed with the table (§4.3)
machineobject{ "os": string, "arch": string, "processor": string, "cores": integer, "memory_gib": integer }
buildobjectthe decoders’ build, as jwp-receipts §2.4.8 writes one: { "profile": "release" or "debug", "toolchain": string or null, "target": string or null }
measuredstringthe date the rounds were taken, YYYY-MM-DD
roundsintegerrounds per row: odd, at least 7
sample_usintegerthe sampling interval every bracket was read at, in microseconds
countersarraythe sink’s survey: one { "profile": term, "status": term, "detail": string } per counter it looked for, in ascending order of (profile, detail); status is one of energy-measurement §9.1’s five, or implausible (§9.3 there)
rowsarraythe rows (§4.2), in strictly ascending order of (capability, path, decoder, profile), strings by their bytes and a null profile first

4.2 A row

membertypemeaning
capabilitystringa capability the registry lists (registry/capabilities.json)
pathtermsoftware or hardware
decoderstringthe decoder: builtin:<crate>@<version> as jwp-receipts §2.4.12 writes one, or platform:<interface> for a decoder of the platform, <interface> 1 to 64 of a–z, 0–9 and -
profileterm or nullthe profile read: macos-task, macos-gpu, linux-rapl or linux-nvml (energy-measurement §9.2, §9.3), whose minimum windows are 1 s, 1 s, 1 s and 5 s; null only in a row absent for no_decoder
fabricsarraythe fabrics the profile’s reading covers (energy-measurement §9.1), exactly: ["cpu"] for macos-task, linux-rapl and estimator-cpu-time/1, ["gpu"] for macos-gpu and linux-nvml; empty in an absent row
coverageterm or nullPartial (§4.5); null in an absent row
unittermimage, frame, content-ms or byte
unitsintegerunits per completion, at least 1
width, heightinteger or nullthe decoded picture’s size for image and frame; null for the other units
workersintegerthe burst’s workers N, a power of two; 0 in an absent row
statustermfigure, relative, unmetered or absent (§4.5)
reasonterm or nullwhy a row is unmetered or absent (§4.5, §8); null otherwise
roundsarrayeach round’s { "idle": summary, "busy": summary, "window_us": integer, "completions": integer }, in the order taken; empty in an absent row
medianinteger or nullthe index in rounds of the median round (§4.5); null unless figure or relative
rangearray or null[least, greatest] of the rounds’ figures; null unless figure or relative
joules_micro, energy_provenance, energy_uncertainty, energy_counter_filtering, energy_calibration_ref—the figure per completion and its class (§2); unmetered unless figure or relative

4.3 From readings to a round

The readings file is the JCS form (RFC 8785) of a JSON object, and readings_sha256 is the SHA-256 of those bytes. The object is { "wai_sink_readings": 1, "rows": [ … ] }, one entry per row of the table in the table’s order, each { "capability", "path", "decoder", "profile", "rounds": [ { "idle": [[d, t], …], "busy": [[d, t], …], "completions": integer } … ] }. Each [d, t] is one interval of the bracket: d the counter’s advance over it, in nanojoules, across its wrap; t its length, in microseconds, on a monotonic clock. The busy bracket’s first read is taken as the window opens and its last as it closes, so the window is the sum of its intervals’ t, and completions is the count of completions between those two reads.

A round’s values follow from its intervals, with n the intervals and pᵢ = ⌊(2000·dᵢ + tᵢ) / (2·tᵢ)⌋ each interval’s power in microwatts:

A verifier holding the readings file recomputes every round and requires the table’s values (table_readings_mismatch), and requires its SHA-256 to be readings_sha256.

4.4 The procedure wai-sink-table/1

  1. Survey. For each profile the platform has, read the counter at the sampling interval for at least 2 s with nothing of the sink’s running, and record its status under energy-measurement §9.1. A profile whose counter is not live gives no rows but absent ones. A profile whose own sampling interval is not the table’s (linux-nvml’s is 1 s) is surveyed, and gives no rows in this table.
  2. Work items. For each capability with a decoder in the sink, a fixed input, written by the procedure from fixed seeds or taken from a committed vector, and decoded once with its output checked against its reference before any round: a decode whose output is wrong is not timed and not metered. A completion is one decode of the whole item. The procedure text states each item, its digest, its units and its size.
  3. Rounds. For each round, and in each round for each row in an order rotated by one each round: settle for 2 s, so that a processor package’s draw falls back from the burst before it (read 200 ms after a burst, the reference Linux sink’s package still drew several times its resting draw); read the idle bracket of the row’s counter over the decode workers parked at their start barrier; release N workers together as the window opens, and read the busy bracket while each decodes the item over and over, counting each completion; close the window; stop and join the workers. The window opens from rest (energy-measurement §2.3). N is the sink’s worker count rounded down to a power of two (jwp-receipts §2.4.12, threads).
  4. Record. Write every interval to the readings file, every round’s values and each row’s status, figure and class to the table (§4.5), and sign the table.

The procedure text committed with a table states the steps above as the tool ran them: its command line, the sampling interval and bracket lengths, the rounds, the work items with their digests, the workers, and the decoders’ build.

4.5 A row’s status and figure

Absent. A row is absent when there is nothing to measure: no_decoder (the sink has no decoder for the capability on the path; profile null), no_work_item (the sink decodes it, and the procedure defines no work item for it), no_hardware_path (the platform’s decoder for it is not a hardware one on this sink, or its output differed from the software path’s), or no_counter (the row’s profile is not live in the survey). An absent row has no rounds, workers 0, and the unmetered marker; it states what was not measured, never a figure of zero.

A round’s figure. Every other row has exactly rounds rounds. Round r is the bracket { idle, busy, window_us, completions, in_flight: workers, opening: from-rest } of energy-measurement §6.2. It gives a figure F_r, with least declaration p_r, when it passes, in order:

  1. too_few_samples: each bracket has at least 2 intervals;
  2. rail_not_live: each bracket’s rail is live: sd_uw above 0, live_intervals at least 5, longest_live_run at least 2, 5 · live_intervals ≥ 4 · n, and the bracket spans at least 300 ms (the idle bracket n · sample_us, the busy bracket window_us);
  3. window_short: window_us is at least the profile’s minimum window;
  4. empty_burst: completions is at least 1;
  5. no_marginal: the busy mean is above the idle mean;
  6. below_attribution_floor: M ≥ sd_idle (energy-measurement §4);
  7. figure_zero: F_r, §6.2’s figure, is at least 1;
  8. not_declarable: F_r is at most 2⁵³ − 1 and §6.2’s least p_r at most 2³² − 1.

The row. If any round gives no figure, the row is unmetered, and its reason is the reason of the first round in rounds that gives none, the first rule it breaks. Otherwise the rounds are ordered by (F_r, r) and the median is the middle one. The row’s verdict is the median round’s (energy-measurement §6.2): clean gives figure, usable for relative comparison gives relative, and noisy or unusable gives unmetered with reason noisy. A figure or relative row seals:

A row whose max(p_median, q) exceeds 2³² − 1 cannot declare it (energy-measurement §2.7): it is unmetered, with reason not_declarable, and like every unmetered row it keeps its rounds and has median and range null.

A relative row’s figure is for comparing two rows of the same table measured round by round together; a reader MUST NOT present it as an absolute figure (energy-measurement §4; staged-measurement §8, its paragraph 8.3). An unmetered row keeps its rounds, so the measurement that failed stays auditable.

Coverage. A figure is Whole only where its profile’s scope covers every fabric the decode runs on. No profile of this revision does: none reads a media engine (energy-measurement §9.2), and none reads memory. So every row that is not absent, and every segment that is not unmetered, is Partial in this revision, and a Whole one is refused (table_row_figure, segment_method_class); Whole is kept for a profile a later revision registers.

4.6 Outside measurements of decode energy (informative)

The three points below are outside measurements of decode energy. Their figures are not figures of a WAI decoder or of a reference sink: no record of this extension states them, and no rule of it reads them. Each is cited by its arXiv identifier and the table it is read from, with what was measured and against what.

  1. A platform’s hardware decoder, against software decoders of the same format. arXiv 2402.09001, Table IV. Over AVC, VP9, HEVC and AV1, each in a random-access and a low-delay configuration, a hardware decoder spent from 0.89% to 8.86% of the energy of a software decoder of the same format, and from 4.44% to 8.86% of the energy of the optimised software decoders with vector instructions enabled. The figures are dynamic energy: the energy measured at idle is subtracted. The software decoders ran single-threaded on a desktop processor, read by the processor’s own energy counter; the hardware decoders ran on a single-board computer’s video unit, read at its power input by an external meter. The point sets two decode paths side by side as two machines built them.
  2. Fewer frames, chosen by the encoder. arXiv 2603.18305, Table V, its row for all sequences. Decoding energy was 17.60% lower, encoding energy 17.46% lower and the bitrate 3.38% lower, each a Bjøntegaard delta at equal matched PSNR (mPSNR, computed against the source), against encoding each sequence at its source’s 120 frames per second. A trained classifier picks, per sequence and per rate-factor setting (the table covers four), the frame rate the encoder codes at, the source’s or a lower one; where it is lower, the decoder decodes fewer frames than the source has. One software encoder and one software decoder of HEVC were measured, by the processor’s own energy counter, idle subtracted.
  3. Lower resolution or coarser quantisation, chosen by the encoder. arXiv 2511.00707, Table 4, its row ρ = 0.05. Decoding energy was 53.54% lower and encoding energy 51.22% lower, for an average loss of 1.68 VMAF points and 3.67 dB PSNR, against the configuration chosen with no loss allowed (ρ = 0). Per sequence, the encoder takes, of the resolutions and quantisers whose predicted VMAF is within 5% of the best predicted, the one of least predicted energy. One software encoder and one software decoder of VVC were measured on UHD sources at 60 frames per second, by a software tool reading the processor’s energy counter and the graphics processor’s; the paper does not state whether the idle energy is subtracted, nor whether Table 4’s savings are the measured or the predicted energy of the configurations chosen.

How they bear on this extension:

5. The segment receipt

A segment receipt is a sink’s statement of what one segment of one stream cost it to decode: the sink-decode hop’s figure for that segment (role 3 of §6.2). A sink signs one per segment it decoded, in order, each naming the one before it. Where the sink also keeps a stream log, the log’s segment record states the same figure and class for role 3 (stream-termination §4.6), and the receipt here is where its bracket, table row or estimator inputs are.

5.1 The record

membertypemeaning
wai_sink_segmentinteger1
signer32 B hexthe sink’s key
session32 B hexfresh random bytes per viewing session, derived from nothing that identifies a person, a device or an account
stream32 B hexthe stream: for a track of a room, live-metering §2’s track digest; otherwise SHA-256 of the stream’s address as the sink fetched it, without query or fragment
segmentintegerthe segment’s index in this session’s reading of the stream, from 0
prev32 B hex or nullthe identity (§3) of this session’s receipt for segment segment − 1 of the stream; null exactly when segment is 0
object32 B hexthe content hash (jwp-receipts §2.1) of the segment as decoded
capability, path, decoder, unit, units, width, height—as a table row has them (§4.2), for this segment: units is the units the segment decoded
media_usintegerthe segment’s content duration, in microseconds, at least 1
methodtermmeasured, table, estimator or unmetered (§5.2)
profileterm or nullthe profile the figure comes from; null exactly when unmetered
fabrics, coverage—as a table row has them; empty and null exactly when unmetered
joules_micro, energy_provenance, energy_uncertainty, energy_counter_filtering, energy_calibration_ref—the segment’s decode energy and its class (§2)
bracketobject or nullmeasured: { "idle": summary, "busy": summary, "window_us": integer, "sample_us": integer }; otherwise null
tableobject or nulltable: { "id": 32 B hex, "row": integer, "per_completion_uj": integer, "units_per_completion": integer }; otherwise null
estimatorobject or nullestimator: { "method": "estimator-cpu-time/1", "cpu_us": integer, "active_mw": integer, "basis": string, "relative_ppm": integer }; otherwise null
reasonterm or nullunmetered: why (§8, unmetered reasons); otherwise null

5.2 The four methods

measured. The sink read its counter over the segment’s own decode, under a profile of energy-measurement §9.2 or §9.3, and seals OnChipCounter (or CalibratedInstrument). The busy window is bounded: it opens as the segment’s first unit is submitted to the decoder and closes as its last is output, and no unit of another segment is decoded inside it. The work the window paid for is then exactly the segment: one completion, with no part-done unit at either edge, which removes the completion-count term by construction (energy-measurement §2.3). The idle bracket is the last the sink read under the profile with its decode parked. With M, T, n_i, n_b, s_i, s_b as in energy-measurement §6.2, these are its §6.2 forms with Wn = Wd = 1 and N = 0:

F = ⌊(2·M·T + 10⁶) / (2·10⁶)⌋                       the segment's figure, µJ
p = the least integer with p² · K ≥ P, where
K = 12 · n_i · n_b · F²
P = 12 · T² · (s_i² · n_b + s_b² · n_i)  +  10¹² · n_i · n_b

The receipt is accepted when both brackets are live (as rule 2 of §4.5 reads them, the idle span n · sample_us), window_us is at least the profile’s minimum window, M ≥ s_i, joules_micro is F and at least 1, energy_uncertainty.window_us is T, and relative_ppm ≥ p. Below a ratio of 10 the figure is sealed and verifiable but not publishable (energy-measurement §4): a reader derives the verdict from bracket.

table. The sink took its figure from a row of a decode table:

joules_micro = ⌊(2 · per_completion_uj · units + units_per_completion) / (2 · units_per_completion)⌋

at least 1. Its class is ModelBased when the table’s signer is the receipt’s signer — a model calibrated on the host it describes (energy-measurement §2) — and Estimator when it is another key’s table, a figure measured on another machine. Neither carries evidence. A verifier holding the table requires: its identity is table.id; row table.row exists, has status figure, and the receipt’s capability, path, decoder, profile, unit, width, height, fabrics and coverage; per_completion_uj is the row’s joules_micro and units_per_completion its units.

estimator. Energy-measurement §9.4’s estimator-cpu-time/1: profile names it, joules_micro is its E over cpu_us and active_mw and at least 1, basis is non-empty, relative_ppm is at least 1, and the class is Estimator. A reader presents the figure with the stated uncertainty estimator.relative_ppm.

unmetered. No figure: the unmetered marker, profile, fabrics, coverage, bracket, table and estimator empty, and reason one of §8’s unmetered reasons.

HwShunt is never a segment’s class (energy-measurement §2.6, hwshunt_forbidden).

5.3 The chain

A verifier holding a session’s receipts for one stream requires (segment_chain_broken): the same session, stream and signer throughout; segment 0 to k with none missing or repeated; and each prev the identity of the receipt before it. A stream whose sink stopped decoding has a last segment; it has no receipt after it.

6. The session receipt and the per-hop split

6.1 The record

membertypemeaning
wai_sink_sessioninteger1
signer, session32 B hexas in the segment receipts it closes
streamsarrayper stream, { "stream": 32 B hex, "segments": integer, "last": 32 B hex }: its segment receipts’ count and the identity of its last; at least one, in strictly ascending order of stream
media_usintegerthe sum of the segments’ media_us
presented_usintegerthe time the session’s content was on screen, in microseconds
displayobject or nullthe display’s declaration (§6.3), or null
hopsarraythe session’s hop entries (§6.2), in strictly ascending order of role, each role at most once

6.2 The hops, and a hop entry

The hops are the four roles of a delivery’s energy, and they are one table with a stream log’s hop entries (stream-termination §2, Hop, and §3.5): 1 origin, 2 relay, 3 sink decode, 4 display. A hop is in one of three states, by the same rule:

membertypemeaning
roleinteger1 origin, 2 relay, 3 sink decode, 4 display
joules_micro, energy_provenance, energy_uncertainty, energy_counter_filtering, energy_calibration_ref—the hop’s figure and its own class (§2), or the marker
unmeteredterm or nullfor the marker, why the hop has no figure: not_reported, hop_unmetered, hop_shared, unmetered or display_undeclared; null for a figure
coverageterm or nullnull for the marker; for a figure, Whole for the display (the estimate is of the whole panel’s draw), Partial for the origin and the relay (a hop’s record does not state what its figure covers), and the sink decode’s by §6.3
sourceobject or nullfor the origin and the relay with a figure: the hop record the entry restates (§6.4); otherwise null

Which hops have an entry:

A figure entry’s figure is at least 1 and its class coheres with it (energy-measurement §2); a marker entry has coverage and source null and a reason its role may have: not_reported (the sink holds no figure for the hop), hop_unmetered (the hop’s own record carries the marker) or hop_shared (§6.4) for the origin and the relay; unmetered for the sink decode; display_undeclared or unmetered for the display (split_part_invalid). Each hop carries its own class: the receipt states no total over its hops, and a reader MUST NOT add hops of different classes into one figure, nor add the display to any decode figure (energy-measurement §9.5).

6.3 The figure of each hop

Sink decode (3). Read from the session’s segment receipts (§5), each of which is the sink-decode hop’s figure for its segment, the figure a stream log’s segment receipt states for role 3 (stream-termination §4.6). With the metered segments those whose method is not unmetered:

Display (4). Energy-measurement §9.5’s estimator-display/1 over the session’s presented_us, with the declaration

{ "method": "estimator-display/1", "panel_class": "backlit" or "emissive", "on_mode_mw": integer,
  "reference_nits": integer, "nits": integer, "basis": string, "relative_ppm": integer }

on_mode_mw, reference_nits and relative_ppm at least 1, nits at least 0 and basis non-empty. The entry is a figure with class Estimator when the declaration is present and its E is at least 1; the marker display_undeclared when display is null, and the marker unmetered when E is 0. A reader presents the figure with the stated uncertainty display.relative_ppm, as an estimate, apart.

Origin (1) and relay (2). A hop’s own signed figure, where this session was the hop’s sole user (§6.4), or the marker: not_reported when the sink holds no such figure, hop_unmetered when the hop’s record carries the marker, hop_shared when the session shared the hop with other sessions.

6.4 A hop’s figure, where the session was its sole user

source = { "kind": "live-metering-hop" or "other", "record": 32 B hex, "hop_joules": integer,
           "hop_class": class label, "share_num": integer, "share_den": integer }

record is the hop’s record’s digest: for live-metering-hop the digest of live-metering §3.5, and for other the SHA-256 of the record’s bytes as published. hop_joules and hop_class are its figure and class label, hop_joules at least 1. share_num is the busy time this session accrued on the hop and share_den the busy time every user of the hop accrued over the hop’s span, 1 ≤ share_num ≤ share_den.

A hop’s figure is about every session it carried, and it is not divided among them by the time each kept it busy: busy time does not apportion energy (energy-measurement §9.1). The entry restates the hop’s figure only where this session was the hop’s sole user, at least 99% of its busy time:

100 · share_num ≥ 99 · share_den
joules_micro = ⌊(2 · hop_joules · share_num + share_den) / (2 · share_den)⌋

and then joules_micro is at least 1, its attribution is rail (energy-measurement §9.1), and its class and evidence are the hop’s: energy_provenance is hop_class. A hop this session shared below that gives no figure: its entry is the marker, with reason hop_shared. A HwShunt hop gives hwshunt_forbidden.

For live-metering-hop the record is a per-hop session record WMH1 (live-metering §3.1), and share_den is the sum of its nine subscriber_us: share_num is the sink’s statement of its own subscriber-microseconds on that hop, which the record does not hold (live-metering §3 keeps no per-viewer entry). A verifier holding the record’s bytes requires: they read as a per-hop record of the room their own room field names, its signature verified (live-metering §3.6); their digest is record; its joules is hop_joules, its class label is hop_class and its evidence the entry’s; and share_den is its subscriber-microseconds’ sum (split_hop_mismatch). For other, the arithmetic and the class rule are checked from the receipt alone.

6.5 Against the segment receipts

A verifier holding the session’s segment receipts requires (session_streams_mismatch) that each verifies (§7), names this session and signer, and that per stream they form a chain (§5.3) whose count is segments and whose last receipt’s identity is last, with no stream left out; and that media_us is the sum of their media_us. It then requires the sink-decode entry to be what §6.3 gives (split_decode_mismatch).

7. Verification

A verifier reads a record and checks it in the order below; the first rule broken is the refusal.

  1. Shape (record_malformed). The record is a JSON object with no duplicate member; it has the member §3 names it by, with the value 1 (JCS fixes no order of members, so “first” in §3 is the order a producer writes, not a rule); it has exactly the members its tables list, each of the type they give. Beyond the types:

    • a hex member has the stated length in lowercase hexadecimal digits; a term is one of the terms its table lists; an integer is from 0 to 2⁵³ − 1;
    • a bracket summary has exactly its five integer members, and a round exactly its four members;
    • width and height are integers of at least 1 for image and frame, and null for the other units; units is at least 1;
    • decoder follows its grammar (§4.2);
    • every member of a fabrics array is one of cpu, gpu, media and npu (energy-measurement §9.1), none twice;
    • measured is a date YYYY-MM-DD;
    • a source (§6.4) and a display (§6.3) have exactly their members, of their types;
    • each of hops has exactly the members of §6.2, its role from 1 to 4, the entries in strictly ascending order of role;
    • a capability is one registry/capabilities.json lists;
    • a table’s counters are in ascending order of (profile, detail), and its machine and build have exactly their members;
    • a segment’s media_us is at least 1, and its prev is null exactly when its segment is 0;
    • a session’s streams are at least one, in strictly ascending order of stream;
    • hop_class is a string.
  2. Signature (signature_invalid): sig over the body under signer (§3).

  3. Classes. For each class the record carries, in this order — a table’s rows in order; the segment’s; a session’s hop entries in the order of their role, each entry’s class and then its source’s hop_class — three rules in turn: a HwShunt label is refused (hwshunt_forbidden); then a class beside a joules_micro of 0, or a non-zero joules_micro beside no class, is refused (unmetered_as_zero); then a label energy-measurement §2 does not name, a class whose evidence members are not exactly those its §2.7 requires (as jwp-receipts §2.4.5 writes them, null where a class carries none), an energy_uncertainty with a member of 0 or a relative_ppm above 2³² − 1, a hardware declaration below §2.3’s resolution floor, or a hop_class that is not a label of a class, is refused (energy_class_invalid).

  4. A decode table. rounds is odd and at least 7, and each row not absent has exactly that many rounds (table_rounds_invalid); the rows are in strictly ascending order (table_row_order); then each row in order, by §4.5:

    • its status and reason (table_row_status): an absent row has a reason of the four absent ones, no rounds, workers 0, profile null exactly for no_decoder, empty fabrics, coverage, median and range null; an absent or unmetered row carries the unmetered marker; any other row has workers a power of two and the status and reason its rounds give; and a row’s profile has an entry with status live in counters exactly when the row is not absent for no_counter (null profiles aside);
    • its figure (table_row_figure): fabrics its profile’s, and for figure and relative rows coverage Partial, median (an index into rounds, from 0) and range the ones its rounds give, joules_micro the median’s figure, the class OnChipCounter with filtering Unknown (energy-measurement §9.2, §9.3) or CalibratedInstrument, and window_us the median round’s; for unmetered rows coverage Partial and median and range null;
    • its declaration (table_row_declaration): relative_ppm ≥ max(p_median, q);

    and then, once every row has passed, holding the readings file: its SHA-256 is readings_sha256, it has one entry per row naming the row’s capability, path, decoder and profile, each row’s rounds as many as the table’s, and every round’s values are the ones §4.3 gives (table_readings_mismatch).

  5. A segment receipt.

    • Its method (segment_method_class): measured has bracket and no table, estimator or reason, a profile of §9.2 or §9.3 of energy-measurement, and a hardware class; table has table and no other, a profile of those, and ModelBased or Estimator; estimator has estimator and no other, the profile estimator-cpu-time/1, and Estimator; unmetered has none of the three, profile, coverage null, empty fabrics, the unmetered marker and a reason of §8’s unmetered reasons. Every metered segment has fabrics its profile’s and coverage Partial, and reason null.
    • measured (§5.2): both brackets live (segment_rail_not_live); window_us at least the profile’s minimum window (segment_window_short); M ≥ s_i (segment_below_floor); joules_micro F, at least 1, and the declared window_us T (segment_figure_mismatch); relative_ppm ≥ p (segment_declaration_below).
    • table (§5.2): a verifier holds the table whose identity is table.id when one is given to it; a held table that does not pass steps 1–4 is refused here (segment_table_mismatch), and table.row is an index into its rows, from 0. The figure is the formula’s and at least 1, the class ModelBased exactly when the verifier holds the table and its signer is the receipt’s, and otherwise Estimator where it holds the table; and, holding the table, everything §5.2 requires of the row (segment_table_mismatch). A verifier that does not hold the table checks the formula only.
    • estimator (§5.2): the figure is E over its inputs and at least 1, basis non-empty and relative_ppm at least 1 (segment_estimator_mismatch).
    • Holding the stream’s receipts: §5.3 (segment_chain_broken), after each receipt has passed every step above.
  6. A session receipt, in order:

    • the hop entries as §6.2 reads them (split_part_invalid): the sink decode and the origin have an entry, the display has one exactly when presented_us is above 0; then, in the order of their role, a figure entry has unmetered null, a figure of at least 1, the coverage §6.2 gives it (for the sink decode, either of the two here, its value checked against §6.3 below) and a source exactly when its role is the origin’s or the relay’s; a marker entry has coverage and source null and a reason its role may have;
    • the display declaration, where there is one, within its ranges (§6.3), and the display entry, where there is one, against §6.3 (split_display_mismatch);
    • the origin’s then the relay’s entry, where they have a figure, against §6.4: the sole-user rule, the figure, the class and evidence, and, holding the record, the record (split_hop_mismatch);
    • holding the segment receipts (a verifier given none holds none), §6.5: each receipt verifies (steps 1–5) and the streams agree (session_streams_mismatch), then the sink-decode entry is what §6.3 gives (split_decode_mismatch).

An accepted record establishes that its signer stated it. The arithmetic between its values is checked, and so are its readings, its table and its hop records where the verifier holds them. The values themselves — the counter readings, the completions, the declared inputs of an estimate — are the signer’s statements (energy-measurement §5): a record that invents every value consistently passes every check.

8. Reasons

reasonrefused when
record_malformeda record does not read in its shape (§3, §7 step 1)
signature_invalidits signature does not verify (§3)
hwshunt_forbiddena class, or a hop’s class, is HwShunt (energy-measurement §2.6)
energy_class_invalida class label is unknown, or its evidence is missing, extra or below the resolution floor
unmetered_as_zeroa class sits beside a zero figure, or a non-zero figure beside no class
table_rounds_invalidrounds is even or below 7, or a row has another count of rounds
table_row_orderthe rows are not in strictly ascending order
table_row_statusa row’s status or reason is not the one its rounds give (§4.5)
table_row_figurea row’s median, range, figure, class or window is not the one its rounds give
table_row_declarationa row declares less than max(p_median, q)
table_readings_mismatchthe readings file’s digest, or a round recomputed from it, differs
segment_method_classa segment’s members or class do not fit its method
segment_rail_not_livea measured segment’s bracket is not live
segment_window_shorta measured segment’s window is below its profile’s minimum
segment_below_floora measured segment’s marginal is below the idle deviation
segment_figure_mismatcha measured segment’s figure is not its bracket’s F, or its window not T
segment_declaration_belowa measured segment declares less than its bracket’s p
segment_table_mismatcha table segment’s figure, class or row disagrees with its table
segment_estimator_mismatchan estimated segment’s figure or inputs are not the method’s
segment_chain_brokena stream’s receipts do not form its chain
split_part_invalida hop entry is missing where §6.2 requires one, or is neither a figure nor a marker with its reason
split_display_mismatchthe display entry is not the estimator’s over the declaration
split_hop_mismatchan origin or relay entry’s busy time, class or record disagrees
split_decode_mismatchthe sink-decode entry is not what the segment receipts give
session_streams_mismatchthe streams, counts, last receipts or media_us disagree with the segment receipts

The row reasons a table row states are §4.5’s: no_decoder, no_work_item, no_hardware_path, no_counter, the round rules too_few_samples, rail_not_live, window_short, empty_burst, no_marginal, below_attribution_floor, figure_zero and not_declarable, and noisy. The unmetered reasons a segment states are no_counter, rail_not_live, window_short, no_marginal, below_attribution_floor, figure_zero, not_declarable and not_reported.

9. Conformance

10. Security and privacy considerations