wai packaging train: a title's whole ladder in one package, steps on the fabric with the least measured energy, decode-equivalence on GPUs (#426 #438 #452's GPU tier) #465
Merged
dcharlot
merged 41 commits from 2026-10-26 08:43:11 -04:00
train/pack-stack into main 2026-10-26
Merge origin/main into train/pack-stack (Train C and wai-quantum 0.6.15)
All checks were successful
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m21s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 31m36s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 7m1s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h2m52s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 3m39s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 6s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 6s
wai-quantum on every processor / emulated · aarch64-unknown-linux-gnu (pull_request) Successful in 1m2s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m42s
wai-quantum on every processor / emulated · armv7-unknown-linux-gnueabihf (pull_request) Successful in 1m6s
wai-quantum on every processor / emulated · loongarch64-unknown-linux-gnu (pull_request) Successful in 1m44s
wai-quantum on every processor / emulated · powerpc64-unknown-linux-gnu (pull_request) Successful in 2m26s
wai-quantum on every processor / emulated · powerpc64le-unknown-linux-gnu (pull_request) Successful in 4m10s
wai-quantum on every processor / emulated · riscv64gc-unknown-linux-gnu (pull_request) Successful in 2m33s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 10m46s
wai-quantum on every processor / emulated · s390x-unknown-linux-gnu (pull_request) Successful in 2m33s
wai-quantum on every processor / emulated · sparc64-unknown-linux-gnu (pull_request) Successful in 4m33s
wai-quantum on every processor / emulated · i686-unknown-linux-gnu (pull_request) Successful in 2m40s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 6s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m22s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 35s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 9m43s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m43s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 2m58s
wai-pack / wai-pack · linux (pull_request) Successful in 1m36s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m48s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 2m48s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 4m53s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m50s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m49s
Six files conflicted; both sides kept in each: - claim-conformance: main's span vectors stay where main published them, and this train's fabric-record vectors follow them, so main's 615 vectors are an unchanged prefix of the 636. vectors.json regenerated with `wai_claim_vectors gen`; it verifies, and claim_verify.py passes all 636. - jwp-receipts.md: a claim's two optional-member exceptions, the hybrid pq-signatures members and a measurement claim's `fabrics`. - wai-ops-gpu: both modules (`semantics`, `splat`); the workflow header names both suites. - CHANGELOG: this train's sections above Train C's, newest first. Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25
wai-pack media prober: the sample spacing from the first two timestamps, not the first duration
Some checks failed
wai-pack / wai-pack · macos (pull_request) Successful in 4m54s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 3m13s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 23m1s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 12m7s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 23m56s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Successful in 35m15s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m53s
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Successful in 5m45s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 5m16s
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Successful in 32m33s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 5s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 32m43s
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Successful in 6m49s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m31s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 49m47s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 21s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 2m0s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m32s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m25s
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Successful in 6m55s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 7m15s
WAI conformance / cargo-class corpora · linux (pull_request) Failing after 9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 29s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m12s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 2m23s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 4m20s
wai-pack / wai-pack · linux (pull_request) Successful in 2m26s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m21s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 2m46s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 4m18s
CI's ffprobe 4.4.2 reports no duration (N/A) for the first sample of the CMAF floor, so the step refused video-cmaf-01 before reading a key frame. The spacing is now the second sample's pts less the first's. Every sample must sit on that grid, and a duration ffprobe does report must equal the spacing. A gap, an uneven duration or a missing pts is still refused (checked on synthetic ffprobe output), and every golden's key frames read as its plan. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merge origin/main (#462, #464) into train/pack-stack
Some checks failed
wai-pack / wai-pack · linux (pull_request) Successful in 1m51s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 13m48s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 9s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 20m46s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 23s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 1m23s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 13m36s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 2m53s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 20s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 44s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 4m51s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 5m51s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 7m57s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 4m13s
wai-pack / wai-pack · macos (pull_request) Successful in 2m30s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 2m7s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 39m31s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Successful in 30m46s
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Successful in 30m29s
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Successful in 5m21s
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Successful in 6m6s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 4s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m3s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m16s
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Successful in 5m31s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m18s
wai-pack / wai-pack · the floor through a media prober (pull_request) Failing after 21s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m7s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 6m17s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 30m55s
One textual conflict, wai/CHANGELOG.md (both sides added entries at the top of v0.4.0), resolved as their union, the stack's first. Every other file main changed (joule-moq-relay, joule-moq-room's tests, co-performance, wai-quantum-service) is outside the train's. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack fabric attribution: the sole-user case tells the whole rail from a busy-time split (#438 review M4)
Falsifying #438 review M4 (the rail sealed whole) showed its test could not fail: the sole-user fixture gave this process all of the GPU's time, so the rail times mine/all was the rail itself. Another client now holds 0.5% of the GPU's time, still sole use, so a busy-time split would give 2,388,000 uJ against the whole rail's 2,400,000, and the test requires the latter. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack tests/cmaf.rs: the width case edits the sample entry; the binding case reseals by rename
Two of the review-fix tests were wrong, not the checks: - the "sample entry wider" case (#426 review S2) took the first `av01` in the init, which is ftyp's compatible brand, so it edited ftyp and the pack was accepted; it now finds the av01 entry after stsd (64x36 on video-cmaf-01's hi init); - the_package_binds_the_supplied_bytes replaced a segment and resealed with the plain reseal, which now (#426 review S6) refuses a supplied floor that does not check; it reseals with golden::reseal_renamed, as the corpus case does, so the package's one fault is the binding, which the verifier still refuses (floor-cmaf-mismatch). Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack tests: a fabric that ran steps with no share is refused by the packer (#438 review M2)
The packer's fabric_record refuses a fabric that ran steps of the pack with no share or a share of 0 (#438 review M2); no test held it. the_fabric_record_rides_in_the_ measurement_claim now packs with an empty split and requires the packer's own reason, not only the claim's sum rule one layer down. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merge origin/main (#451, live room train D) into train/pack-stack
One textual conflict, wai/CHANGELOG.md, where both sides added entries at the top of v0.4.0; resolved as their union, the stack's first, no line of either dropped. #451's registry export and vocabulary are main's: the train changes neither their inputs nor wai-conformance.yml. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack fabric meter: a type for what a span's join gives back
clippy's type_complexity (denied in wai-pack's `--features gpu,fabric-meter` lint) refused join's five-member tuple; it is the alias `Joined`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
pack-conformance: cmaf-mutations regenerated (#426 review S6)
`wai-pack conformance regen` after the reseal fix: `segment-not-the-supplied-one` now removes only the replaced segment, and its playlists and MPD name the replacement (hls/classic/floor-hi.m3u8 is back, the masters list both rungs), so the case's one fault is the segment's binding to `floor.listing`. Its moq catalog names no segment and is the golden's, so the overlay no longer carries it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24
determinism-tiers §5: the Vulkan run on PCI 0x1002, with both runs' reports committed (#452 review S7)
#452 review S7 asked for the hand-run evidence in the repository, or the claims removed. The Metal and browser claims rest on the forge's run 10236 (job 46928); this train ran the crate's tests with WAI_OPS_GPU_REQUIRE=1 on a Linux x86_64 host's integrated GPU of PCI vendor 0x1002, device 0x1586 (Mesa 26.0.8), and its llvmpipe, on this revision's kernels: the semantics suite (254,464 cases, none differing, guarded or not), the probe, the corpus at both widths and the 18 mutants. Both runs' WAI_OPS_GPU_REPORT lines are committed in wai/research/ops-gpu-runs.txt, each as written but for its `adapter=` field, the device's product name. §5 claims the 0x1002 adapter and llvmpipe again; the §6 row and the CHANGELOG say what ran where, and that the capability corpora did not run on the Vulkan adapters. Co-Authored-By: Claude Opus 5.5 <[email protected]>
energy-measurement §6.3: cite packaging §11, as the section checker reads it
check-wai-section-refs.py resolves a cross-document section only to a heading, and packaging's 11.6 is a numbered paragraph under §11; §6.3's new sentence on step vocabularies cited "§11.6". It cites "§11, its steps and fabrics", as the sentence after it already does. Co-Authored-By: Claude Opus 5.5 <[email protected]>
CHANGELOG (packaging): the figure's bracket, the CMAF floor's agreements
The #426 entry records what its review's fixes changed: the meter brackets the whole pack (§9.4), a CMAF floor's av1C and sample entry are its sequence header's and every sample's sync flag is its unit's (§7.7, §11.3), and a re-pack holds its parent whole while it verifies it (§11.4). Co-Authored-By: Claude Opus 5.5 <[email protected]>
CHANGELOG (GPU tier) to what was shown; wai-pack names the object domain (#452 review S4, S6, S7; #438 review N6)
- #452 review S4, S6, S7. The GPU entry claimed the suite covers every integer operation WGSL defines, and listed Vulkan and DX12 results with no committed record. It now says every operation a kernel may use, the rules check's new refusals, the identity for backends with no PCI id, the accelerator-general form, and that the tier is claimed on Metal and its browser WebGPU, the forge run's. - #438 review N6. wai-pack's GPU object-hash call wrote the domain `moq-jwp:object\x01` and its 15 bytes by hand; it uses wai::jwp_hash::DOMAIN_OBJECT. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack-gpu: per-call error scopes; the backends claimed are the one shown (#438 review S6, S7, N12)
- #438 review S7. Device errors were collected in one uncaptured-error sink per device, and `settled()` took them all, so under `--jobs N` one thread could consume another call's validation or out-of-memory error and that call returned its output as Ok. Each `run` now pushes its own Validation and OutOfMemory error scopes and pops them after its read-back, refusing the call on either; wgpu 30's scopes are thread-local with its `std` feature, which this crate enables. - #438 review S6. The crate docs, both Cargo.toml comments and the CHANGELOG said the kernels are exact on Metal, Vulkan and DX12; they were shown on Metal only. They now say so, that Vulkan and DX12 were not run and nothing is claimed for them, and that qualification at open is the gate on any adapter. - #438 review N12. The CHANGELOG entry says a verifier before this revision refuses a claim carrying `fabrics`; it also states the meter's new class, its sampled sole use, the share of more than 0, and the `npu` term. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-rs encode_with: a search vector outside the window is refused (#438 review S8)
#438 review S8. encode_with checked only how many vectors a MotionSearch returned, so a search (a GPU backend among them) that gave a vector past -range..=range was encoded: the payload still decodes, but it is not packaging §5.5's search, and §11.2 would break silently. Such a vector is now refused `field_range`, and the test adds a search that returns one a step past the window. Co-Authored-By: Claude Opus 5.5 <[email protected]>
CMAF floors: the init's av1C and size are the sequence header's (#426 review S2)
#426 review S2. With a CMAF floor the playlists' CODECS and RESOLUTION come from the in-band sequence header, while players (and Media Capabilities, through http-delivery §12.2) configure from the ladder's own av1C, and nothing checked that the two agree. §7.7 (step 4) and §11.3 now refuse an init whose av01 entry has no av1C, or whose av1C profile, level, tier, bit depth, monochrome and chroma fields, or sample-entry width and height, are not the sequence header's and its maximum frame size. Both Rust readers (cmaf_read::read_init reads the record and the size; floor::init_disagrees compares, in check_cmaf and in verify's cmaf_supplied) and pack_verify.py (cmaf_init and init_agrees, in both CMAF paths) apply it. tests/cmaf.rs refuses an av1C one level higher and a sample entry one pixel wider, and (for S3) a segment whose tfhd default flags make every non-key frame a sync sample, each `floor-cmaf-malformed`. On video-cmaf-01, both rungs' inits agree (81000c00 at 64x36 and 32x18). Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack golden: a reseal that fails its CMAF check says so (#426 review S6)
#426 review S6. reseal_as swallowed cmaf_supplied's error, so the `segment-not-the-supplied-one` vector silently lost its `hi` floor: its catalogs listed `lo` only and its overlay removed hls/classic/floor-hi.m3u8, three faults where its README describes one. reseal_as now propagates the error, and the mutation reseals through reseal_renamed, which renders the catalogs naming the replacement segment, so the one fault is the segment's binding to `floor.listing`. The corpus is regenerated in a later commit. Co-Authored-By: Claude Opus 5.5 <[email protected]>
CMAF floors: every sample's sync flag held to its unit (#426 review S3)
#426 review S3. In the CMAF form only each segment's first sample had its sync flag checked (floor.rs, verify.rs, and pack_verify.py's two readers), so a non-key frame flagged as a sync sample was accepted, while the ladder's flags reach players unchanged and players seek by them. §7.7 (step 4) and §11.3 now require every sample to be a sync sample exactly when its unit starts at a shown key frame (`floor-cmaf-malformed` at the packer, `floor-cmaf-mismatch` against a package), and the packer's check_cmaf, the verifier's cmaf_supplied and pack_verify.py's verify_supplied_cmaf and cmaf_package_files hold every sample to it, from the units' own key frames. Co-Authored-By: Claude Opus 5.5 <[email protected]>
pack_verify.py: a metered package's claim checked by claim_verify's step 6 (#426 review S4)
#426 review S4. measurement_claim_fault compared profile, index, group, joules, class and signer by hand, beside claim_verify.check_figure, the normative step 6 of jwp-receipts §3.1 with its own reasons; #438's `fabrics` would have drifted from a private copy. It now builds the receipt's view (profile, receipt hash, no group, its one figure with the class class_of_json reads, its signer) and calls CV.check_figure, keeping as local additions the subject type, the class's evidence members as written, and the record's §11.6 step vocabulary. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack verify --parent: an unreadable parent is repack-parent-invalid (#426 review S11)
#426 review S11. `wai-pack verify --parent` mapped every read_strict error to `unexpected-file`, the parent's too. A parent that cannot be read is one that does not verify, which §11.5 names `repack-parent-invalid`; `unexpected-file` stays the package's own. Co-Authored-By: Claude Opus 5.5 <[email protected]>
cmaf_diff.py: the timescale case alters mdhd's timescale (#426 review S5)
#426 review S5. The "timescale altered" branch wrote at mdhd's type offset + 20, which in version 0 is the duration, not the timescale (+16; +24 in version 1). Neither reader reads the duration, so the branch always gave ok/ok and a timescale of 0 was reached only by a stray bit flip. The offset now follows the box's version; on video-cmaf-01's init, +16 reads 1,200,000 and +20 the duration, 0. The elst offsets were right. Co-Authored-By: Claude Opus 5.5 <[email protected]>
packaging: six wording findings (#426 review S1, S7, S8, S9, S10, S12)
- #426 review S1. §11.4 said what a packer holds is not a function of the source's length; a re-pack holds its parent whole while it verifies it (load_parent reads every file), so its memory grows with the parent. §11.4 now says so. - #426 review S7. §11.5 said every check runs before anything is written, but check 3 runs as each piece is coded; it now says checks 1 and 2 before, check 3 as it reads each piece, leaving nothing written. - #426 review S8. §11.2's re-pack equivalence needs a parent packed by a conforming packager of the same identity, as §11.2 itself exempts other identities. - #426 review S9. §7.4 and §7.8 said no `replicate` claim covers a floor, while every floor object's manifest writes `intent: "replicate"`. They now say that it promises only the capability's decoder conformance, and that no tier and no claim against a primary or a source covers it. - #426 review S10. §7.8 said a sink checking an object's hash receives the signer's bytes, but a floor-only package's catalogs list no WAI object. It now states what a sink can check in each form, and that browser-sink §7's binding does not apply. - #426 review S12. §7.2's first sentence is rewritten so it no longer reads as if a floor-only floor names a base. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack fabric meter: its declared uncertainty in integers
wai-pack denies floating-point arithmetic (clippy's float_arithmetic, so no package byte can depend on it), and the meter's OnChipCounter declaration was computed in f64. It is now computed in integers: the declared 5% and the register resolution (⌈408,249 / µJ⌉ ppm) in quadrature, each step rounded up, through Uncertainty::new. Co-Authored-By: Claude Opus 5.5 <[email protected]>
claim-conformance: the corpus regenerated, 588 vectors (#438 review M3, S11)
`wai_claim_vectors gen` over the changed fabric vectors: the accept vector's class is OnChipCounter, and seven vectors are appended (581 to 588). The 567-vector prefix before the fabric record is unchanged, as its pinned digest requires. claim_verify.py gives every vector its expected verdict. Co-Authored-By: Claude Opus 5.5 <[email protected]>
determinism-tiers §5: what the GPU leg showed, and an accelerator rule (#452 review S2, S4-S7, corrections, N5, N13)
- #452 review S6, S7. The adapters claimed are those the forge's run 10236 (job 46928) of wai-ops-gpu.yml shows on this revision's kernel text: Metal on an arm64 desktop (macOS 27.0.1) and Chromium 148's WebGPU on that GPU. The Linux and Windows Vulkan, DX12 and software adapters were hand runs with no record committed, and G1's 0x1002 adapter ran the kernel text before the shift masks; none is claimed now. Committing their report lines would publish adapter product names, so the claims are narrowed instead. The §6 row and summary cite the forge run (N13). - #452 review S5. Item 6 says what a claim names where the backend reports no PCI identity and no driver (Metal, a browser's WebGPU). - #452 review S2. The rules check holds items 1, 2 and 4 and item 3's atomic and barrier parts; write-once and in-bounds rest on the host's indexing and wgpu's bounds checks, which the checked module creation keeps on. - #452 review S4. The suite covers every integer operation a kernel may use (rule 7), not every one WGSL defines: in §5, wgsl-conformance/README.md. - The corrections: SPIR-V's signed remainder is guarded even with the checks off; HLSL also writes integer `clamp` as `clamp` (spec and semantics::UNGUARDED); DX12 goes through FXC; semantics.rs cites WGSL §8.8 and §8.10; its intra-doc links name `Op::guarded_case` and `Op::ShlU32`, which exist (N5). - The subsection now opens with the conditions in general form for any accelerator, and states that the items are their GPU instance, so G2's NPU text (#440) can reuse it rather than write a parallel rule. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-ops-gpu rules: rule 8 finds naga's signed wrapping, not a bitcast (#452 review S1)
#452 review S1. Rule 8 checked signed add, subtract and multiply by looking for `as_type<uint>(` in the MSL and `asuint(` in the HLSL, which every `bitcast<u32>(i32)` also writes: modules with no signed arithmetic carried both, and ops32 passed for a reason the check did not test. It now requires naga's nesting, `as_type<int>(as_type<uint>(` (and its two-component form) in MSL and `asint(asuint(` in HLSL. A new test takes the wrapping out of ops32's translations, leaving its bitcasts, and shows each refused; wai-ops-gpu.yml counts 17 tests. Co-Authored-By: Claude Opus 5.5 <[email protected]>
energy-measurement §6.3: the class, task, sole use sampled, the rail's window (#438 review M1, M3, S1-S3, S10)
- #438 review M3. A figure divided by fabric is sealed under its weakest share's class; the reference meter's shares are OnChipCounter readings (§2.9), filtering Unknown, with a declared 5% uncertainty over the span, so its figure is OnChipCounter. A fabric that ran a step has a share of more than 0. - #438 review S1. `task` on the reference hosts is ri_energy_nj + ri_billed_energy - ri_serviced_energy, and S2: each end's read waits for the reading thread's fold, and a span lasts at least 1 s and five intervals. - #438 review M1. `rail` states how sole use is read: every 200 ms, per user by a stable identity, the busy window enclosing the rail's, a vanished user of the work's own or a negative difference giving no share, another's charged its interval, nothing clamped; and the residual, a user that lives between two reads. - #438 review S3. A `rail` share includes the fabric's idle and static draw, and its window can exceed the span by up to one republish period on each side. - #438 review S10. A figure profile defines its step vocabulary, and a report about a figure whose profile defines none MUST NOT carry a fabric record. M4 needs no text change: §6.3 already defined `rail` as the whole rail; the code now seals that. Co-Authored-By: Claude Opus 5.5 <[email protected]>
packaging §11.6 item 1 states the qualifying set; §7.5 holds the device (#438 review S5, S9)
- #438 review S5. Item 1 defined a MUST by pointing at a code function (`wai_pack::fabric::qualifying_frames`), which a second implementer cannot meet. It now states what a qualifying set holds at the least, for the motion search (noise, a smooth field, a flat field, alternating columns, sizes not a whole number of blocks, three block sizes, full-pel and half-pel, ranges to the edge), for SSE and for BLAKE3 (lengths around a chunk and past four chunks), each of which the reference set covers; the reference's set is named as informative. - #438 review S9. Item 3 required the device and driver of a hardware-encoded floor in `derived_from.renderer`, which §7.5 does not. §7.5's MUST now carries them for a hardware encoder, and item 3 points to it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
claims rule 6: a stepped fabric's share of 0 is unmetered; vectors (#438 review M2, M3, S11)
- #438 review M2, the claim half. jwp-receipts §2.4.8 rule 6 accepted a GPU step with a GPU share of 0, which is how a missing or frozen GPU reading was sealed. A fabric a step names now needs a share of more than 0 (`measurement_fabric_unmetered`), in the text, the reasons table, wai::claim_receipt and claim_verify.py. - #438 review M3. The fabric accept vector's figure is an OnChipCounter one, declared 5% over 1.2 s, as the reference meter seals; the fabric vectors sit after the pinned prefix, which is unchanged. - #438 review S11. Appended: a GPU share of 0 beside GPU steps, an unknown fabric in a step, a (step, fabric) pair twice, fabrics out of order within one step, steps with no share, a step missing its backend (missing_required_field) and an extra member on the record (unknown_member). The corpus is regenerated in a later commit. Co-Authored-By: Claude Opus 5.5 <[email protected]>
fabric term
npu, not neural (#438 review, the fabric term)
#438 review SHOULD-FIX: the neural-processor fabric was `neural`, while determinism-tiers §5 and G2 (#440, `wai-ops/1-npu`) say NPU. The term is now `npu` in energy-measurement §6.3, packaging §2, jwp-receipts §2.4.8 rule 6 and its reasons table, wai::claim_receipt::FABRICS, claim_verify.py and wai-pack's Fabric (variant Fabric::Npu). No committed vector names the old term. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack fabric meter: sampled sole use, the whole rail, OnChipCounter (#438 review M1-M4, S1-S4)
The fabric meter is rebuilt on a pure attribution (src/fabric_attribution.rs, compiled on every OS so its tests run in every leg) over what the macOS meter reads. - #438 review M1, the 99% sole-user rule. GPU time was summed over the clients present at each end, so a client that exited mid-span took its whole lifetime's time with it, and `d_all.max(m)` then read a shared GPU as 100% this process's. The clients are now read every 200 ms through the span, keyed by registry entry id and differenced between reads: a negative difference, a failed read or a vanished client of this process refuses the span; another process's vanished client is charged its whole interval; nothing is clamped. The first client read is before the rail's start edge and the last after its end edge, so the busy window encloses the rail's. - #438 review M2, no 0 J share from a missing or frozen reading. A failed registry or rail read refuses the span; the rail must be live through it (energy-measurement §3.1, wai::energy_report::Liveness, as CounterMeter); GPU time with a rail of 0 refuses; a span with no GPU time has no GPU share at all; and the packer's fabric_record refuses a fabric that ran steps with no share or a share of 0 (so GPU calls whose time went unseen are refused there). A begin() that fails keeps its reason. - #438 review M3, the class. The figure is sealed OnChipCounter, filtering Unknown, with a declared 5% relative uncertainty combined with the register resolution over the span's window, never ModelBased; Meter::kind says OnChipCounter. - #438 review M4, `rail`. The GPU share is the whole rail over the span, never the rail times a share of busy time. - #438 review S1, `task` is ri_energy_nj + ri_billed_energy - ri_serviced_energy (rusage_info_v6 fields 40, 31 and 32, checked against the SDK header), EN-A's definition. - #438 review S2. Each end's task read is taken only once the reading thread's own count (PROC_PIDTHREADCOUNTS) is seen to fold across a sleep, as sandbox-meter's probe does; a span is at least 1 s and five sampling intervals. - #438 review S3. The rail's idle and static draw and its window are stated in the module, the attribution and §6.3 (next commits); the window is sealed through the uncertainty's window_us. - #438 review S4. The attribution's outcomes are unit tests: the sole user, no GPU time, a shared GPU, another process's vanished client, this process's vanished client, time going backwards, failed client reads, a frozen or lump rail, a failed rail read or no rail, unread or non-advancing task energy, and spans under the minimum. `wai-pack fabric calibrate` takes its spans at 1 s or more, and prints the meter's reason when it gives no figure. GpuRail's Send note no longer cites a lock that does not exist, and two `GPU Energy` channels are refused rather than summed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
determinism-tiers §5 item 3: one atomic kind per word, its result unused (#452 review M3)
#452 review M3. Item 3 listed atomicOr, atomicAnd, atomicMin, atomicMax, atomicAdd and atomicSub as order-free. Each is, alone; two on one word are not (atomicOr then atomicAnd gives 0 from 0, the reverse 1; atomicMin with atomicMax the same). Item 3 now requires every atomic operation on a word to be of one kind (atomicAdd and atomicSub counting as one), no load, store, exchange or compare-exchange to reach it, and its result unused. The rules check enforces this for the shipped modules: rule 6 admits atomicOr alone, with its result unused, and refuses atomic loads and stores (the previous commit). Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-ops-gpu rules, determinism-tiers §5: no signed left shift (#452 review S3)
#452 review S3. naga routes only signed add, subtract and multiply through unsigned in MSL; a signed `<<` goes out as written, and in MSL (C++14) a left shift of a negative or unrepresentable signed value is undefined. The suite marked shl_i32 guarded for every amount below 32, and the rules check accepted `bitcast<i32>(A[t]) << 31u`. No kernel shifts a signed value left today. Rule 5 now refuses a left shift with a signed left operand in a kernel (shift the u32 and bitcast), with that plant. Item 4 and the paragraph before it name the case, and say that a right shift of a negative value, which MSL leaves to the implementation, is held by item 5's suite on the adapter. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-ops-gpu rules: refuse atomicLoad and atomicStore (#452 review M2)
#452 review M2. naga lowers `atomicLoad` to a plain `Expression::Load` and `atomicStore` to a plain `Statement::Store` through a pointer to an atomic, and the closed lists accepted both without looking at the pointee; only `Statement::Atomic` and `AtomicResult` were inspected. So `O[t] = atomicLoad(&F[...])`, `atomicStore(&F[...], 0u)`, and `atomicOr` then `atomicStore` on one word all passed rule 6, though each result depends on scheduling. Rule 6 now refuses a load from, or a store to, any pointer whose pointee is atomic. The planted cases are the review's three, plus a storage barrier alone (N7), which rule 6 refuses on its own rather than through rule 2's workgroup plant. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack: the meter brackets the whole pack, and §9.4 says so (#426 review M4)
#426 review M4. pack_into started the meter only after the source's first read and scene cut, every supplied-floor check (nearly all of a floor-only pack) and a re-pack's full verification of its parent (about 40% of a re-pack), while the receipt's figure read as the pack's energy and no text said what it bracketed. The meter now starts once the policy's own refusals have passed, before the source's first read, so it covers both reads, the floor checks, the parent's verification, every piece and every file, and stops before the receipt is sealed. §9.4 states that bracket as a MUST. The fabric meter (#438) is started at the same call, so the fix carries through it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
packaging §11.4: pack-source-missing is the standard profile's (#426 review M3)
#426 review M3. §11.4 refused "a component with no source (pack-source-missing)", which contradicts §7.8, whose floor-only component has no source by definition (and §3.4 item 8 refuses one that has a source). The refusal is now the standard profile's. The packer already agrees: pack.rs asks for a source only when the component is not floor-only. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-rs: include/wai.h regenerated with PIECE_KIND_NONE (#426 review M1)
#426 review M1. #426's stage_index.rs adds `pub const PIECE_KIND_NONE: u8 = 6`, which cbindgen exports, but #426 left the committed header as main's. So the first build of wai-rs rewrote include/wai.h, the tree was dirty, and every HTTP corpus falsify-patch shard failed its first "the tree is clean after reversing the patch" check. The header now holds the define, exactly the six lines the build writes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-rs tests: wgsl-conformance names why it states no output digest (#452 review M1)
#452 review M1, the root cause of its red cargo-class corpora jobs (linux, linux-arm64, macos). int_kernels_vectors.rs every_decoded_output_states_a_sha256 holds every wai/*-conformance directory to a sha256.json sidecar, or to an exclusion naming why it has no decoded output. #452 added wgsl-conformance/ (and platform-decode-conformance/, which this train leaves out) with neither, so the test read a sidecar that does not exist, and every step after it never ran. wgsl-conformance decodes nothing: each case states its operands and result word in full. It is listed with that reason, as ops-conformance is. The rule is unchanged: a corpus with neither a sidecar nor a reason still fails. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack-gpu: tokio 1.54.1, as #443 moved every other lockfile (#438 review M5)
#438 review M5. #438 committed wai/wai-pack-gpu/Cargo.lock with tokio 1.54.0 (RUSTSEC-2026-0384, yanked), reached through wasm-bindgen-futures; main's advisory sweep (#443) moved every other lockfile to 1.54.1, and its gate (scripts/check-advisories.py) refuses the new one. Resolved with `cargo update -p tokio --precise 1.54.1`; nothing else in the lockfile moves. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-pack CI: the media prober reads key frames as frame indices (#426 review M2)
#426 review M2. The media-prober job (test 14) compared ffprobe's packet pts with the plan's frame numbers. A pts is in the track's timescale: the packager's own floors tick once per frame, so they matched, but video-cmaf-01's floors are a muxer's fMP4 at timescale 1/1200000 with 48000 ticks per sample, so its key frames read 0 2880000 4080000 6480000 7680000 against the plan's 0 60 85 135 160. The floor was right; the check was wrong. Each key frame's index is now its pts over the sample duration, and every sample must sit one duration after the one before it (constant duration, no gap, in order), so the index is also the packet's ordinal, the review's NR-1, and an off-grid sample is refused by name instead of read as a moved key frame. The step now reaches video-floor-only-02, which passes. The packages are unchanged. Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai packaging stack: #426, #438 and #452's GPU tier, squashed onto main
One squashed history of three stacked PRs, onto main atb16816671: - #426 (wai/pack-efficiency): a title's whole AV1 ladder in one package over one integer base; several floor rungs (packaging §7.1), a re-pack from a parent (§11.5), a floor that is the ladder's own CMAF (§7.7), a floor-only profile (§7.8), a streaming pack (§11.4), and the independent verifier at scale (§9.4). - #438 (wai/cross-fabric): each pack and verify step on the fabric with the least measured energy (§11.6); the `fabrics` member of measurement claims (jwp-receipts §2.4.8, energy-measurement §6.3); the wai-pack-gpu crate; `wai-pack fabric`; `wai-pack floor-decode`. - #452 (wai/gpu-int-tier), its GPU-tier part only: claiming decode-equivalence on a GPU (determinism-tiers §5), the WGSL integer semantics suite, the rules check on naga's IR, and the kernels' shift masks and min(max()) clamps. Left out, by the review's split (EN-C takes it over): #452's platform decode in dispatch, its commits6ad92e2e8,8695bc75fandfed8694f4and its CHANGELOG entry: extensions/platform-decode.md, platform-decode-conformance/, wai::platform_decode, wai-web's platform_decode bundle and demo, and its two SPEC.md sentences. #438's research note is not carried as written: it is rewritten as wai/research/cross-fabric.md, with hardware named by architecture, PCI id and OS version, and every table marked as one run. floor_decode.rs and a wai_pack.rs comment name the platform's media engine and a full-length film the same way. wai/CHANGELOG.md is the union of both sides' entries, the stack's first. Co-Authored-By: Claude Opus 5.5 <[email protected]>