WAI across fabrics: each step on the fabric that does it with the least measured energy (packaging §11.6) #438

Closed
dcharlot wants to merge 13 commits from wai/cross-fabric into wai/pack-efficiency

2026-10-22

Transaction Science
docs/research: a metered pack sealed with its fabric record
Some checks failed
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 34s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m22s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 2m18s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 27s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m3s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m21s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 11m50s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 5s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 1m52s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 23m42s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m12s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m5s
wai-pack / wai-pack · linux (pull_request) Successful in 1m33s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m20s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m37s
wai-pack / wai-pack · the floor through a media prober (pull_request) Failing after 17s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m23s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 2m40s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 4m9s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 7m15s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 35m1s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 6m1s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 9m18s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 13m39s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 19s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 55s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 5m17s
wai-pack / wai-pack · macos (pull_request) Successful in 2m50s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 2m28s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 2m35s
The av1-360 pack with --fabric gpu --meter fabric, run when the GPU was otherwise idle:
a ModelBased figure of 2,248.4 J divided into the CPU's 475.4 J (task) and the GPU's
1,773.0 J (rail), the claim's steps the search, SSE and hashes on the GPU and the rest on
the CPU, accepted by wai-pack verify and by pack_verify.py; and the same pack of run B,
refused pack-meter a minute later when the GPU was shared.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 07:25:56 -04:00
Transaction Science
docs/research: WAI across fabrics, the research and the measurements
Some checks failed
WAI energy receipts / energy receipts · linux (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI HTTP delivery / WAI HTTP · does this change touch it (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Has been cancelled
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Has been cancelled
WAI neural sink gates / does this change touch it (pull_request) Has been cancelled
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Has been cancelled
wai-pack / wai-pack · does this change touch it (pull_request) Has been cancelled
wai-pack / wai-pack · linux (pull_request) Has been cancelled
wai-pack / wai-pack · linux-arm64 (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
wai-quantum studio and desktop / does this change touch it (pull_request) Has been cancelled
wai-quantum studio and desktop / studio · browser (pull_request) Has been cancelled
wai-quantum studio and desktop / desktop app · macos (pull_request) Has been cancelled
wai-web wasm32 / does this change touch it (pull_request) Has been cancelled
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Has been cancelled
Which fabric can run each step of a WAI pack and verify, on the fleet as probed, through
which API, with the primary sources: VideoToolbox and the media engines (AV1 decode from
M3; no AV1 encode on any Apple chip through the 2026 launches), WGSL, Metal and CUDA
integer semantics, the neural engine (FP16: no exact step), NVENC/NVDEC, QSV, VCN and
Vulkan Video; AV1 §7.2's exactness and film grain; hardware encoders' irreproducibility;
and energy without root on macOS 27 (only IOReport's GPU rail is live; the kernel's
per-task CPU energy; per-client GPU time; the sole-user rule), Linux and Windows. The
design choice each finding decided, what was judged unsound, and the big-buck-bunny
measurements: packages byte-identical on the GPU, the media engine's pictures dav1d's,
and joules per fabric against the CPU baselines.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 07:08:03 -04:00
Transaction Science
wai CHANGELOG, claim-conformance README: steps on every fabric
The changelog's v0.4.0 entry for packaging §11.6, the measurement claim's fabric record,
wai-pack-gpu, wai-pack's fabric dispatch, meter and floor-decode, and their conformance;
the claim corpus's README describes the fabric record's vectors.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 06:45:44 -04:00
Transaction Science
wai-pack tests: a share on a fabric no step ran on is refused for itself
The fabric test held a split with a GPU share and no GPU step to pack-measurement-claim,
which the claim's own sum rule would also give were the share silently dropped; it now
requires the packer's reason, so the refusal in fabric_record is what the test holds.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 06:45:24 -04:00
Transaction Science
wai-pack-gpu: wait for a buffer map itself, not only for its submission
With several threads polling one device, a map's callback can run inside another
thread's poll, after this thread's wait for its submission has returned. The read then
found no result and handed the call back to the CPU: correct, since the CPU computes the
same vectors, but it happened to 15 of 24,930 motion-search calls of a 12-piece pack of
big-buck-bunny. The read now waits for the callback, polling without blocking until a
deadline, and fails only past it.

tests/concurrent.rs: 16 threads share one device, 9,600 calls of the search and of
BLAKE3, every one required to complete on the device with the reference's result. With
the old wait the test fails.

Also clippy's clamp and as_chunks forms.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 06:45:24 -04:00
Transaction Science
ci(wai-pack): the GPU steps on the macOS leg, and the fabric test's floor
The macOS leg, whose host has a GPU, runs wai-pack-gpu's clippy, its kernels against
their references and its mutants, and wai-pack's fabric differential with the `gpu`
feature, with WAI_PACK_GPU_REQUIRE set so that an absent adapter fails rather than
skips; each step requires its report lines. The paths include wai/wai-pack-gpu. The
test-count floors gain --test=fabric and raise --lib to the target's count.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 05:13:34 -04:00
Transaction Science
packaging §11.6: steps and fabrics
The computations of a pack and a verify are named steps, each of which may run on a
CPU, a GPU, a media engine or a neural engine. Every step is a function of its inputs,
defined in integers (and floor-decode by the AV1 decoding process), and none names a
fabric:

1. a packager runs a step only on a backend that has given the reference's output on
   qualifying inputs, never on one that computes otherwise than the step's definition,
   and leaves a call a backend does not take to the CPU; so §11.2 holds across fabrics
   (amended to say so), and only a metered package's claim says where steps ran;
2. a verifier computes a check on another fabric only where the package states the
   value it compares with, and decides a mismatch again on the reference: a verdict that
   changes with the fabric is the verifier's fault;
3. no step is computed by a hardware encoder, whose output no rule fixes; a floor encoded
   on one is a §7.5 floor naming its encoder, version, device and driver;
4. a floor states no decoded-output digest, so no floor verdict comes from a hardware
   decode; wider hardware formats are read back exactly or refused, never rounded;
5. a metered package's claim may carry the fabric record (jwp-receipts §2.4.8), its steps
   §11.6's terms (§11.3 step 7); an unmetered package carries none.

Terms gain Step and Fabric; §11.4 says what the reference packager places where.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 05:13:34 -04:00
Transaction Science
pack-conformance: a metered package's fabric record, and one naming no step
Two package mutations of the metered golden (§9.4): `metered-fabrics`, whose measurement
claim carries a fabric record of two steps on the CPU and the figure as its one share,
which both verifiers accept; and `metered-fabrics-unknown-step`, a claim that keeps every
rule of jwp-receipts §2.4.8 but whose record names a step packaging §11.6 does not
define, refused measurement-claim-invalid by wai-pack and pack_verify.py alike. Every
other file of the corpus regenerates unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 05:13:34 -04:00
Transaction Science
wai-pack floor-decode: a package's floors through a conformant AV1 decoder
`wai-pack floor-decode <package> --decoder dav1d|videotoolbox` decodes every floor
rung's CMAF files (init.mp4 and the fragments in the floor playlist's order) through
ffmpeg, with libdav1d on the CPU (film grain exported, not applied) or VideoToolbox on
the media engine (its frames required to be the hardware's: a decoder that fell back to
software fails), and prints each piece's SHA-256 of its 4:2:0 pictures at the stream's
bit depth. Informative, for comparing decoders and fabrics (packaging §11.6 item 4):
nothing refuses a floor for it.

The media engine gives AV1 frames as P010 whatever the stream's bit depth. They are read
back exactly: a 10-bit sample is the word's high ten bits, an 8-bit one is recovered only
from a shift or a bit replication, and a word with low bits set, or a 10-bit value no
8-bit value widens to, fails the picture. ffmpeg's own 16-to-8-bit conversion rounds and
dithers, so it is never used. A rung whose sequence header carries film grain is not
decoded on the media engine, which applies grain no rule fixes.

av1: SequenceHeader::film_grain_params_present reads the bit after color_config();
SequenceHeader::parse does not, so what a packager accepts is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 04:51:12 -04:00
Transaction Science
wai-pack: each step placed on a fabric by measured energy (packaging §11.6)
fabric.rs names the steps of a pack and a verify (source-read, segment, base-search,
base-code, refine-code, sse, object-hash, digest, floor-read, index, io, ...) and places
each call of one on a fabric, the way an energy-aware scheduler places work: a backend
is a candidate only once it has given the CPU reference's output on qualifying inputs
(seeded frame pairs of every kind the search meets, seeded SSE and BLAKE3 inputs), and
among candidates the least `uJ per call + nJ per unit * units` of a measured cost table
wins, the CPU on a tie or where nothing was measured. The CPU is the reference and the
fallback: a call another fabric does not take runs on the CPU, with the same output.
--fabric cpu (the default), gpu, or auto:<costs.json>.

With feature `gpu`, base-search, sse and object-hash run on a GPU through wai-pack-gpu.
The packer's coder, its floors' object hashes, and the verifier's object hashes go
through the placement; the verifier hashes a component's objects in one batch and
decides any object-hash refusal again on the CPU, so its verdict is the CPU's.

With feature `fabric-meter` (macOS), --meter fabric meters the pack per fabric, without
privileges: the CPU's energy as the kernel accounts it to the process (task), and the
GPU rail (IOReport "GPU Energy"), read on its republish at each end, where the process
held at least 99% of every client's GPU time (rail); a shared GPU gives no figure, and
the pack is refused pack-meter, saying why. The claim carries the fabric record
(jwp-receipts §2.4.8). `wai-pack fabric list` shows each step's qualified backends,
`fabric calibrate` measures the cost table.

tests/fabric.rs: placement, the cost table, and the claim's record on every build; with
`gpu`, on every GPU, the search against the reference (qualifying frames, seeded noise
at every block size and range, every fixture's frame pairs, whole encodes), every golden
packed on the GPU byte for byte the committed package, every golden and package and
staged mutation given the CPU's verdict with the hashes on the GPU, and an edited kernel
refused by qualification and, forced in, moving no verdict. pack_verify.py holds a
package's fabric record to the steps of §11.6.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 04:51:02 -04:00
Transaction Science
wai-pack-gpu: the motion search, SSE and BLAKE3 as exact WGSL kernels
A crate of its own, with its own lockfile, as wai-ops-gpu is: WGSL compute kernels
through wgpu 30.0.1 (Metal, Vulkan, DX12), in 32-bit words with every intermediate
bounded inside its type, so a device that executes WGSL's integer arithmetic gives the
CPU's result for every input.

- motion.wgsl: one workgroup per block, each thread the least of the candidates it
  visits by (cost, |dy| + |dx|, index), the workgroup reducing them to the least: the
  order is total, so the result is the encoder's whichever thread meets which
  candidate first. Half-pel prediction with integer rounding and clamped coordinates,
  as integer-payloads §3 defines it.
- sse.wgsl: partial sums of at most 4,096 bytes a thread (under 2^32), added on the
  host in 64 bits.
- blake3.wgsl: BLAKE3's chunk function, one thread per chunk of one message; a message
  of several chunks has its parent nodes merged on the host by the reference crate's
  subtree functions, in the tree the specification fixes.

A size a kernel does not take (a block whose cost can pass 2^32 - 1, a range past 127,
a binding past the device's) is refused before anything runs, so the caller computes
it on the CPU. A software rasteriser is not opened: it runs on the CPU.

tests/kernels.rs holds each kernel to a reference transcribed from the extension text
(the BLAKE3 crate for BLAKE3), on frames of noise, near ties, flat fields (every
candidate ties), alternating columns (two vectors tie at one length) and hard edges,
at sizes that are not whole blocks and both precisions; tests/mutants.rs edits one
expression of a kernel at a time (a tie rule, a rounding addend, a clamp bound, a
reduction bound, a square, a rotation, a permutation entry, the root flag, the chunk
counter, a block length) and requires the cases to catch each, on every adapter. With
no adapter the tests print SKIPPED, unless WAI_PACK_GPU_REQUIRE is set.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 04:50:22 -04:00
Transaction Science
jwp-receipts §2.4.8: a measurement claim's fabric record
A measurement claim may carry `fabrics` (energy-measurement §6.3): the steps of the work
the figure covers, each with every fabric that ran it (cpu, gpu, media, neural) and the
backend that did, and the figure divided into one share per fabric, each attributed as
`task` (the operating system's account of the work's own energy) or `rail` (the
fabric's whole rail, the work its sole user, at least 99% of its busy time). No
attribution divides a shared rail by its users' busy time, which does not apportion
energy.

`fabrics` is the one claim member that is absent rather than null (§2.4), so every
claim sealed before it keeps its bytes and link hash. Rule 6 refuses, in order: a
fabric or attribution outside §6.3 (measurement_fabric_unknown); no step or no share,
or either out of order or repeated (measurement_fabric_order); a step on a fabric with
no share (measurement_fabric_unmetered); a share on a fabric no step ran on
(measurement_fabric_unused); shares that do not sum to the figure
(measurement_fabric_sum).

wai-rs: MeasurementClaim::fabrics, its parse, rules and serialisation, and
meter_report::emit_with_fabrics. claim_verify.py: the same rules, written from the
text. claim-conformance: 14 vectors appended after the 567 before them, which a new
test pins by digest (computed from the committed corpus before the change); one
accept, four step-2 shape refusals (null among them), the step-4 reasons, and a share
attributed by GPU time refused.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 04:50:07 -04:00
Transaction Science
wai-rs: the encoder's motion search and an object's hash may run elsewhere
int_video_enc::encode_with takes the motion search as a MotionSearch, whose rule is the
encoder's (every candidate's cost, the least by cost, then by |dy| + |dx|, then the
earlier vector): every other step of the encode stays here, so a search that keeps the
rule gives encode's payload byte for byte. CpuSearch is the reference, and encode is
encode_with over it; a search that gives another number of vectors than the frame's
blocks is refused (field_range).

stage_index::check_object_hashed is check_object with the content hash handed in, so a
verifier can hash a component's objects in one batch on another fabric; check_object is
it over the reference hash.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 04:49:56 -04:00