wai: exact tone mapping — wai.meta.gainmap (ISO 21496-1), wai.meta.st2094_50 (SMPTE ST 2094-50), and a rendition every sink at a headroom computes alike (B3b) #430

Closed
dcharlot wants to merge 0 commits from wai/gain-maps into main
Owner

What this is

B3b: HDR gain maps and dynamic metadata, with an exact tone map.

  • Two companions (SPEC §5, §7.1): wai.meta.gainmap carries an ISO 21496-1:2025 gain map (its binary metadata as written, and its gain map image as a PNG of 8-bit samples, in a WGM1 frame) as a companion of an image payload; wai.meta.st2094_50 carries SMPTE ST 2094-50:2026-08 (Application #5) metadata sets in their Annex C encoding, each with the frames it applies to (WD50), as a companion of a video payload. §7.1's rule 2 gains the image media class (the registry's media column) for the gain map; codecs::companion_applies_to and staged_verify.py follow it.
  • The exact derivations (extensions/exact-tonemap.md §3 to §5): wai-tonemap:gainmap and wai-tonemap:st2094-50 map the base's RGB8 samples, the companion's bytes and a headroom (an integer in 1/10000 of a stop, the unit Annex C encodes headrooms in) to one RGB16 rendition, linear light relative to the display's peak. Integer only:
    • L2: bitwise log2 in Q16 from below (16 squarings, each truncating);
    • E2/scale: exp2 as a product of 16 Q30 constants K_i = 2^(2^-i), made by integer square roots (table in §3.3, checked against its rule by both implementations);
    • an sRGB table S[k] (Q30, reference white at 2^30) built from L2/E2;
    • one rounding rule, rnd(a, b) = ⌊(a + ⌊b/2⌋)/b⌋, every intermediate exact in 128 bits;
    • the gain map's upsampling pinned (centre-aligned bilinear over the codes, factor 1/2/4/8, edges repeated) — the one step the standard, as far as known here, leaves to each implementation;
    • ST 2094-50's slopes from θ through a Q62 Taylor series for sin/cos (π pinned as ⌊π·2^62⌋), or by C.3.9's PCHIP on exact rationals; Formulas (2)–(12) each mapped onto an integer step (§5.7).
  • Error against binary64 (§6), over every rendition of the corpus: largest difference 2 code values of 65535 for each derivation; mean 0.1269 (gain map, 10 renditions, 41472 samples) and 0.1642 (ST 2094-50, 25 renditions, 172800 samples). The test fails if the figures in §6 drift from the corpus.
  • The rendition record wai.media.tonemap (kind wai-tonemap, §7, §8): a sink signs the base (envelope content hash, entry index, size), the companion (index, SHA-256), and per picture the frame, headroom, input digest and output digest; a verifier holding the envelope (and, for video, the frames) recomputes each picture. Policy require-proof refuses what it cannot recompute.
  • Provenance: a rendition is a convert step of synthesis §3.2 — it rebuilds what base and companion hold, names no model, generates nothing; its class must be the greatest of reconstructed and its inputs' (class_mismatch). determinism-tiers §2 now names HDR display adaptation as processing that alters the decode, and the pinned derivations as how a sink keeps its tier.
  • Corpus live-conformance/tonemap/ (38 cases, 25 envelope cases): generated HDR scenes (integer formulas: a sky with a sun at 6× reference white and a past-white yellow; a room with a window) rendered to an sRGB base + gain map by the reference's own integer encoder; a single-channel map at 1/4 size, a three-channel map at full size with gamma 2, a map down (alternate headroom below the base's, negative weight); the int_video clip (5 frames, 48×48, decoded by wai.video.int_motion, digests bound to that clip's sidecar) under two ST 2094-50 sets (θ slopes with mixing types 0 and 2 and two alternates; PCHIP with type-3 mixing and a last control point at 0.9 so Formula (12)'s log branch runs), at headrooms below, on, between and past the alternates. Every §9 reason refuses at least one control, each a single defect — among them a rendition stated at another headroom, a headroom past 6 stops, a 13×8 map for a 48×32 base, metadata out of range in each companion, one rendition sample changed, a gain map carried as a rendition (envelope_nonconforming), a gain map bound to another rendition than the record's base. Envelope cases with SPEC's own codes: gain map as a WAI1 capability (companion-only-as-capability), as a selectable rendition (companion-only-as-rendition), bound to video (incompatible-base), ST 2094-50 bound to an image (incompatible-base).
  • Second implementation live-conformance/tonemap_verify.py (python3 -I, stdlib only), written from the text: its own integer arithmetic, PNG reader (zlib + unfilter), ISO metadata and Annex C readers, PCHIP on fractions.Fraction; envelopes and §7.1's rules via staged_verify.py; strict Ed25519 and BLAKE3 from claim-conformance; reads §3.3's K table, §5.4's P and §9's codes from the extension. It agrees with wai-rs on every case and envelope and on the arithmetic vectors (L2, E2, the sRGB table, tan at stated points and as SHA-256 over whole ranges, the video's slopes), recomputes §6 (within 1 code value / 0.01 of the mean), catches 9 corpus mutations, and catches each of its 23 checks dropped in turn.
  • png_still reads and writes 8-bit greyscale (decode_grey_or_rgb, encode_grey; decode/encode unchanged; a palette in a greyscale picture refused).

Decisions the lead should know

  • ISO 21496-1:2025 was not read. Its text is sold; the ANSI preview and iso.org both refused automated fetches. What the extension states of it — the binary field list (§4.2) and the application formula (§4.5) — is what ST 2094-50:2026-08's terms 3.1–3.11 say of it and what public open-source readers of its binary metadata implement; each such statement is marked in the text, and the header says a revision that reads the standard confirms or corrects them. Nothing is attributed to the standard that was not seen.
  • ST 2094-50:2026-08 was read in full (every clause and annex, from its published HTML; figures not read). Its Foreword records claimed IPR under RAND assurance and no royalty-free commitment.
  • Licence class patent-pool for both (royalty status not established; conservative, as NNC), replicate class standard-unclassified (the standards state the rendition in real numbers; the exact rendition is WAI's derivation, not a property of the capability). Fidelity tier lossless (descriptor bytes), as for the existing HDR descriptors.
  • Derivation kind: the derivations are extension terms (wai-tonemap:*), not wai.derive.* strings — the registry's derivation kind is ISO/IEC 23001-16's operations, and a tone map is none of them (as wai-upscale:sr2 in #408).
  • Record, not #408's presentation statement: #408 (wai.media.upscale) is not merged, so this registers its own record wai.media.tonemap following #408's pattern (session key, digests per picture, recomputation, policy). Once #408 lands, a tone-mapped picture can be referenced from its presentation statement; nothing here conflicts with it textually except an adjacent paragraph in determinism-tiers §2.
  • Scope limits stated as refusals, not silently approximated: base read as sRGB-coded RGB8; gain applied in the base's primaries only (ISO use_base_colour_space 0, ST 2094-50 chromaticity modes 1–3 and the reference-white tone map of C.3.8, which sets BT.2020 primaries, are gain_space_unsupported); WAI's ranges for the exact derivation (headroom ≤ 6, |gain| ≤ 16 stops, gamma in [1/64, 64], |offset| ≤ 1, last control point x > 0) are metadata_out_of_range. A set with no tone map is applied as identity + projection (B.4); §5.2 says so.
  • Output encoding: RGB16, linear, normalised to the display's peak (code = T / 2^h · 65535, clamped — the projection of ST 2094-50 A.4 Note), each sample little-endian.

Checks

check command result
corpus + reasons + §6 + int_video frames rb … cargo test --no-default-features --features exact_tonemap --test exact_tonemap 4 passed
module + PNG unit tests rb … cargo test --no-default-features --features exact_tonemap --lib -- exact_tonemap:: png_still:: 11 passed
all lib tests under the feature rb … cargo test --no-default-features --features exact_tonemap --lib 584 passed
lib tests, the CI feature set rb … cargo test --lib --no-default-features --features world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,oer,receipt_claims,key_discovery,staged,video_int,audio_int,splat_int,stage_measure,telemetry,video_package,http 843 passed
carriage/registry CLI tests rb … cargo test --no-default-features --test carriage --test manifest_builders --test cli_wrap_intent --test cli_registry --test corpus_provenance all passed
default-feature suite rb … cargo test --locked all passed
corpus regenerates rb … cargo run --no-default-features --features exact_tonemap --bin wai_tonemap_vectors -- verify ../live-conformance/tonemap ok: 27 files
registry export rb … cargo run -q --no-default-features --bin wai -- registry export --check up to date
clippy, touched files rb … cargo clippy --no-default-features --features exact_tonemap --all-targets and default --all-targets, filtered to the touched files 0 notes (pre-existing notes elsewhere unchanged; int_payload::unpinned_read dead-code warning is pre-existing for any neural_int build without neural)
second implementation python3 -I live-conformance/tonemap_verify.py live-conformance/tonemap 38 cases, 25 envelope cases, 9 mutations, 23 checks dropped: 0 failures
staged corpus (companion rule updated) python3 -I staged-conformance/staged_verify.py staged-conformance 0 failures
repo checks check-tests-in-ci.py, check-workflow-concurrency.sh, check-spec-refs.py, check-wai-section-refs.py, check-no-vanity-metrics.sh, test-public-text-checks.sh, check-comparative-prose.sh, check-orphan-sources.py all clean
public names check-public-names.sh on every changed text file, commit messages and this body with the private patterns clean
Cargo.lock features only, no dependency added unchanged

Falsifications

Committed first; each patch applied to a scratch copy, the test run, the copy restored.

Python (tonemap_verify.py, exit codes):

  • §3.3's K_16 changed by one → exit 1 (§3.3's table of K is not its rule).
  • §6's largest difference for the gain map stated as 1 → exit 1.
  • frame_uncovered dropped from §9 → passed (exit 0) before, so the verifier gained a check that every refusal code is in §9 (commit 17e56b609); now exit 1.
  • one byte of frames.rgb8 flipped → exit 1 (frames no longer the sidecar's; the video case refused input_samples_mismatch).
  • built in: 9 corpus mutations and each of 23 checks dropped in turn are all caught.

Rust (tests/exact_tonemap.rs):
Each row: the patch, then cargo test --no-default-features --features exact_tonemap --test exact_tonemap's exit code and the tests that failed. Unpatched: exit 0; restored after each: exit 0.

falsification exit failing tests
F1 the input-digest check dropped from verify_record 101 corpus regenerates / every case its outcome
F2 rnd rounds halves down 101 corpus; §6 measurement
F3 the gain map's bilinear weights swapped 101 corpus; §6 measurement
F4 the class lattice not checked 101 corpus
F5 frame_uncovered dropped from §9 101 the_extension_lists_the_reasons
F6 §6's largest difference stated as 1 101 the_extension_states_the_measurement
F7 tan's series cut to 5 terms 0 at first → 101 the corpus's renditions did not expose it; the corpus now states the arithmetic at fixed points and the SHA-256 of tan over every angle (commit 96a822528)
F8 ST 2094-50's headroom weights reversed 101 corpus; §6 measurement
F10 L2's squarings rounded instead of truncated 0 at first → 101 the variant differs on ~3 in 10^5 mantissas, none in the corpus; the corpus now states the SHA-256 of L2 at 2^18 spread values and of E2 over every fraction (commit 2b54ac205)
F11 E2's products truncated instead of rounded 101 corpus; §6 measurement

Not done

  • ISO 21496-1:2025's own text: field semantics and the application formula rest on ST 2094-50's references and public readers (marked in the text). A revision that reads the standard should confirm §4.2/§4.5, and the upsampling filter (if the standard pins one, §4.4 step 3 should follow it).
  • Bases in other transfers (PQ, HLG, BT.709/BT.1886) and gain application spaces with other primaries (a primaries matrix in exact rationals is feasible, not built).
  • ST 2094-50's reference-white tone map (C.3.8), which needs BT.2020 primaries and a Bézier sampling in integer arithmetic.
  • vocab/check_shapes.py was not run locally (needs rdflib/pyshacl, which the CI job installs); the shapes are generated by the registry export, which --check confirms.
  • #408's presentation statement is not reused (unmerged); a follow-up can let it name wai-tonemap records.

🤖 Generated with Claude Code


Closed: landed on main through merge train C (#461, e0ac15f5); this PR's head is an ancestor of main.

## What this is B3b: HDR gain maps and dynamic metadata, with an exact tone map. - **Two companions** (SPEC §5, §7.1): `wai.meta.gainmap` carries an ISO 21496-1:2025 gain map (its binary metadata as written, and its gain map image as a PNG of 8-bit samples, in a `WGM1` frame) as a companion of an **image** payload; `wai.meta.st2094_50` carries SMPTE ST 2094-50:2026-08 (Application #5) metadata sets in their Annex C encoding, each with the frames it applies to (`WD50`), as a companion of a **video** payload. §7.1's rule 2 gains the `image` media class (the registry's `media` column) for the gain map; `codecs::companion_applies_to` and `staged_verify.py` follow it. - **The exact derivations** (`extensions/exact-tonemap.md` §3 to §5): `wai-tonemap:gainmap` and `wai-tonemap:st2094-50` map the base's `RGB8` samples, the companion's bytes and a headroom (an integer in 1/10000 of a stop, the unit Annex C encodes headrooms in) to one `RGB16` rendition, linear light relative to the display's peak. Integer only: - `L2`: bitwise log2 in Q16 from below (16 squarings, each truncating); - `E2`/`scale`: exp2 as a product of 16 Q30 constants `K_i = 2^(2^-i)`, made by integer square roots (table in §3.3, checked against its rule by both implementations); - an sRGB table `S[k]` (Q30, reference white at 2^30) built from `L2`/`E2`; - one rounding rule, `rnd(a, b) = ⌊(a + ⌊b/2⌋)/b⌋`, every intermediate exact in 128 bits; - the gain map's upsampling pinned (centre-aligned bilinear over the codes, factor 1/2/4/8, edges repeated) — the one step the standard, as far as known here, leaves to each implementation; - ST 2094-50's slopes from θ through a Q62 Taylor series for sin/cos (π pinned as ⌊π·2^62⌋), or by C.3.9's PCHIP on exact rationals; Formulas (2)–(12) each mapped onto an integer step (§5.7). - **Error against binary64** (§6), over every rendition of the corpus: largest difference **2** code values of 65535 for each derivation; mean 0.1269 (gain map, 10 renditions, 41472 samples) and 0.1642 (ST 2094-50, 25 renditions, 172800 samples). The test fails if the figures in §6 drift from the corpus. - **The rendition record** `wai.media.tonemap` (kind `wai-tonemap`, §7, §8): a sink signs the base (envelope content hash, entry index, size), the companion (index, SHA-256), and per picture the frame, headroom, input digest and output digest; a verifier holding the envelope (and, for video, the frames) recomputes each picture. Policy `require-proof` refuses what it cannot recompute. - **Provenance**: a rendition is a `convert` step of synthesis §3.2 — it rebuilds what base and companion hold, names no model, generates nothing; its `class` must be the greatest of `reconstructed` and its inputs' (`class_mismatch`). determinism-tiers §2 now names HDR display adaptation as processing that alters the decode, and the pinned derivations as how a sink keeps its tier. - **Corpus** `live-conformance/tonemap/` (38 cases, 25 envelope cases): generated HDR scenes (integer formulas: a sky with a sun at 6× reference white and a past-white yellow; a room with a window) rendered to an sRGB base + gain map by the reference's own integer encoder; a single-channel map at 1/4 size, a three-channel map at full size with gamma 2, a map down (alternate headroom below the base's, negative weight); the `int_video` clip (5 frames, 48×48, decoded by `wai.video.int_motion`, digests bound to that clip's sidecar) under two ST 2094-50 sets (θ slopes with mixing types 0 and 2 and two alternates; PCHIP with type-3 mixing and a last control point at 0.9 so Formula (12)'s log branch runs), at headrooms below, on, between and past the alternates. Every §9 reason refuses at least one control, each a single defect — among them a rendition stated at another headroom, a headroom past 6 stops, a 13×8 map for a 48×32 base, metadata out of range in each companion, one rendition sample changed, a gain map carried as a rendition (`envelope_nonconforming`), a gain map bound to another rendition than the record's base. Envelope cases with SPEC's own codes: gain map as a `WAI1` capability (`companion-only-as-capability`), as a selectable rendition (`companion-only-as-rendition`), bound to video (`incompatible-base`), ST 2094-50 bound to an image (`incompatible-base`). - **Second implementation** `live-conformance/tonemap_verify.py` (`python3 -I`, stdlib only), written from the text: its own integer arithmetic, PNG reader (zlib + unfilter), ISO metadata and Annex C readers, PCHIP on `fractions.Fraction`; envelopes and §7.1's rules via `staged_verify.py`; strict Ed25519 and BLAKE3 from claim-conformance; reads §3.3's K table, §5.4's P and §9's codes from the extension. It agrees with wai-rs on every case and envelope and on the arithmetic vectors (`L2`, `E2`, the sRGB table, `tan` at stated points and as SHA-256 over whole ranges, the video's slopes), recomputes §6 (within 1 code value / 0.01 of the mean), catches 9 corpus mutations, and catches each of its 23 checks dropped in turn. - `png_still` reads and writes 8-bit greyscale (`decode_grey_or_rgb`, `encode_grey`; `decode`/`encode` unchanged; a palette in a greyscale picture refused). ## Decisions the lead should know - **ISO 21496-1:2025 was not read.** Its text is sold; the ANSI preview and iso.org both refused automated fetches. What the extension states of it — the binary field list (§4.2) and the application formula (§4.5) — is what ST 2094-50:2026-08's terms 3.1–3.11 say of it and what public open-source readers of its binary metadata implement; each such statement is marked in the text, and the header says a revision that reads the standard confirms or corrects them. Nothing is attributed to the standard that was not seen. - **ST 2094-50:2026-08 was read in full** (every clause and annex, from its published HTML; figures not read). Its Foreword records claimed IPR under RAND assurance and no royalty-free commitment. - **Licence class `patent-pool` for both** (royalty status not established; conservative, as NNC), **replicate class `standard-unclassified`** (the standards state the rendition in real numbers; the exact rendition is WAI's derivation, not a property of the capability). Fidelity tier `lossless` (descriptor bytes), as for the existing HDR descriptors. - **Derivation kind**: the derivations are extension terms (`wai-tonemap:*`), not `wai.derive.*` strings — the registry's derivation kind is ISO/IEC 23001-16's operations, and a tone map is none of them (as `wai-upscale:sr2` in #408). - **Record, not #408's presentation statement**: #408 (`wai.media.upscale`) is not merged, so this registers its own record `wai.media.tonemap` following #408's pattern (session key, digests per picture, recomputation, policy). Once #408 lands, a tone-mapped picture can be referenced from its presentation statement; nothing here conflicts with it textually except an adjacent paragraph in determinism-tiers §2. - **Scope limits stated as refusals, not silently approximated**: base read as sRGB-coded `RGB8`; gain applied in the base's primaries only (ISO `use_base_colour_space` 0, ST 2094-50 chromaticity modes 1–3 and the reference-white tone map of C.3.8, which sets BT.2020 primaries, are `gain_space_unsupported`); WAI's ranges for the exact derivation (headroom ≤ 6, |gain| ≤ 16 stops, gamma in [1/64, 64], |offset| ≤ 1, last control point x > 0) are `metadata_out_of_range`. A set with no tone map is applied as identity + projection (B.4); §5.2 says so. - **Output encoding**: `RGB16`, linear, normalised to the display's peak (`code = T / 2^h · 65535`, clamped — the projection of ST 2094-50 A.4 Note), each sample little-endian. ## Checks | check | command | result | |---|---|---| | corpus + reasons + §6 + int_video frames | `rb … cargo test --no-default-features --features exact_tonemap --test exact_tonemap` | 4 passed | | module + PNG unit tests | `rb … cargo test --no-default-features --features exact_tonemap --lib -- exact_tonemap:: png_still::` | 11 passed | | all lib tests under the feature | `rb … cargo test --no-default-features --features exact_tonemap --lib` | 584 passed | | lib tests, the CI feature set | `rb … cargo test --lib --no-default-features --features world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,oer,receipt_claims,key_discovery,staged,video_int,audio_int,splat_int,stage_measure,telemetry,video_package,http` | 843 passed | | carriage/registry CLI tests | `rb … cargo test --no-default-features --test carriage --test manifest_builders --test cli_wrap_intent --test cli_registry --test corpus_provenance` | all passed | | default-feature suite | `rb … cargo test --locked` | all passed | | corpus regenerates | `rb … cargo run --no-default-features --features exact_tonemap --bin wai_tonemap_vectors -- verify ../live-conformance/tonemap` | ok: 27 files | | registry export | `rb … cargo run -q --no-default-features --bin wai -- registry export --check` | up to date | | clippy, touched files | `rb … cargo clippy --no-default-features --features exact_tonemap --all-targets` and default `--all-targets`, filtered to the touched files | 0 notes (pre-existing notes elsewhere unchanged; `int_payload::unpinned_read` dead-code warning is pre-existing for any `neural_int` build without `neural`) | | second implementation | `python3 -I live-conformance/tonemap_verify.py live-conformance/tonemap` | 38 cases, 25 envelope cases, 9 mutations, 23 checks dropped: 0 failures | | staged corpus (companion rule updated) | `python3 -I staged-conformance/staged_verify.py staged-conformance` | 0 failures | | repo checks | `check-tests-in-ci.py`, `check-workflow-concurrency.sh`, `check-spec-refs.py`, `check-wai-section-refs.py`, `check-no-vanity-metrics.sh`, `test-public-text-checks.sh`, `check-comparative-prose.sh`, `check-orphan-sources.py` | all clean | | public names | `check-public-names.sh` on every changed text file, commit messages and this body with the private patterns | clean | | Cargo.lock | features only, no dependency added | unchanged | ## Falsifications Committed first; each patch applied to a scratch copy, the test run, the copy restored. Python (`tonemap_verify.py`, exit codes): - §3.3's K_16 changed by one → exit 1 (`§3.3's table of K is not its rule`). - §6's largest difference for the gain map stated as 1 → exit 1. - `frame_uncovered` dropped from §9 → **passed (exit 0) before**, so the verifier gained a check that every refusal code is in §9 (commit 17e56b609); now exit 1. - one byte of `frames.rgb8` flipped → exit 1 (frames no longer the sidecar's; the video case refused `input_samples_mismatch`). - built in: 9 corpus mutations and each of 23 checks dropped in turn are all caught. Rust (`tests/exact_tonemap.rs`): Each row: the patch, then `cargo test --no-default-features --features exact_tonemap --test exact_tonemap`'s exit code and the tests that failed. Unpatched: exit 0; restored after each: exit 0. | falsification | exit | failing tests | |---|---|---| | F1 the input-digest check dropped from `verify_record` | 101 | corpus regenerates / every case its outcome | | F2 `rnd` rounds halves down | 101 | corpus; §6 measurement | | F3 the gain map's bilinear weights swapped | 101 | corpus; §6 measurement | | F4 the class lattice not checked | 101 | corpus | | F5 `frame_uncovered` dropped from §9 | 101 | `the_extension_lists_the_reasons` | | F6 §6's largest difference stated as 1 | 101 | `the_extension_states_the_measurement` | | F7 `tan`'s series cut to 5 terms | **0 at first** → 101 | the corpus's renditions did not expose it; the corpus now states the arithmetic at fixed points and the SHA-256 of `tan` over every angle (commit 96a822528) | | F8 ST 2094-50's headroom weights reversed | 101 | corpus; §6 measurement | | F10 `L2`'s squarings rounded instead of truncated | **0 at first** → 101 | the variant differs on ~3 in 10^5 mantissas, none in the corpus; the corpus now states the SHA-256 of `L2` at 2^18 spread values and of `E2` over every fraction (commit 2b54ac205) | | F11 `E2`'s products truncated instead of rounded | 101 | corpus; §6 measurement | ## Not done - ISO 21496-1:2025's own text: field semantics and the application formula rest on ST 2094-50's references and public readers (marked in the text). A revision that reads the standard should confirm §4.2/§4.5, and the upsampling filter (if the standard pins one, §4.4 step 3 should follow it). - Bases in other transfers (PQ, HLG, BT.709/BT.1886) and gain application spaces with other primaries (a primaries matrix in exact rationals is feasible, not built). - ST 2094-50's reference-white tone map (C.3.8), which needs BT.2020 primaries and a Bézier sampling in integer arithmetic. - `vocab/check_shapes.py` was not run locally (needs rdflib/pyshacl, which the CI job installs); the shapes are generated by the registry export, which `--check` confirms. - #408's presentation statement is not reused (unmerged); a follow-up can let it name `wai-tonemap` records. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- **Closed:** landed on main through merge train C (#461, e0ac15f5); this PR's head is an ancestor of main.
decode_grey_or_rgb reads colour type 0 or 2 under the reader's rules (a
palette refused in a greyscale picture); encode_grey writes colour type 0
with the same Sub filter and fixed deflate. decode and encode are unchanged.
A gain map's picture is carried as such a PNG (extensions/exact-tonemap.md).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The extension text (extensions/exact-tonemap.md), the exact_tonemap module
of wai-rs (integer log2/exp2, the sRGB table, wai-tonemap:gainmap and
wai-tonemap:st2094-50, the rendition record and its verification), the
registry rows and SPEC §5 / §7.1 text for the two companions, the glossary
entries, and the corpus live-conformance/tonemap/ written by
wai_tonemap_vectors gen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
tonemap_verify.py, written from extensions/exact-tonemap.md: its own integer
log2/exp2, sRGB table, gain map and ST 2094-50 derivations, Annex C reader,
PCHIP on exact rationals and PNG reader; envelopes and SPEC §7.1's component
rules through staged_verify.py, which now knows the two new companions' base
classes. It agrees with wai-rs on every case, recomputes §6's measurement,
and catches every mutation and every dropped check. Two cases added so the
binding check is load-bearing: a base index that names the companion, and a
gain map bound by id to another rendition than the record's base.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The wai-conformance step runs the module's and the PNG reader's unit tests,
tests/exact_tonemap.rs and tonemap_verify.py; the extension is in the
workflow's paths. determinism-tiers §2 names HDR display adaptation as
processing that alters the decode, and the pinned derivations as the way a
sink keeps its tier. The research registry records what was read for the two
companions and why both are classified conservatively. The carriage test
binds the gain map to an image, as rule 2 now requires. png_still gains a
greyscale round-trip test; clippy notes in the new code fixed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
tonemap_verify: a refusal with a code §9 does not list fails the corpus
Some checks failed
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 reach builds / wai-web reach · does this change touch it (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (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
17e56b609b
Falsified: §9 without frame_uncovered passed before this check (exit 0)
and fails with it (exit 1).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A falsification showed the corpus's renditions do not expose every error in
the arithmetic: tan's series cut to five terms still regenerated the corpus
(slopes off by less than a code value's worth). vectors.json now states L2,
E2, the sRGB table, tan across its range of angles and the video's slopes at
fixed points; both implementations check them, and a stated tan changed by
one is a mutation the Python verifier requires to fail.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A second falsification: L2's squarings rounded instead of truncated still
regenerated the corpus (the variant differs on about 3 in 100000 mantissas).
vectors.json now states the SHA-256 of L2 at 2^18 spread values, of E2's
mantissa for every fraction and of tan for every angle; both implementations
check them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
tonemap corpus: no cast of L2's value to its own type (clippy)
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 conformance / does this change touch it (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
wai cross-architecture byte-equality / does this change touch it (pull_request) Has been cancelled
wai cross-architecture byte-equality / linux-aarch64 (pull_request) Has been cancelled
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Has been cancelled
wai cross-architecture byte-equality / macos-arm64 (reference) (pull_request) Has been cancelled
standards workspaces build + test / which workspaces this change touches (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (pull_request) Has been cancelled
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Has been cancelled
joule-code conformance gate / joule-moq-relay, every target (pull_request) Has been cancelled
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Has been cancelled
17ff17d84f
Co-Authored-By: Claude Opus 5.5 <[email protected]>
dcharlot closed this pull request 2026-10-25 23:51:17 -04:00
Some checks failed
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
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (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-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-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 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 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 energy receipts / does this change touch it (pull_request) Has been cancelled
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 conformance / does this change touch it (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
wai cross-architecture byte-equality / does this change touch it (pull_request) Has been cancelled
wai cross-architecture byte-equality / linux-aarch64 (pull_request) Has been cancelled
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Has been cancelled
wai cross-architecture byte-equality / macos-arm64 (reference) (pull_request) Has been cancelled
standards workspaces build + test / which workspaces this change touches (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (pull_request) Has been cancelled
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Has been cancelled
joule-code conformance gate / joule-moq-relay, every target (pull_request) Has been cancelled
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!430
No description provided.