open-standards/wai/wai-web/compose/README.md
Transaction Science bf7c9fcfee
All checks were successful
WAI operation catalogue / does this change touch it (push) Successful in 17s
wai-fleet service / does this change touch it (push) Successful in 16s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 25s
wai-app and Create / wai-app · does this change touch it (push) Successful in 23s
wai-ledger service / does this change touch it (push) Successful in 19s
wai-sink-swift native sink package / does this change touch it (push) Successful in 22s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 53s
WAI Studio / does this change touch it (push) Successful in 18s
wai-quantum for JavaScript / does this change touch it (push) Successful in 54s
wai-audit collector and player integration / does this change touch it (push) Successful in 57s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 1m7s
wai-key-proxy / does this change touch it (push) Successful in 57s
wai-quantum studio and desktop / does this change touch it (push) Successful in 55s
wai-sink-android native sink library / does this change touch it (push) Successful in 55s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 2m46s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 5m2s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 5m5s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 6m41s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 16s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 15s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 1m2s
wai-fleet service / service · linux (push) Successful in 3m16s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m14s
wai-ledger service / service · linux (push) Successful in 4m28s
wai-audit collector and player integration / collector · linux (push) Successful in 5m1s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 8m15s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 1m28s
wai-quantum studio and desktop / studio · browser (push) Successful in 5m18s
wai-key-proxy / proxy · linux (push) Successful in 3m1s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 10m1s
wai-quantum for JavaScript / javascript · linux (push) Successful in 7m14s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 12m23s
wai-fleet service / service · macos (push) Successful in 38s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 7m35s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 9m15s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 9m29s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 12m24s
WAI Studio / Studio in WebKit · linux (push) Successful in 20m25s
wai-ledger service / service · macos (push) Successful in 1m28s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 7m54s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 20m38s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 15m54s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m9s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 49s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 10m34s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 4m34s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 15m59s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 6m42s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 7m0s
The browser sink presents a graphics component's text floor, with captions as graphics-vector §6.4 has them
browser-sink §14.9: where a device has no decoder of wai.graphics.vector, a composing
page presents each graphics piece's floor (graphics-vector §6.3), the piece's transcript
as wai.text.zstd, as text: the blocks active at the clock's tick, in block order, each
with its language, direction and writing mode. A piece presents its overlay or its
floor, never both.

Before presenting, the page holds the floor object to its piece: its derived_from names
the piece's base (floor_base), its payload is the raw frame and no other Zstandard
frame (floor_frame), its target states the transcript's length and a timebase
(floor_target), and its content is a transcript in graphics-vector §5.4's one encoding
(floor_transcript).

A caption or a subtitle block is never presented from the floor (caption_track): the
text component of its language carries it, and the text layer presents it or not as the
viewer set it. A forced_narrative block is presented from the floor unless the text
layer shows a cue of its language with its string at that millisecond (forced_in_cue),
so the words are on the page once. The text layer presents one text component of a
package, or none.

wai-rs browser_sink::floor is the reference (read, present), which wai-web's compose
bundle calls as TextFloor. Corpus live-conformance/browser-floor/ (49 floors, 25
presentations), written by wai_browser_floor_vectors and regenerating byte for byte on
x86_64 and aarch64; tests/browser_floor.rs also reads the floors wai-pack wrote for
pack-conformance/multi/multi-captions-01, and wai-web's compose::floor_tests holds them
to wai-vector's transcripts. browser_floor_verify.py, the second implementation,
refuses 72 mutated floors each with its defect's reason, fails 23 mutated copies of the
corpus, and each of its 32 checks, dropped, is caught. compose/run.mjs gains case 10.

Not here: a base that is routed and then refused when loaded still refuses the package,
and the overlay path does not yet leave out caption items (graphics-vector §5.7).

Co-Authored-By: Claude <[email protected]>
2026-11-10 22:36:11 -05:00

9.3 KiB
Raw Permalink Blame History

