wai: prove integer video byte-identical, meter it, and publish the method #60
Loading…
Reference in a new issue
No description provided.
Delete branch "wai/video-byte-equality"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The cross-arch byte-equality matrix covered the still-image and synthesis paths — rANS,
int_synth, the JPEG-AI entropy stage — but not the inter-frame video decoder.wai.video.int_motionwas verified only bywai-rs/tests/int_video.rs, which is#![cfg(feature = "video_int")], and no CI job passes--features.Measured rather than assumed:
So the temporal leg of the determinism contract was asserted on four platforms and checked on none.
Why video is the strictest leg, not just another one
Still-image decode is a single shot: one divergent byte is one wrong byte. Inter-frame decode is a feedback loop — each P-frame predicts from the previously reconstructed frame. An architecture that rounds one half-pel sample differently produces a frame that then predicts the next frame, and the error compounds for the rest of the clip.
That is why per-frame hashes are asserted and not only the clip hash: they say where divergence began, which a single terminal hash cannot.
What is covered
int_videovideo_realThe real-footage test also asserts the vector still prefers half-pel, so it cannot silently degrade into covering only the whole-pel path while still passing.
Cost stays flat:
int_video.rsneeds onlyserde_jsonandcrate::rans, both already present, so all four legs still run in ~1 minute with no codec libraries and no ONNX runtime.ransis re-exported, not included twice — two#[path]includes would compile two structurally identical but distinct types, and one-source-of-truth is why this crate exists.Also fixes: the workflow could not see its own inputs
The crate compiles five sources. Only one of them could fire this workflow:
wai-rs/src/rans.rswai-rs/src/int_synth.rs(crate root)neural/int_synth.rs, a different filewai-rs/src/int_entropy.rswai-rs/src/jpegai_mans.rs(crate root)wai-rs/src/neural/jpegai_mans.rsAny of the four could have broken cross-architecture equality and merged green. All five are now watched, plus
int_video.rsand its vectors.Not covered, and not papered over
video_nk(wai.video.int_hyper, the neural-keyframe variant) is not included. Its I-frame comes fromint_hyper_synth::decode_conditional, so it cannot be driven bydecode()— an earlier draft of this file tried, and got a slice overrun out of the rANS reader, which is what feeding one codec another codec's bitstream looks like. Covering it means#[path]-includingint_hyper_synth.rsas well: a real follow-on, not a line to add here. Until it lands the neural-keyframe leg is proven only where someone runs--features neural_int,video_intlocally, and the source comment says so rather than letting a reader assume full coverage.Verification
27573cdba1ad6628,1ec1f0fa7da0d70f).Second commit: meter the integer video class
Haptics / 4D splats / scores / film are metered by
wai_meter, worlds / feeds / avatars bywai_world_meter, quantum circuits bywai_quantum_meter. Video had none — it could be decoded but never accounted. This adds the JWP receipt profile (VideoReceipt) and thewai_video_meterbinary, followingQuantumReceiptexactly.Why this profile is stronger than its siblings
In every other cargo class the reconstruction is deterministic by construction and taken on trust. Here it is deterministic and proven on real silicon — by the first commit's four-architecture matrix. So a verifier holding only the codestream can re-derive
clip_hash, every frame hash andwork_pixel_opsthemselves (verify_reconstructiondoes precisely that), and the receipt collapses to one field that rests on trusting the signer:codestream_hash,clip_hash,frames,work_pixel_opsjoules_microThe docs say which is which in those words, so a reader cannot conflate them.
Deliberate choices
int_video.rs. That file is#[path]-included bybyte-exact-conformance, whose three-dependency set is what lets the matrix run everywhere in ~1 minute. Pulling blake3 + ed25519 into it would break the very proof this profile leans on.video_receipt = ["video_int", "world"]mirrorsquantum_receipt.uj_per_kilopixel_op()returnsNonewhen unmetered, never0. Zero would read as "this decode was free" — a stronger and false claim than "nobody measured".to_jsonemitsnull, and withoutmacmonthe meter emits an UNMETERED receipt rather than an estimate.Measured, not modelled
Release build, real-footage vector (8 frames 96×96), on this machine:
A debug build reports 4.9x higher, which is why the meter is documented as a release-build tool. IOReport CPU power is SoC-wide, so the figure is the marginal delta over an idle machine — stated bounds, never a fabricated number.
Verification
int_video.rsuntouched.Fourth commit: the measurement methodology (
extensions/energy-measurement.md)jwp-receipts.mddefinesjoules_microas "microjoules consumed producing this object" — which fixes the unit and the scope of attribution and nothing else. The field was a number-shaped hole: one implementation can write a counter reading, another a model, a third a constant, and all three are conformant, incomparable, and indistinguishable.The extension requires two things of any receipt carrying energy: that the figure declare how it was acquired (
HwShunt/ModelBased/Estimator— the vocabulary the sibling receipt families already use, not a new one for media), and that the measurement declare whether it was good enough to publish. It also specifies the bracketed marginal protocol, the five bracket parameters that must accompany any published figure, and what the number is not: machine-specific, marginal over idle, scoped to what the interface reports, build-dependent, and never verifiable by re-execution.Two corrections the document forced on the implementation
1. The publication bar moves from 3× to 10×, on evidence. A later reading of the same clip at a 3.8× marginal-to-noise ratio — inside what the previous rule called "usable" — reported 2,469 µJ against 10,565 µJ from a quieter run. A 4.3× disagreement from a reading the rule had passed.
The 3–10 band is sound for comparing two workloads back-to-back on one machine, where the bias applies to both. It is not sound for an absolute figure. And the bias has a direction: a busy machine inflates the idle baseline that is then subtracted from a busy mean that never rose as far, so a poor bracket always reads low. An implementation reporting its own energy errs toward flattering itself — which is exactly why the check has to be automatic rather than left to the operator.
2. The worked example is a failing one, deliberately. My draft carried a clean-looking bracket with an idle standard deviation and a quality ratio for the 10,565 µJ run — numbers that run never produced, because it predates the standard-deviation reporting. Inventing them in a document about measurement honesty is the precise failure the document exists to prevent.
The example is now the real 3.8× bracket, labelled as one this spec forbids publishing, with a note on why a clean bracket isn't currently obtainable on the authoring machine. The quiet row in the comparison table is marked as predating the rule rather than given a ratio it never had.
Linked from
SPEC.mdbeside the receipt sub-spec, and from thejoules_microrow ofjwp-receipts.mdthat it constrains.Fifth commit: the neural-keyframe clip joins the matrix
The first commit named this gap and left it open.
wai.video.int_hyper— the variant whose I-frame is decoded by the learned conditional codec rather than as an ordinary integer keyframe — could not be driven byint_video::decode, so it sat outside the four-platform matrix. Covering it meant pullingint_hyper_synth.rsin rather than adding a line, which is why it was deferred rather than bodged.It needed one more source than expected:
int_hyper_synthdepends onint_transform::igdn, which wasn't included either.int_transformturns out to have no crate-internal dependencies at all, so both drop in cleanly and the legs still run in ~1 minute with no codec libraries and no ONNX.Why this is the strictest composition in the container
A learned decode feeding a feedback loop. The keyframe comes out of a quantised transform network, and every later frame predicts from the previously reconstructed one — so a divergent byte in the learned synthesis does not stay in the keyframe, it propagates through the clip.
Frame 0 is therefore pinned in its own test as well as inside the clip, so a regression in the conditional codec is distinguishable from one in the motion predictor rather than leaving both suspect.
A side effect worth naming
Including a source brings its
#[cfg(test)]module with it, soint_transform's 13 unit tests now run on all four architectures instead of only where someone passes--features. The crate goes from 17 tests to 32:int_transformneuralint_entropygoldenneural_keyframe_goldenjpegai_goldenint_video_goldenBoth new sources and the
int_hypervectors are added to the path triggers, on the same rule as before: every source the crate compiles must be able to fire the matrix, or a change can break cross-arch equality and merge green.Verification
32 tests pass, the clip reproducing its committed hash
a5f53d477999d159; workflow YAML parses with all four legs intact and 13 triggers.wai: prove integer VIDEO decode byte-identical across architecturesto wai: prove integer video byte-identical across architectures, then meter itwai: prove integer video byte-identical across architectures, then meter itto wai: prove integer video byte-identical, meter it, and publish the method