wai: D2c M7a — jpegai's scale path and entropy decodes through wai-ops/1 (jpegai-int/1) #298

Closed
dcharlot wants to merge 0 commits from wai/d2c-m7a into main
Owner

D2c M7a: wai.image.jpegai's scale path and its two entropy decodes run through the integer operator set wai-ops/1, lowered by jpegai-int/1 (integer-operators §13.6.1), on both reference decode paths. Every committed and pinned golden is unchanged.

Not stacked: #274 (M6, this branch's base) merged as 80477972. origin/main is merged in (last at bea79dc6); CHANGELOG keeps both sides, this branch's section first.

What changes

  • The lowering, from the bundle a decoder holds. wai-ops gains lower::parse_jpegai (the members of norm.json and Table 13.6-A, typed), lower::jpegai_net and lower::jpegai_net_loaded (the same lowering of a bundle already parsed, the last loading both scale graphs without writing and parsing them again), lower::jpegai::scale (one plane's graph) and stage::mans::decode_sgm_tables (E8 with its latent tables built once). lower::jpegai is now parse, then lower. The committed graphs and certificates are unchanged.
  • The driver (wai-rs/src/jpegai_ops.rs, new). load / load_bytes give a ScalePath: §13.6.1's load checks, the two scale graphs loaded under acc32, the latent tables, the hyper-latent rows and the gains. plane decodes one plane's integers as §13.6.1 steps 1 to 4 give them: a fresh fac decode over SOZ (for chroma, the 160 luma rows first, decoded with luma's rows and discarded), the scale graph, coded, block_stat, band_lookup, scale_index, then a fresh sgm decode over SORP or SORS. It refuses with the operator set's codes and never panics on a stream.
  • The switch. jpegai_decode::{decode, decode_with_stages} run the scale path and the entropy decodes through the driver, and return Result<Rgb, Refusal> (Refusal::Scope with check_scope's reason, or Refusal::Ops with model_mismatch or stream_exhausted). jpegai_decode::{load, decode_loaded} decode with a scale path loaded once. NormTables' bounds and CDF rows are i64, so a load check sees the value the file gives, not a byte it wrapped to.
  • The direct path, test-only (legacy_int): jpegai_decode::legacy, jpegai_ops::legacy, and the pieces they run: the crate-root mANS port, jpegai_synthesis::decode_hyper_scale and the pipeline's skip_mask, rvs_additive, rvs_likely and sigma_index. The calibration tests that read them require legacy_int.
  • The duplicates retire (O10). neural/jpegai_hyper.rs and neural/jpegai_mans.rs are deleted. The float decode path (neural::jpegai) builds a ScalePath from its own bundle's members (the normative PMFs and bounds, the factorized CDFs, the gains, the scale network in its blocks form, jpegai_ops::scale_net_of_blocks) and decodes each plane through the same jpegai_ops::plane. A bundle whose hyper-latent offsets are not 31, or that fails a load check, is refused.
  • No silent fallback (O9). The neural sink lowers and loads the scale path from the members' bytes through the store of loaded sets (int_set_cache, keyed by the listing of norm.json, weights/hs_y.json and weights/hs_uv.json; ScalePath is Resident). A refusal of the exact decode is the decode's result: model_mismatch, stream_exhausted, or set_incomplete for a member the set lacks. Only a sink without the bundle (no norm.json), or a thread or target that cannot run the float stages (check_scope), takes the float path.
  • The browser crate. decodeJpegAiMans decodes through E8 (jpegai_ops::latent_span) and throws on a refusal; decodeJpegAiFull reports the decode's refusal. The site's reference vector gives the same symbols and hash.
  • Registry: wai.image.jpegai gains the ops member { wai-ops/1, acc32, full, jpegai-int/1 } (no stage modes: E8 and the scale path's stage operators have none). registry/capabilities.json regenerated.
  • Text: integer-operators (the status note; §13.6.1 step 3's band edges; §15.3 item 4), determinism-tiers §5 (both codes; both paths decode the claim's stages through the operator set at acc32; a sink that holds the bundle reports the exact decode's refusal and does not fall back), SPEC §5's row, SPEC §7's NeuralEntropyExact entry, SPEC §8's planned breaks, CHANGELOG.
  • CI: tests/jpegai_ops.rs in both fast-kernel steps of wai-conformance.yml (its pinned-bundle cases skip there); wai-jpegai-e2e.yml runs jpegai_ops and jpegai_memory on the fetched bundle with WAI_REQUIRE_SOTA_VECTORS=1, requiring every test by name and no skip banner, and fires on the files they read; the nightly differential names the jpegai half.

A defect found: the residual-variance band edges

The exact decoder, and §13.6.1 step 3 transcribed from it, put a block whose likely was exactly 1003, 1352 or 1937 in the next band, for its σ addition and for its dequantisation multiplier. The reference decoder's own tables (4352 entries per branch, indexed by likely; the 18 tables dumped from the reference decoder, and the ones the float path reads) change value at 1004, 1353 and 1938 in both branches and for both the addition and the dequant. The edges are now 1004, 1353 and 1938 in the decoder and in §13.6.1, and §15.3 item 4 records it. jpegai_rvs_bands_are_the_reference_tables holds both branches' additions and multipliers to the reference's tables at every index. On test256.bin no block's likely lies within 2 of an edge (the reference's own likely, luma 0 to 1357, chroma 0 to 908, equals the decoder's), so no output changes; the two reference decode paths disagreed on codestreams that have such a block. The exact decoder's comment that "one block lands exactly on edge 1352" did not hold for the reference decoder's likely.

Planned breaks (integer-operators §15.3 item 4, SPEC §8)

On both reference decode paths, refused before the streams where the decoder decoded or panicked:

  • a bundle that fails a load check of §13.6.1 (model_mismatch), among them a bound above 255 or a shift outside 0..=127, which the loader wrapped;
  • a bundle whose scale graphs do not meet acc32, the capability's profile: a sum past i32, or a shift past 63 (model_mismatch). acc32 holds every shift to at most 63 (§7.1), so a shift of 64 to 127 is this refusal;
  • a latent or hyper-latent substream that ends before the decode it carries (stream_exhausted), where the decoder panicked.

The codestream's scope is checked first, then the bundle, then the streams. No committed bundle or codestream is affected (the committed synthetic bundle and the pinned jpegai/v1 load under acc32, and every committed and pinned decode is unchanged).

Gates, each red once and restored

gate commits falsification red
band edges 18646564 the edges back to 1003, 1352, 1937 jpegai_mans_golden: "σ addition, flag false, likely 1003" (−31); the pinned decode stays green
1 lowering and certificates 2778f166 the conversion reads the depthwise block's shifts from conv1's member jpegai_ops, both tests: "the converted bundle is the one wai-ops parses from the bytes"
2 golden equality a6875276, 9d8cad8e chroma's fac decode skips the 160 luma rows' reads (Part 3.5) jpegai_ops 2 of 4 (Refusal { StreamExhausted, Symbol(711) }; the whole decode Ops(StreamExhausted)), jpegai_e2e_chroma (the same); the file-based goldens stay green (the switch is gate 6)
2 B_y read as signed in E8 (Part 3.5) every M7a golden stays green: no reference stream decodes an escape at a distribution whose bound is 128 or more, so the prediction that jpegai_mans_golden carries this row is corrected. Red: wai-verify vectors verify, stage/mans_decode.jsonl line 12 (a vector with a bound of 128)
3 refusal parity, ops member d709a776, aff9584c, 4ac4c3e7 the bounds load check admits 256 jpegai_ops: "bounds: one of 256: the load from bytes accepts it"
4 differential 758d36d5, 35f3d9a2, ffba2989, efc71269 a shift of 32 to 63 read mod 32 in the conversion (only random bundles reach it) gates 1 to 3 and the stage tests green; the differential red, "Luma: the two decodes differ", seed 7073408957376268560. A first version of this fault (every shift mod 32) also reddened gate 3's fixture, a shift of 128 read as 0
5 fast kernels ffba2989, 0e456c9a channel-0 requantisation on the fast path jpegai_ops::fast_kernels and 5 other int_ops equivalence tests; jpegai_ops::every_kernel_policy_decodes_the_planes_alike: "jpegai/v1 Luma: Policy { path: Fast, threads: 1 } differs from the interpreter alone"
6 the switch 5bd789bf, 0e456c9a, fe0c6e20, 25013a85, b8710703 rq floor → half_up in jpegai-int/1's convolutions now the file-based goldens: jpegai_cross_platform, jpegai_e2e_chroma, jpegai_hyperscale_calibration (luma 8263/40960 exact, max|Δ| = 172; chroma 8/24576, 80), and the committed graphs
6 memory a plane holds every mask and σ_idx twice while its latent decodes jpegai_memory: "Luma: the front half through the operator set held 2666864 bytes; directly, 2218884"
7 delete 8386f0f4, 15f0a282 the test-only direct mANS port refills its window to 48 bits production green (the CI trio, byte-exact's E8 golden); the comparisons red: jpegai_ops 4 of 9, byte-exact's direct-port golden, the differential (seed 10208061212434326836)

The other commits: 1d53d003 (the CHANGELOG names the retired duplicates); 62768898 and 0fba6461 (narrower K27 harnesses, withdrawn in 3bc90f02, see Kani below); and the merges of origin/main, 7c4c4bd3, c329f46d and b9afc889.

A memory fault placed in the decode's shared back half (the latents held through synthesis) stayed green, as it should: it moves both decodes alike. The fault above is the one the test is for.

Pinned inputs: what ran, with no skip

  • jpegai/v1 was fetched on the build host with tools/wai_jpegai_fetch_e2e_inputs.sh, every file checked against tools/jpegai-e2e-v1.sha256, as wai-jpegai-e2e.yml does, and every pinned-input test ran with WAI_REQUIRE_SOTA_VECTORS=1.
  • The reference-decoder stage fixtures the NOT-IN-CI tests read (WAI_JPEGAI_FRONTEND_FIXTURE, WAI_JPEGAI_HYPERSCALE_IO) no longer existed anywhere. They were rebuilt on the build host from the local reference assets' dumps (the reference decoder's entropy calls, scale, LSBS and synthesis dumps) and jpegai/v1's norm.json, by a scratch script, and checked first against the unchanged tests at this branch's base, where jpegai_e2e_frontend, jpegai_e2e_chroma and jpegai_hyperscale_calibration (both planes) passed with the figures their comments record. The assets root was copied to the build host for jpegai_mans_golden and the float path's tests.
  • Ran, every case checking its input: jpegai_e2e_full, jpegai_reconstruction_binding (the pinned pixel hash), jpegai_cross_platform (all 9 hashes), jpegai_ops (9), jpegai_memory, jpegai_e2e_frontend, jpegai_e2e_chroma, jpegai_hyperscale_calibration (luma and chroma), jpegai_mans_golden (12), the neural dispatch tests (3), the float path's jpegai_e2e, jpegai_live and jpegai_scope_ort, byte-exact jpegai_golden, and wai-ops' jpegai_scale_path_on_a_supplied_bundle and mans_matches_reference_encoder_streams.

Results on the merged head

All on the build host, at 3bc90f02 (main merged in at bea79dc6).

  • gate.sh d2c-m7a-merged: GREEN. The build, the lib tests, carriage, the corpus loop (21 of 21), the fast kernels, byte-exact, wai-web wasm32 and the neural gates all passed.
  • The M7a goldens, unchanged:
    • jpegai_hyperscale_calibration: luma 40960/40960 and chroma 24576/24576 exact, max|Δ| = 0.
    • jpegai_mans_golden: 12 of 12.
    • byte-exact jpegai_golden: E8 and the direct port both decode the reference stream.
    • jpegai_e2e_chroma: U and V max|Δ| = 1, 4426/131072 differ, as before.
    • jpegai_e2e_frontend: Y from the codestream 916/65536, from the reference latent 788/65536, as before.
    • jpegai_cross_platform: every hash; against the reference PNG max|Δ| = 1, 8742/196608 differ, as before.
    • jpegai_reconstruction_binding and jpegai_e2e_full pass on the pinned pixel hash.
  • The differential (int_ops_differential, the jpegai half; each case decodes two planes, and a planned break is counted per case):
    • The per-push run: 1500 cases, seed 3372. Planes decoded alike: 226. Refused where the direct decode panicked: 2194. Refused where the unchecked build computed on: 0. Breaks: acc32 55, bounds 27, cdfs 36, dims 51, gains 24, per_channel 16, pmf 34, shift 47.
    • Timed, 300 s, seed 20261016, release: 29,656 cases. Alike 5,091, refused 42,893, computed on 0. Breaks: acc32 830, bounds 502, cdfs 918, dims 818, gains 460, per_channel 445, pmf 942, shift 749.
    • The same in debug, where overflow checks make the direct decode panic exactly where E8 refuses: 1,229 cases. Alike 195, refused 1,767, computed on 0. Breaks: acc32 32, bounds 26, cdfs 52, dims 36, gains 22, per_channel 20, pmf 29, shift 31.
    • No case panicked through the operator set.
  • Memory (jpegai_memory: the heap's peak during the call, jpegai/v1, reference kernels):
    • The whole decode holds 175,465,380 bytes directly, and the same 175,465,380 through the operator set with the scale path loaded beforehand. The peak is in the shared back half.
    • Loading the scale path takes 14,083,663 bytes while it runs and holds 7,557,178 afterwards. Loading and decoding in one call holds 183,012,574.
    • The front half, which is what this milestone changes: luma holds 2,114,160 bytes through the operator set against 2,218,884 directly; chroma holds 1,290,864 against 1,357,586.
  • Timings. Release builds, 3 rounds, each figure the mean with the minimum in brackets. The host was carrying other sessions' load (load average about 120 to 130), so treat these as rough.
    • Loading the scale path: 3.2 to 5.2 ms from the parsed bundle (2.7), 74 to 89 ms from the members' bytes (58).
    • The luma front half: 6.4 to 12.2 ms through the operator set (3.8), 28 to 36 ms directly (21).
    • The chroma front half: 2.9 to 4.5 ms (2.0), 10 to 11 ms directly (6.9).
    • The whole decode: 2.0 to 2.5 s by either path, within the host's noise. Its time is in the float stages, which this milestone does not change.
  • Also green:
    • wai-ops cargo test --locked, debug and release, and the fast-kernel steps of wai-conformance.yml in release.
    • The wai-verify build and its tests, and wai-verify vectors verify (every file verifies).
    • tools/wai_ops_check.py ops-conformance: every file rewritten byte for byte.
    • The pinned bundle's certificate 3e243dc1… at acc32, recomputed by both certifiers (wai-verify bounds --check and wai_ops_check.py certify --check).
    • wai-ops' jpegai_scale_path_on_a_supplied_bundle, and wai registry export --check.
    • check-lockfiles.sh.
    • Each integer feature alone (cargo check --lib). Each gives one dead-code warning, int_payload::unpinned_read without neural; main gives the same warning, and this branch does not touch that file.
    • wai-web: the native tests (32) and the wasm32 tests (4).
    • The node checks: int synth, payload, world and staged.
    • The browser crate's decodeJpegAiMans on the site's reference vector: 172 coded symbols, 0 mismatched, the native hash. A cut stream throws stream_exhausted.
    • No build changed a tracked file; include/wai.h is as committed.
  • Local checks: comparative prose, vanity metrics, public names, section refs, tests in CI and orphan sources are all clean.

Kani, under a memory budget

Every K27 totality harness ran under memguard with a memory budget, not only a time budget, and each was stopped at its budget:

  • The two existing kani_open harnesses (16-byte streams, a span or a row of up to 5 positions): each passed a 48 GB budget, peaking at 76 GB and 91 GB resident.
  • One harness over a 10-byte stream with a span and a row of 3 (62768898): it passed a 40 GB budget, peaking at 57 GB.
  • A latent harness and a hyper-latent harness over 8-byte streams, 2 positions each (0fba6461): each was still running past 25 minutes and 24 GB.

Run in the stage shard, any of them would take its runner's memory. So they are withdrawn (3bc90f02), and K27's totality harnesses stay kani_open as on main. k27_mans_bounds_are_unsigned and k28_mans_entry_fields verify.

Decisions

  • The profile is acc32. Both certified bundles' scale graphs meet it, and so the capability declares it: every conforming bundle's scale path then runs on a 32-bit fabric as on a 64-bit one (D3b's first target). A bundle that meets only acc64 is a planned break.
  • O9. A refusal of the exact decode is reported with its code and does not fall back; determinism-tiers §5 now says so and names both codes. The documented fallback stays only for a sink without the bundle or a thread or target the float stages cannot run in.
  • K27. The decode is total by construction: every read, refill and index is checked, every new state is a byte (% 256 into a u8), and B_y is unsigned (refused outside [0, 255] before any symbol). It is exercised by the cut-at-every-length tests on two bundles and by the differential, where every stream the operator set refuses is one the direct port panics on, and no case panics through the operator set. The model checker could not prove totality within a memory budget at any window tried (see Kani above); the totality harnesses stay kani_open, and k27_mans_bounds_are_unsigned and k28_mans_entry_fields verify.
  • O10. The duplicates are deleted, not proven equal: the float path runs the shared driver.
  • The loaded-set store fits the sink: the scale path is lowered from three members' bytes, keyed by their listing digest. The parsed-bundle path (jpegai_decode::load) follows the *_net_loaded pattern (lower::jpegai_net_loaded). The store keeps only the scale path: the other networks are parsed by the float stages' loaders, which this milestone does not lower.
  • The ONNX-path bundle's RVS tables (4352-entry lookups) are no longer read for σ; band_lookup with the corrected edges gives the same values at every index.

Left for M7b and M8

  • M7b (waits for O8): ψ, the four context stages and the synthesis, with check ranges at the float boundaries. The float stages' weight loaders still panic on a mistyped member (Weights::from_json, IntNet::from_json, IcciNet::from_json).
  • K27 at a window a CI shard can hold needs a cheaper harness (for example a window over a fixed-size array rather than the heap copy Win::init makes).
  • The reference-decoder stage fixtures are rebuilt only by a scratch script; a committed builder (or committing the fixtures, licence permitting) would let a job run jpegai_e2e_frontend, jpegai_e2e_chroma and jpegai_hyperscale_calibration.
  • M8, WIV1 and WIR1 (stage operators only).
  • Nothing is deployed. The site's /jpegai page calls decodeJpegAiMans and decodeJpegAiFull; it picks up the change (a refusal now throws) with its next wasm build.

Notes

  • The build host rebooted once at about 10:02 on 2026-10-16, while a build of this branch was compiling (no test of mine was running), and was unreachable twice under other sessions' load (load average 130 to 180). Runs were repeated.
  • Two session limits stopped the work; on each resume the worktree held only a falsification fault in flight, which was rerun and restored.
  • No cargo fmt, no git stash, no cargo output piped into head or tail. include/wai.h is unchanged: the new constants are crate-only (an early build put four of them and an opaque Profile in the header; not kept).
  • No write or command was refused by the permission system.

🤖 Generated with Claude Code


Closed: landed in main through #308 (wai/d2c-m8), which contains this branch's head a6cd06d7 unchanged; 3bc90f02 was green on its own (80), and #308 was green with both (103 passed, 38 skipped).

D2c M7a: `wai.image.jpegai`'s scale path and its two entropy decodes run through the integer operator set `wai-ops/1`, lowered by `jpegai-int/1` ([integer-operators](wai/extensions/integer-operators.md) §13.6.1), on both reference decode paths. Every committed and pinned golden is unchanged. Not stacked: #274 (M6, this branch's base) merged as 80477972. `origin/main` is merged in (last at bea79dc6); CHANGELOG keeps both sides, this branch's section first. ## What changes - **The lowering, from the bundle a decoder holds.** `wai-ops` gains `lower::parse_jpegai` (the members of `norm.json` and Table 13.6-A, typed), `lower::jpegai_net` and `lower::jpegai_net_loaded` (the same lowering of a bundle already parsed, the last loading both scale graphs without writing and parsing them again), `lower::jpegai::scale` (one plane's graph) and `stage::mans::decode_sgm_tables` (E8 with its latent tables built once). `lower::jpegai` is now parse, then lower. The committed graphs and certificates are unchanged. - **The driver** (`wai-rs/src/jpegai_ops.rs`, new). `load` / `load_bytes` give a `ScalePath`: §13.6.1's load checks, the two scale graphs loaded under `acc32`, the latent tables, the hyper-latent rows and the gains. `plane` decodes one plane's integers as §13.6.1 steps 1 to 4 give them: a fresh `fac` decode over SOZ (for chroma, the 160 luma rows first, decoded with luma's rows and discarded), the scale graph, `coded`, `block_stat`, `band_lookup`, `scale_index`, then a fresh `sgm` decode over SORP or SORS. It refuses with the operator set's codes and never panics on a stream. - **The switch.** `jpegai_decode::{decode, decode_with_stages}` run the scale path and the entropy decodes through the driver, and return `Result<Rgb, Refusal>` (`Refusal::Scope` with `check_scope`'s reason, or `Refusal::Ops` with `model_mismatch` or `stream_exhausted`). `jpegai_decode::{load, decode_loaded}` decode with a scale path loaded once. `NormTables`' bounds and CDF rows are `i64`, so a load check sees the value the file gives, not a byte it wrapped to. - **The direct path, test-only** (`legacy_int`): `jpegai_decode::legacy`, `jpegai_ops::legacy`, and the pieces they run: the crate-root mANS port, `jpegai_synthesis::decode_hyper_scale` and the pipeline's `skip_mask`, `rvs_additive`, `rvs_likely` and `sigma_index`. The calibration tests that read them require `legacy_int`. - **The duplicates retire (O10).** `neural/jpegai_hyper.rs` and `neural/jpegai_mans.rs` are deleted. The float decode path (`neural::jpegai`) builds a `ScalePath` from its own bundle's members (the normative PMFs and bounds, the factorized CDFs, the gains, the scale network in its `blocks` form, `jpegai_ops::scale_net_of_blocks`) and decodes each plane through the same `jpegai_ops::plane`. A bundle whose hyper-latent offsets are not 31, or that fails a load check, is refused. - **No silent fallback (O9).** The neural sink lowers and loads the scale path from the members' bytes through the store of loaded sets (`int_set_cache`, keyed by the listing of `norm.json`, `weights/hs_y.json` and `weights/hs_uv.json`; `ScalePath` is `Resident`). A refusal of the exact decode is the decode's result: `model_mismatch`, `stream_exhausted`, or `set_incomplete` for a member the set lacks. Only a sink without the bundle (no `norm.json`), or a thread or target that cannot run the float stages (`check_scope`), takes the float path. - **The browser crate.** `decodeJpegAiMans` decodes through E8 (`jpegai_ops::latent_span`) and throws on a refusal; `decodeJpegAiFull` reports the decode's refusal. The site's reference vector gives the same symbols and hash. - **Registry:** `wai.image.jpegai` gains the `ops` member `{ wai-ops/1, acc32, full, jpegai-int/1 }` (no stage modes: E8 and the scale path's stage operators have none). `registry/capabilities.json` regenerated. - **Text:** integer-operators (the status note; §13.6.1 step 3's band edges; §15.3 item 4), determinism-tiers §5 (both codes; both paths decode the claim's stages through the operator set at `acc32`; a sink that holds the bundle reports the exact decode's refusal and does not fall back), SPEC §5's row, SPEC §7's `NeuralEntropyExact` entry, SPEC §8's planned breaks, CHANGELOG. - **CI:** `tests/jpegai_ops.rs` in both fast-kernel steps of `wai-conformance.yml` (its pinned-bundle cases skip there); `wai-jpegai-e2e.yml` runs `jpegai_ops` and `jpegai_memory` on the fetched bundle with `WAI_REQUIRE_SOTA_VECTORS=1`, requiring every test by name and no skip banner, and fires on the files they read; the nightly differential names the jpegai half. ## A defect found: the residual-variance band edges The exact decoder, and §13.6.1 step 3 transcribed from it, put a block whose `likely` was exactly 1003, 1352 or 1937 in the next band, for its σ addition and for its dequantisation multiplier. The reference decoder's own tables (4352 entries per branch, indexed by `likely`; the 18 tables dumped from the reference decoder, and the ones the float path reads) change value at 1004, 1353 and 1938 in both branches and for both the addition and the dequant. The edges are now 1004, 1353 and 1938 in the decoder and in §13.6.1, and §15.3 item 4 records it. `jpegai_rvs_bands_are_the_reference_tables` holds both branches' additions and multipliers to the reference's tables at every index. On `test256.bin` no block's `likely` lies within 2 of an edge (the reference's own `likely`, luma 0 to 1357, chroma 0 to 908, equals the decoder's), so no output changes; the two reference decode paths disagreed on codestreams that have such a block. The exact decoder's comment that "one block lands exactly on edge 1352" did not hold for the reference decoder's `likely`. ## Planned breaks (integer-operators §15.3 item 4, SPEC §8) On both reference decode paths, refused before the streams where the decoder decoded or panicked: - a bundle that fails a load check of §13.6.1 (`model_mismatch`), among them a bound above 255 or a shift outside `0..=127`, which the loader wrapped; - a bundle whose scale graphs do not meet `acc32`, the capability's profile: a sum past `i32`, or a shift past 63 (`model_mismatch`). acc32 holds every shift to at most 63 (§7.1), so a shift of 64 to 127 is this refusal; - a latent or hyper-latent substream that ends before the decode it carries (`stream_exhausted`), where the decoder panicked. The codestream's scope is checked first, then the bundle, then the streams. No committed bundle or codestream is affected (the committed synthetic bundle and the pinned `jpegai/v1` load under `acc32`, and every committed and pinned decode is unchanged). ## Gates, each red once and restored | gate | commits | falsification | red | |---|---|---|---| | band edges | `18646564` | the edges back to 1003, 1352, 1937 | `jpegai_mans_golden`: "σ addition, flag false, likely 1003" (−31); the pinned decode stays green | | 1 lowering and certificates | `2778f166` | the conversion reads the depthwise block's shifts from conv1's member | `jpegai_ops`, both tests: "the converted bundle is the one wai-ops parses from the bytes" | | 2 golden equality | `a6875276`, `9d8cad8e` | chroma's `fac` decode skips the 160 luma rows' reads (Part 3.5) | `jpegai_ops` 2 of 4 (`Refusal { StreamExhausted, Symbol(711) }`; the whole decode `Ops(StreamExhausted)`), `jpegai_e2e_chroma` (the same); the file-based goldens stay green (the switch is gate 6) | | 2 | | `B_y` read as signed in E8 (Part 3.5) | every M7a golden stays green: no reference stream decodes an escape at a distribution whose bound is 128 or more, so the prediction that `jpegai_mans_golden` carries this row is corrected. Red: `wai-verify vectors verify`, `stage/mans_decode.jsonl` line 12 (a vector with a bound of 128) | | 3 refusal parity, `ops` member | `d709a776`, `aff9584c`, `4ac4c3e7` | the bounds load check admits 256 | `jpegai_ops`: "bounds: one of 256: the load from bytes accepts it" | | 4 differential | `758d36d5`, `35f3d9a2`, `ffba2989`, `efc71269` | a shift of 32 to 63 read mod 32 in the conversion (only random bundles reach it) | gates 1 to 3 and the stage tests green; the differential red, "Luma: the two decodes differ", seed 7073408957376268560. A first version of this fault (every shift mod 32) also reddened gate 3's fixture, a shift of 128 read as 0 | | 5 fast kernels | `ffba2989`, `0e456c9a` | channel-0 requantisation on the fast path | `jpegai_ops::fast_kernels` and 5 other `int_ops` equivalence tests; `jpegai_ops::every_kernel_policy_decodes_the_planes_alike`: "jpegai/v1 Luma: Policy { path: Fast, threads: 1 } differs from the interpreter alone" | | 6 the switch | `5bd789bf`, `0e456c9a`, `fe0c6e20`, `25013a85`, `b8710703` | `rq` floor → half_up in `jpegai-int/1`'s convolutions | now the file-based goldens: `jpegai_cross_platform`, `jpegai_e2e_chroma`, `jpegai_hyperscale_calibration` (luma 8263/40960 exact, max\|Δ\| = 172; chroma 8/24576, 80), and the committed graphs | | 6 memory | | a plane holds every mask and `σ_idx` twice while its latent decodes | `jpegai_memory`: "Luma: the front half through the operator set held 2666864 bytes; directly, 2218884" | | 7 delete | `8386f0f4`, `15f0a282` | the test-only direct mANS port refills its window to 48 bits | production green (the CI trio, byte-exact's E8 golden); the comparisons red: `jpegai_ops` 4 of 9, byte-exact's direct-port golden, the differential (seed 10208061212434326836) | The other commits: `1d53d003` (the CHANGELOG names the retired duplicates); `62768898` and `0fba6461` (narrower K27 harnesses, withdrawn in `3bc90f02`, see Kani below); and the merges of `origin/main`, `7c4c4bd3`, `c329f46d` and `b9afc889`. A memory fault placed in the decode's shared back half (the latents held through synthesis) stayed green, as it should: it moves both decodes alike. The fault above is the one the test is for. ## Pinned inputs: what ran, with no skip - **`jpegai/v1`** was fetched on the build host with `tools/wai_jpegai_fetch_e2e_inputs.sh`, every file checked against `tools/jpegai-e2e-v1.sha256`, as `wai-jpegai-e2e.yml` does, and every pinned-input test ran with `WAI_REQUIRE_SOTA_VECTORS=1`. - **The reference-decoder stage fixtures** the NOT-IN-CI tests read (`WAI_JPEGAI_FRONTEND_FIXTURE`, `WAI_JPEGAI_HYPERSCALE_IO`) no longer existed anywhere. They were rebuilt on the build host from the local reference assets' dumps (the reference decoder's entropy calls, scale, LSBS and synthesis dumps) and `jpegai/v1`'s `norm.json`, by a scratch script, and checked first against the unchanged tests at this branch's base, where `jpegai_e2e_frontend`, `jpegai_e2e_chroma` and `jpegai_hyperscale_calibration` (both planes) passed with the figures their comments record. The assets root was copied to the build host for `jpegai_mans_golden` and the float path's tests. - **Ran, every case checking its input:** `jpegai_e2e_full`, `jpegai_reconstruction_binding` (the pinned pixel hash), `jpegai_cross_platform` (all 9 hashes), `jpegai_ops` (9), `jpegai_memory`, `jpegai_e2e_frontend`, `jpegai_e2e_chroma`, `jpegai_hyperscale_calibration` (luma and chroma), `jpegai_mans_golden` (12), the neural dispatch tests (3), the float path's `jpegai_e2e`, `jpegai_live` and `jpegai_scope_ort`, byte-exact `jpegai_golden`, and wai-ops' `jpegai_scale_path_on_a_supplied_bundle` and `mans_matches_reference_encoder_streams`. ## Results on the merged head All on the build host, at `3bc90f02` (main merged in at `bea79dc6`). - **`gate.sh d2c-m7a-merged`: GREEN.** The build, the lib tests, carriage, the corpus loop (21 of 21), the fast kernels, byte-exact, wai-web wasm32 and the neural gates all passed. - **The M7a goldens, unchanged:** - `jpegai_hyperscale_calibration`: luma 40960/40960 and chroma 24576/24576 exact, max|Δ| = 0. - `jpegai_mans_golden`: 12 of 12. - byte-exact `jpegai_golden`: E8 and the direct port both decode the reference stream. - `jpegai_e2e_chroma`: U and V max|Δ| = 1, 4426/131072 differ, as before. - `jpegai_e2e_frontend`: Y from the codestream 916/65536, from the reference latent 788/65536, as before. - `jpegai_cross_platform`: every hash; against the reference PNG max|Δ| = 1, 8742/196608 differ, as before. - `jpegai_reconstruction_binding` and `jpegai_e2e_full` pass on the pinned pixel hash. - **The differential** (`int_ops_differential`, the jpegai half; each case decodes two planes, and a planned break is counted per case): - The per-push run: 1500 cases, seed 3372. Planes decoded alike: 226. Refused where the direct decode panicked: 2194. Refused where the unchecked build computed on: 0. Breaks: acc32 55, bounds 27, cdfs 36, dims 51, gains 24, per_channel 16, pmf 34, shift 47. - Timed, 300 s, seed 20261016, release: 29,656 cases. Alike 5,091, refused 42,893, computed on 0. Breaks: acc32 830, bounds 502, cdfs 918, dims 818, gains 460, per_channel 445, pmf 942, shift 749. - The same in debug, where overflow checks make the direct decode panic exactly where E8 refuses: 1,229 cases. Alike 195, refused 1,767, computed on 0. Breaks: acc32 32, bounds 26, cdfs 52, dims 36, gains 22, per_channel 20, pmf 29, shift 31. - No case panicked through the operator set. - **Memory** (`jpegai_memory`: the heap's peak during the call, `jpegai/v1`, reference kernels): - The whole decode holds 175,465,380 bytes directly, and the same 175,465,380 through the operator set with the scale path loaded beforehand. The peak is in the shared back half. - Loading the scale path takes 14,083,663 bytes while it runs and holds 7,557,178 afterwards. Loading and decoding in one call holds 183,012,574. - The front half, which is what this milestone changes: luma holds 2,114,160 bytes through the operator set against 2,218,884 directly; chroma holds 1,290,864 against 1,357,586. - **Timings.** Release builds, 3 rounds, each figure the mean with the minimum in brackets. The host was carrying other sessions' load (load average about 120 to 130), so treat these as rough. - Loading the scale path: 3.2 to 5.2 ms from the parsed bundle (2.7), 74 to 89 ms from the members' bytes (58). - The luma front half: 6.4 to 12.2 ms through the operator set (3.8), 28 to 36 ms directly (21). - The chroma front half: 2.9 to 4.5 ms (2.0), 10 to 11 ms directly (6.9). - The whole decode: 2.0 to 2.5 s by either path, within the host's noise. Its time is in the float stages, which this milestone does not change. - **Also green:** - wai-ops `cargo test --locked`, debug and release, and the fast-kernel steps of `wai-conformance.yml` in release. - The wai-verify build and its tests, and `wai-verify vectors verify` (every file verifies). - `tools/wai_ops_check.py ops-conformance`: every file rewritten byte for byte. - The pinned bundle's certificate `3e243dc1…` at acc32, recomputed by both certifiers (`wai-verify bounds --check` and `wai_ops_check.py certify --check`). - wai-ops' `jpegai_scale_path_on_a_supplied_bundle`, and `wai registry export --check`. - `check-lockfiles.sh`. - Each integer feature alone (`cargo check --lib`). Each gives one dead-code warning, `int_payload::unpinned_read` without `neural`; main gives the same warning, and this branch does not touch that file. - wai-web: the native tests (32) and the wasm32 tests (4). - The node checks: int synth, payload, world and staged. - The browser crate's `decodeJpegAiMans` on the site's reference vector: 172 coded symbols, 0 mismatched, the native hash. A cut stream throws `stream_exhausted`. - No build changed a tracked file; `include/wai.h` is as committed. - **Local checks:** comparative prose, vanity metrics, public names, section refs, tests in CI and orphan sources are all clean. ## Kani, under a memory budget Every K27 totality harness ran under memguard with a memory budget, not only a time budget, and each was stopped at its budget: - **The two existing `kani_open` harnesses** (16-byte streams, a span or a row of up to 5 positions): each passed a 48 GB budget, peaking at 76 GB and 91 GB resident. - **One harness over a 10-byte stream** with a span and a row of 3 (`62768898`): it passed a 40 GB budget, peaking at 57 GB. - **A latent harness and a hyper-latent harness over 8-byte streams**, 2 positions each (`0fba6461`): each was still running past 25 minutes and 24 GB. Run in the stage shard, any of them would take its runner's memory. So they are withdrawn (`3bc90f02`), and K27's totality harnesses stay `kani_open` as on main. `k27_mans_bounds_are_unsigned` and `k28_mans_entry_fields` verify. ## Decisions - **The profile is `acc32`.** Both certified bundles' scale graphs meet it, and so the capability declares it: every conforming bundle's scale path then runs on a 32-bit fabric as on a 64-bit one (D3b's first target). A bundle that meets only `acc64` is a planned break. - **O9.** A refusal of the exact decode is reported with its code and does not fall back; determinism-tiers §5 now says so and names both codes. The documented fallback stays only for a sink without the bundle or a thread or target the float stages cannot run in. - **K27.** The decode is total by construction: every read, refill and index is checked, every new state is a byte (`% 256` into a `u8`), and `B_y` is unsigned (refused outside `[0, 255]` before any symbol). It is exercised by the cut-at-every-length tests on two bundles and by the differential, where every stream the operator set refuses is one the direct port panics on, and no case panics through the operator set. The model checker could not prove totality within a memory budget at any window tried (see Kani above); the totality harnesses stay `kani_open`, and `k27_mans_bounds_are_unsigned` and `k28_mans_entry_fields` verify. - **O10.** The duplicates are deleted, not proven equal: the float path runs the shared driver. - **The loaded-set store fits** the sink: the scale path is lowered from three members' bytes, keyed by their listing digest. The parsed-bundle path (`jpegai_decode::load`) follows the `*_net_loaded` pattern (`lower::jpegai_net_loaded`). The store keeps only the scale path: the other networks are parsed by the float stages' loaders, which this milestone does not lower. - **The ONNX-path bundle's RVS tables** (4352-entry lookups) are no longer read for σ; `band_lookup` with the corrected edges gives the same values at every index. ## Left for M7b and M8 - **M7b** (waits for O8): ψ, the four context stages and the synthesis, with `check` ranges at the float boundaries. The float stages' weight loaders still panic on a mistyped member (`Weights::from_json`, `IntNet::from_json`, `IcciNet::from_json`). - **K27** at a window a CI shard can hold needs a cheaper harness (for example a window over a fixed-size array rather than the heap copy `Win::init` makes). - **The reference-decoder stage fixtures** are rebuilt only by a scratch script; a committed builder (or committing the fixtures, licence permitting) would let a job run `jpegai_e2e_frontend`, `jpegai_e2e_chroma` and `jpegai_hyperscale_calibration`. - **M8**, `WIV1` and `WIR1` (stage operators only). - Nothing is deployed. The site's `/jpegai` page calls `decodeJpegAiMans` and `decodeJpegAiFull`; it picks up the change (a refusal now throws) with its next wasm build. ## Notes - The build host rebooted once at about 10:02 on 2026-10-16, while a build of this branch was compiling (no test of mine was running), and was unreachable twice under other sessions' load (load average 130 to 180). Runs were repeated. - Two session limits stopped the work; on each resume the worktree held only a falsification fault in flight, which was rerun and restored. - No `cargo fmt`, no `git stash`, no cargo output piped into `head` or `tail`. `include/wai.h` is unchanged: the new constants are crate-only (an early build put four of them and an opaque `Profile` in the header; not kept). - No write or command was refused by the permission system. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- **Closed:** landed in main through #308 (wai/d2c-m8), which contains this branch's head a6cd06d7 unchanged; 3bc90f02 was green on its own (80), and #308 was green with both (103 passed, 38 skipped).
The exact decoder (and integer-operators §13.6.1 step 3, transcribed from it) put a
block whose likely was exactly 1003, 1352 or 1937 in the next band, for its σ addition
and its dequantisation multiplier. The reference decoder's own residual-variance tables
(4352 entries per branch, indexed by likely; dumped from the reference decoder, and the
tables the float decode path reads) change value at 1004, 1353 and 1938. The edges are
now 1004, 1353 and 1938 in jpegai_pipeline and in §13.6.1; §15.3 item 4 records it.

tests/jpegai_mans_golden.rs gains jpegai_rvs_bands_are_the_reference_tables: for every
likely and both branches, the band the edges give selects the reference's σ addition and
dequant multiplier. On test256.bin no block's likely is within 2 of an edge (the
reference's likely, luma 0..1357 and chroma 0..908), so no output changes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-ops: lower::jpegai is now parse_jpegai (the members of norm.json and Table 13.6-A,
typed) followed by the lowering, and gains lower::jpegai_net and jpegai_net_loaded, the
same lowering of a bundle already parsed, loaded under a profile without writing and
parsing the graphs again; stage::mans::decode_sgm_tables decodes with latent tables
built once. tests/goldens.rs holds the parsed path to the bytes path.

wai-rs: jpegai_ops (new) converts the bundle this crate parses (NormTables, IntNet) to
wai-ops' form and loads the scale path under acc32 (ScalePath: the two graphs, the latent
tables, the rows and the gains), and decodes one plane through §13.6.1 steps 1-4 (plane);
jpegai_ops::legacy is the front half as jpegai_decode computes it, test-only.
NormTables' bounds and CDF rows are i64, so the load checks see what the file says
rather than a value wrapped to a byte. tests/jpegai_ops.rs: the committed synthetic
bundle and the pinned jpegai/v1 bundle lower, from their bytes and from the parsed form,
to the committed certificates' graphs, and load under acc32. Named in wai-conformance's
fast-kernels steps and in wai-jpegai-e2e.yml (pinned bundle, missing input = failure).

Results (build host, release): wai-ops goldens 7 passed (the parsed lowering test on the
committed set and on the pinned jpegai/v1 bundle); tests/jpegai_ops.rs 2 passed, no skip,
jpegai/v1 at 3e243dc1 meeting acc32; jpegai_mans_golden 12 passed; the pinned whole
decode (jpegai_e2e_full, jpegai_reconstruction_binding, jpegai_cross_platform: 9 stage
hashes and WAI_JPEGAI_EXPECT_SHA256) unchanged; frontend and chroma stage tests green.

Falsified: the conversion reads the depthwise block's shifts from conv1's member.
Red: jpegai_ops EXIT=101, both tests at "the converted bundle is the one wai-ops parses
from the bytes". Restored with git: green above.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
jpegai_decode: each plane's integers come from a front half, the direct computation
(jpegai_ops::legacy, still the production decode until the switch) or the integer
operator set (jpegai_ops::plane, from the bundle's loaded ScalePath). jpegai_decode::ops
decodes through the operator set: the codestream's scope, then the scale path lowered
and loaded under acc32, then the decode; it refuses with the operator set's codes
(Refusal::Ops). LEF's sigma is v + rvs, which is i_s + gain + rvs.

jpegai_ops: PlaneSetup and plane_with (one plane from its graph, rows, tables and
bounds); scale_net_of_blocks (the float path's bundle form of the same network);
load_scale and fac_rows for one plane. wai-ops: lower::jpegai::scale, one plane's graph.

Goldens through the lowering: tests/jpegai_ops.rs (the planes' integers and the whole
decode, stage by stage, against the direct decode, and the pinned RGB hash);
jpegai_hyperscale_calibration (the scale graph, max|Δ| = 0); jpegai_mans_golden (E8's
tables, the reference encoder's streams, the 258-call replay, the scale graph on both
planes, the sigma chain); byte-exact jpegai_golden (E8 on the reference stream);
jpegai_e2e_frontend and jpegai_e2e_chroma (steps 1-4, the chroma plane discarding the 160
luma rows).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The compile fix of the gate's WIP commit (a payload helper with two borrowed inputs
needs its lifetime named), and gate 2's results.

Results (build host, release; pinned jpegai/v1 inputs fetched and checked against
tools/jpegai-e2e-v1.sha256; the reference-decoder stage fixtures rebuilt from the local
assets' dumps and checked by the unchanged tests first):
- tests/jpegai_ops.rs 4 passed, no skip: both planes' z, v, mask, likely, rvs, σ_idx
  and y_q through the lowering equal the direct computation's; the whole decode through
  the operator set equals the direct decode at all 7 stages and matches
  WAI_JPEGAI_EXPECT_SHA256.
- jpegai_hyperscale_calibration, luma and chroma: the scale graph (acc32) vs the
  reference I_s, 40960/40960 and 24576/24576 exact, max|Δ| = 0.
- jpegai_mans_golden 12 passed: E8's tables (4 golden, 32 normative), the reference
  encoder's sgm and fac streams, codestream → E8, the 258-call replay, the scale graph on
  both planes, the sigma chain through the stage operators.
- byte-exact jpegai_golden 3 passed (E8 on the reference stream).
- jpegai_e2e_frontend and jpegai_e2e_chroma: y_q through the operator set 40960/40960
  and 24576/24576 exact; every later stage as before (U,V 3.377%, Y 1.398% at 1 LSB).
- The file-based goldens (jpegai_e2e_full, jpegai_reconstruction_binding,
  jpegai_cross_platform's 9 hashes) unchanged; wai-ops 35 + 7 + 3 + 4 + 2 + 1 + 1 tests.

Falsified (Part 3.5):
- Chroma's fac decode skips the 160 luma rows' reads (a fresh decoder over only its own
  96 rows). Red: jpegai_ops 2 of 4 (the planes test, Refusal { StreamExhausted,
  Symbol(711) }; the whole decode, Ops(StreamExhausted)), jpegai_e2e_chroma (the same
  refusal). The file-based goldens stay green: the switch is gate 6. Restored: green.
- B_y read as signed in E8. Every M7a golden stays green: no reference stream decodes an
  escape at a distribution whose bound is 128 or more, so the prediction that
  jpegai_mans_golden carries this row is corrected. Red: wai-verify vectors verify,
  stage/mans_decode.jsonl line 12 (a vector with a bound of 128). Restored: green.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The registry gains wai.image.jpegai's ops member: wai-ops/1, acc32, full, jpegai-int/1
(no stage modes: mANS and the scale path's stage operators have none). Its registry test
holds it, beside the NeuralIntegerExact capabilities' acc64 members. SPEC §5's row cites
integer-operators §13.6.1 and jpegai_ops.rs; SPEC §7's NeuralEntropyExact entry says
the stages its class covers decode through the operator set at acc32.

tests/jpegai_ops.rs: every load check of §13.6.1 broken one change at a time (and a sum
past i32 that meets acc64), refused model_mismatch from the members' bytes and from the
parsed bundle; the three entropy payloads cut at every length, on the committed bundle
and on the pinned one: decoded alike, or refused stream_exhausted where the direct decode
panics (with overflow checks; without them it may compute on, counted); a codestream
out of scope refused with check_scope's reason, before the bundle's checks.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
registry/capabilities.json regenerated (wai registry export): wai.image.jpegai's ops
member. The stage constants (the coded threshold, the hyper-latent offset, the RVS edges
and additions) and the profile are crate-only, so cbindgen does not put them in
include/wai.h; jpegai_ops::stage_constants gives the first three to tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
On the committed bundle every cut stream runs out (its tables are not the ones the test
codestream was coded with), so the test had no case decoded alike. Payloads lengthened at
their front (16, 256, 4096 bytes) decode further before they run out.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
origin/main at a76522da: #274 (M6, this branch's base) merged as 80477972, and #262, #272,
#276 and #277, none of which touches wai/.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
tests/int_ops_differential.rs gains the jpegai half: random bundles (pmf rows of widths 1
to 64, bounds among 0, 1, 2, 4, 30, 127, 128, 200 and 255, CDF rows, gains that put most,
some or no positions coded, scale networks of 1 to 3 channels between blocks, with
shifts up to 40 and, rarely, weights of 2^20, shifts of 64 to 128 or wrong dims) and
random or damaged payloads (the committed codestream's, cut, lengthened at the front,
bit-flipped, or random bytes). Outside the planned breaks, both planes' integers equal
the direct computation's, or the stream is refused (stream_exhausted) where the direct
computation panics with overflow checks on; a planned break (a load check, acc64 but
not acc32, or a shift of 64 to 127 that now has its exact meaning) is classified from
the members alone, and refused from the bytes and from the parsed bundle alike. The
nightly workflow's header names it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The first per-push run reached no decodable case: a shift of 128 drawn per element
(1 in 64, over 2,560 elements) put nearly every bundle under a load check. One network
in about eight now has one shift of 31 to 40 per block, and one in 64 a shift of 64 to
127 or of 128.

Gate 5 (WIP, committed before running): int_ops' equivalence tests run the committed
bundle's scale graphs on the fast kernels under every fast policy (three convolutions
each, every value the interpreter's, z over [-31, 32]); tests/jpegai_ops.rs holds both
planes' integers to the reference policy under every fast policy, on the committed and
the pinned bundle, payloads whole and cut.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
acc32 holds every shift to at most 63 (integer-operators §7.1), so a bundle with a shift
of 64 to 127 is refused at load under the capability's profile; the classifier's acc32
kind covers it. The first release run: 1,500 cases, planes decoded alike 226, refused
where the direct decode panicked 2,194, computed on 0; breaks acc32 55, bounds 27, cdfs
36, dims 51, gains 24, per_channel 16, pmf 34, shift (128) 47.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
jpegai_decode::{decode, decode_with_stages} decode through the integer operator set and
return Result<Rgb, Refusal>; load and decode_loaded run a scale path loaded once. The
direct decode is jpegai_decode::legacy and jpegai_ops::legacy, test-only (legacy_int).

The neural sink's exact path lowers and loads the scale path from the members' bytes
through the store of loaded sets (int_set_cache, keyed by the listing of norm.json and
weights/hs_{y,uv}.json); a refusal of the exact decode (model_mismatch, stream_exhausted,
or set_incomplete for a member the set lacks) is the decode's result and does not fall
back to the float decode (O9). Only an absent bundle, or a target or floating-point
environment the float stages cannot run in, takes the float decode.

The float decode path (neural::jpegai) runs its scale path and entropy decodes through
the same driver (jpegai_ops::plane, O10), from its own bundle's members; one whose
hyper-latent offsets are not 31, or that fails a load check, is refused.

The browser crate's decodeJpegAiMans decodes through E8 (jpegai_ops::latent_span) and
throws on a refusal; decodeJpegAiFull reports the decode's refusal.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The byte-equality crate includes int_ops.rs without jpegai_ops, so the scale path's
fast-kernel test moves into jpegai_ops' own test module. tests/jpegai_memory.rs (own
binary, a live-bytes allocator, the pinned bundle): with the scale path loaded
beforehand, the decode through the operator set holds no more than the direct decode;
named in wai-jpegai-e2e.yml.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
integer-operators: the status note names jpegai's scale path and entropy decodes;
§15.3 item 4 adds the acc32 refusal, the order (scope, bundle, streams) and that a
refusal is not replaced by the float path. determinism-tiers §5: both paths decode the
claim's stages through the operator set at acc32; the two codes; a sink holding the
bundle reports the exact decode's refusal and does not fall back (O9). SPEC §5's row and
§8's planned breaks; the capability constant's comment; CHANGELOG.

tests/jpegai_memory.rs also reports each plane's front half through the operator set
and directly. First run (before this): the direct decode held 175,465,380 bytes; with
the scale path loaded beforehand (14,083,663 bytes to load, 7,557,178 held) the decode
through the operator set held 175,465,380; loading and decoding in one call 183,012,574.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The front half held about 10% more than the direct computation (luma 2,445,680 bytes
against 2,218,884; chroma 1,489,776 against 1,357,586): every mask and σ_idx was held
twice while the latent decoded, once as the plane's and once in its span. They are now
formed into each channel's span and taken back after the decode.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Results (build host, release, pinned jpegai/v1 inputs, no skip):
- tests/jpegai_ops.rs 9 passed (the whole decode through the operator set equals the
  direct decode at all 7 stages and WAI_JPEGAI_EXPECT_SHA256; the stream parity on the
  committed bundle 4 alike / 326 refused where the direct decode panicked, on jpegai/v1
  39 / 291; every kernel policy alike).
- The file-based goldens, now through the operator set: jpegai_e2e_full,
  jpegai_reconstruction_binding (the pinned pixel hash), jpegai_cross_platform (all 9
  hashes), jpegai_e2e_frontend and jpegai_e2e_chroma, jpegai_hyperscale_calibration on
  both planes (max|Δ| = 0), jpegai_mans_golden 13, byte-exact jpegai_golden 3.
- The neural dispatch: the exact bundle decodes; an absent bundle takes the float path;
  a bound of 256 is reported as model_mismatch and does not fall back; a missing member
  is set_incomplete.
- The float path through the shared driver: jpegai_e2e and jpegai_live 5/196608 samples
  at 1 LSB, as before; jpegai_scope_ort green.
- Memory (reference kernels): the direct decode held 175,465,380 bytes; with the scale
  path loaded beforehand (14,083,663 bytes to load, 7,557,178 held) the decode through
  the operator set held 175,465,380. Each plane's front half alone: luma 2,114,160
  against 2,218,884 directly, chroma 1,290,864 against 1,357,586. The test now asserts
  both.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The duplicate ports neural/jpegai_hyper.rs and neural/jpegai_mans.rs, which the float
decode path ran its front half with, are deleted (O10): that path runs the shared
driver since the switch. The direct pieces of the exact decoder leave production,
test-only (legacy_int): the crate-root mANS port (jpegai_mans), the hyper-scale network
(jpegai_synthesis::decode_hyper_scale and its convolution) and the pipeline's
skip_mask, rvs_additive, rvs_likely and sigma_index. The calibration tests that read
them require legacy_int.

jpegai_mans_golden runs on E8 and the scale graph alone; jpegai_e2e (the float chain
against the reference PNG) takes its front half from the driver, still checking the
dumped RVS additions, masks and residuals; the byte-equality crate drops the neural
port and keeps E8 and the direct port.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Results (build host, release, pinned inputs, no skip): tests/jpegai_ops.rs 9 passed;
the CI trio (jpegai_e2e_full, jpegai_reconstruction_binding, jpegai_cross_platform:
all 9 hashes and WAI_JPEGAI_EXPECT_SHA256); jpegai_e2e_frontend and jpegai_e2e_chroma;
jpegai_hyperscale_calibration on both planes (max|Δ| = 0); jpegai_mans_golden 12 passed
on E8 alone; the neural dispatch 3; the float path (jpegai_e2e, jpegai_live 5/196608 at
1 LSB, jpegai_scope_ort); byte-exact jpegai_golden 2; wai-ops' bundle tests 2;
jpegai_memory (front half luma 2,114,160 against 2,218,884, chroma 1,290,864 against
1,357,586); the differential, 1,500 cases, no disagreement. Each build's cargo check
(neural_int; neural_int,legacy_int,provenance; neural; the differential's features;
the default features with neural; wai-web; the byte-equality crate) adds no warning.

Falsified: the test-only direct mANS port refills its window to 48 bits instead of 56.
Production green (the CI trio, byte-exact's E8 golden); the comparisons red:
jpegai_ops 4 of 9 (the planes, the whole decode, both stream-parity tests), byte-exact's
direct-port golden, the differential ("Luma: the two decodes differ", seed
10208061212434326836). Restored: green.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
origin/main at f18ce9ac (#275, #278, #280, #281, #282, #283). CHANGELOG: both sections
kept, this branch's first.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The two K27 totality harnesses (16-byte streams, spans of up to 5) are kani_open: on the
build host each grew past a 48 GB memory guard (peak resident 76 and 91 GB) and was
stopped. k27_mans_is_total_small checks the same property on 10-byte streams, a latent
span of up to 3 positions and then a hyper-latent row of up to 3 symbols from the same
window; the stage shard's filter (proofs::stage::k27) runs it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The harness over a 10-byte stream with a latent span and a hyper-latent row of 3 also
grew past its memory guard on the build host (40 GB; peak resident 57 GB) and was
stopped. It is replaced by two harnesses over 8-byte streams, a span of up to 2 and a
row of up to 2.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
origin/main at bea79dc6 (the live-room, live-events and capture-binding extensions,
#284 to #288 among them). CHANGELOG: both sides kept, this branch's section first.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai-ops: K27's narrower harnesses withdrawn; K27's totality stays kani_open
All checks were successful
wai-ops integer operators / linux-x86_64 (pull_request) Successful in 1m4s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m29s
wai-ops integer operators / wasm32 under Node (pull_request) Successful in 23s
wai-ops integer operators / wasm32-wasip2 (wasmtime) (pull_request) Successful in 30s
wai-ops integer operators / independent checker (Python) (pull_request) Successful in 12s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 13s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 26s
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Successful in 2m18s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 1m14s
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Successful in 3m36s
wai-pack / wai-pack · linux (pull_request) Successful in 1m31s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 2m30s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m17s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 5m55s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 14m24s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 16m44s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Successful in 49m4s
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Successful in 6m11s
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Successful in 48m16s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 48m25s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 6s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m54s
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Successful in 6m40s
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Successful in 6m13s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m42s
wai-ops integer operators / linux-aarch64 (pull_request) Successful in 1m5s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 27s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m22s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m24s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 4m13s
3bc90f0297
None of the narrower windows fits a memory budget. On the build host, under memguard:
the existing kani_open harnesses (16-byte streams, a span or a row of up to 5) grew past
48 GB (peak resident 76 and 91 GB); one over a 10-byte stream with a span and a row of 3
past 40 GB (57 GB); and the latent and the hyper-latent harness over 8-byte streams with
2 positions each still ran past 25 minutes and 24 GB. Each was stopped. Run in the
stage shard, any of them would take its runner's memory, so they are withdrawn and K27's
totality harnesses stay kani_open as on main. The stage shard's k27 and k28 harnesses
that do fit (k27_mans_bounds_are_unsigned, k28_mans_entry_fields) verify.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Main gained wai.live.compose (#296). The only conflict was the CHANGELOG's top
insertion; both entries are kept, this one first.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merge remote-tracking branch 'origin/main' into wai/d2c-m7a
Some checks failed
wai formal verification (integer core) / kani (plan) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (sound) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (stage) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (rans64-t2) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (stage-long) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (integer-core) (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
a6cd06d780
dcharlot closed this pull request 2026-10-18 07:19:40 -04:00
dcharlot referenced this pull request from a commit 2026-10-18 07:34:19 -04:00
Some checks failed
wai-ops differential (nightly) / differential · debug (pull_request) Successful in 2m26s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 5s
wai-ops differential (nightly) / differential · release (pull_request) Successful in 3m25s
wai-quantum WebGPU member / member · DX12 and Vulkan (cbio-windows) (pull_request) Successful in 12m1s
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 builds · this tree's wai-web, every rung on its engine line (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 mbt2018_mean integer decode (regenerated vectors) / does this change touch it (pull_request) Has been cancelled
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Has been cancelled
wai-quantum WebGPU member / does this change touch it (pull_request) Has been cancelled
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Has been cancelled
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · Metal (macos) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · discrete GPU, Vulkan (jetson-hub) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · integrated GPU, Vulkan (framework-128gb) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · 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-ops integer operators / does this change touch it (pull_request) Has been cancelled
wai-ops integer operators / linux-aarch64 (pull_request) Has been cancelled
wai-ops integer operators / linux-x86_64 (pull_request) Has been cancelled
wai-ops integer operators / macos-arm64 (pull_request) Has been cancelled
wai-ops integer operators / wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
wai-ops integer operators / wasm32 under Node (pull_request) Has been cancelled
wai-ops integer operators / independent checker (Python) (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 neural decoders end-to-end / does this change touch it (pull_request) Has been cancelled
WAI neural decoders end-to-end / synthetic fixtures → Rust decode → reference (±4) (pull_request) Has been cancelled
WAI JPEG-AI whole decode (pinned inputs, required) / does this change touch it (pull_request) Has been cancelled
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (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 formal verification (integer core) / does this change touch it (pull_request) Has been cancelled
wai formal verification (integer core) / every harness in one shard (pull_request) Has been cancelled
wai formal verification (integer core) / kani (arith) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (isqrt512) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (plan) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (sound) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (stage) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (rans64-t2) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (stage-long) (pull_request) Has been cancelled
wai formal verification (integer core) / kani (integer-core) (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

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!298
No description provided.