The composing sink

index.html opens a WAI package of several components, dispatches each to a decoder this device can run, checks everything it is about to present against the package's signed receipt, and plays the components on one timeline (browser-sink §14).

file what it is
compose.js the runtime: openPackage() and the Composition it returns
index.html, page.js the reference page: the picture, the dispatch record and the checks
policy.toml, sources/, floor/, key.hex the package's policy and inputs
package/ the package it plays, written by wai-pack (packaging §5.8)
staged/ the staged packages: fields and pictures with layers the page computes (browser-sink §14.5, §14.7)
mutations/forged.receipt.json the package's receipt signed by another key
run.mjs the gate: the page in browser engines, every outcome held to what it expects

The package

One programme of seven seconds as five components under one version-2 package receipt, each cut at the lead's piece starts, each piece one object:

component capability source presented as
v wai.video.int_motion bases and a wai.video.av1 floor for every piece the fixture compose-01, a test pattern of 320 × 180 at 25 frames a second the picture, and the clock
g wai.graphics.vector vector-conformance/vectors/motion/stroke-titles.wvg1, a title card and a credit roll at 1280 × 720 an overlay rasterised in WebAssembly
t wai.text.timed sources/t.vtt, three captions text, in the page's text layer
s wai.audio.score of two channels at 48 kHz, each note voiced, and a wai.audio.flac floor of each piece's mixdown sources/s.wscr, score-conformance/vectors/scale48.wscr's notes up and down samples synthesised in the tab in two channels (or, without the score, the floor decoded from FLAC in WebAssembly), on Web Audio
f wai.feed.state sources/f.wwld, a scoreboard of signed ops the state at the clock's tick

Each entry with a decoded output states its digest, which the page holds what it decodes to: each video base's clip digest, each overlay piece's clip digest, each caption segment's SHA-256, each score piece's sample digest; each feed piece is sealed by the package's key.

wai-pack's corpus check (wai-pack conformance check ../pack-conformance, which tests/conformance.rs runs) writes the sources under sources/, packs the package from them and requires every file the same, verifies it, and writes the forged receipt again (wai_pack::multi_fixture::compose_check; conformance regen writes them). By hand:

# from wai/wai-pack
cargo run --release --bin wai-pack -- fixture gen compose-01 -o ../wai-web/compose/src.y4m
cargo run --release --bin wai-pack -- pack --policy ../wai-web/compose/policy.toml \
  --out <dir> --key ../wai-web/compose/key.hex
cargo run --release --bin wai-pack -- verify <dir>

The staged packages

staged/ holds four packages of one image component each, sealed with key.hex from objects of the corpora, byte for byte, by src/compose_stage.rs's tests, which compute every prefix digest natively and hold it to the corpus's own statement:

package pieces
fields the orb of volumetric-conformance/fields/ (a base carrying two of its four levels, then its levels 2 and 3 as layers 1 and 2), mlp and edge
fields-digest fields, the orb's layer 2 stating stage 1's digest
cond cond_side_planes, cond_dual_gbuffer and cond_render of staged-conformance/cond/: a PNG base, its wai.image.int_cond_refine layer and its side objects as asset entries
cond-not-exact cond_side_not_exact's layer over a plane the page decodes only through its fallback

The page renders each field at its pinned view and each picture's base in WebAssembly, presents them, then takes each layer as it arrives: a field's next level, or a picture's conditioned layer with the side planes it names (a splat set's frame rendered in the page at its pinned pose), each stage held to its signed digest before it is presented; a refused layer leaves the stage below. The tests check, and WAI_COMPOSE_STAGED_WRITE=1 writes them again:

# from wai/wai-web
cargo test --lib --features compose compose_stage::

The AV1 floor floor/v.obu is supplied (packaging §7.3), made the way pack-conformance/supplied_floor.py makes a golden's: wai-pack plan cuts the fixture (two pieces, of 100 and 75 frames), each piece is coded alone by aomenc with that script's settings, and the streams are concatenated. The policy pins the floor directory's listing.

Run the page

# from wai/wai-web: the compose bundle
cargo build --release --target wasm32-unknown-unknown --lib --features compose
wasm-bindgen --target web --out-dir compose/pkg --out-name wai_compose \
  target/wasm32-unknown-unknown/release/wai_web.wasm
# serve wai/, which holds the outline set the overlay names
cd .. && python3 -m http.server 8741
# → http://localhost:8741/wai-web/compose/index.html

Query parameters: without=<capability>,… forces a device profile without those capabilities; receipt=<url> reads another receipt; pkg=<dir>/ another package; captions=<language> has the text layer present the text component in that language, and captions=off none (the default is the first the receipt lists).

Titles as text

A graphics component may carry a text floor: each piece's transcript as wai.text.zstd (graphics-vector §6.3). On a device with no decoder of wai.graphics.vector (without=wai.graphics.vector) the page presents it (browser-sink §14.9): it holds each floor to its piece's base, reads the one frame the format writes and the transcript in its one encoding, and at each tick shows the active blocks as text, each with its language and direction. A caption or a subtitle is never shown from the floor, because the text layer carries it; a forced narrative is shown from the floor unless a cue is showing the same words. pack-conformance/multi/multi-captions-01 is such a package:

http://localhost:8741/wai-web/compose/index.html?pkg=../../pack-conformance/multi/multi-captions-01/package/&without=wai.video.av1,wai.graphics.vector

The gate

cd compose && npm ci
node run.mjs --engines chromium,webkit --pkg pkg

In each engine: the package opens with every check holding and every component presented, and plays to its end; each score piece's samples, synthesised in the tab in the two channels and at the rate its target states, have the digest its index entry states; every overlay frame hashed in the page equals vector-conformance/'s, and each piece's clip digest its entry's; each caption segment and each feed piece holds; without the AV1 decoder each integer video base decodes to its signed clip digest; without the integer rung and the still every video piece plays its AV1 floor and the page says so; without the score every score piece plays its FLAC floor, decoded in WebAssembly to the samples the score's signed base states for its mixdown, and the page says so; in pack-conformance/multi/multi-opus-01, without FLAC, the sound track's Opus floor plays through the engine's AudioDecoder where it takes Opus, each piece trimmed to exactly its samples (an engine whose decoder refuses that golden's 64 × 36 picture refuses it at the lead); the forged receipt is refused receipt-signature and an object with one byte flipped in delivery object-hash, with nothing presented. Over the staged packages: each field renders at its pinned view to the frame digest volumetric-conformance/fields/ states, read back from the canvas; the orb's levels, each held back in delivery and released one at a time, present each stage, its stage hash the corpus's, before the next level is asked for; a stage that is not its signed digest is refused prefix-digest and a level with a byte flipped object-hash, the stage below staying presented; each picture of cond presents the stage hash its case states; a side object withheld, or the splat decoder left out of the profile, refuses its layer side-absent, a plane held only through its fallback side-not-exact, and a side object with a byte flipped is refused object-hash and never held, each with the base presented. Over pack-conformance/multi/multi-captions-01: on this device each graphics piece presents its overlay and nothing comes from a floor; without wai.graphics.vector each presents its floor, whose transcript is the one the script reads from the floor object, and at every frame the text from the floor is the blocks active at that tick less the captions, the text layer shows the cues of the component it presents (English, French with captions=fr, none with captions=off), and a caption's words are on the page once; a floor with a byte flipped, and two floors exchanged in delivery, are refused object-hash; and the bundle's reader refuses a floor held to another piece's base floor_base. --only staged runs the staged cases alone, --only package the reference package's and --only floor the text floor's. It exits 0 only when every check passes in every engine, and 1 on any failure, a page error, an engine it cannot launch, fewer checks than it makes, or an error of its own.