open-standards/.github/workflows/wai-jpegai-e2e.yml
Transaction Science 427fb1dbd2 toolchain: Rust 1.98.0 -> 1.99.1 (change-controlled pin)
Approved by the owner on 2026-10-22. Procedure: change `channel`, run
`rustup show`, then run the pipeline.

What changed
- rust-toolchain.toml and eoc/eoc-rs/rust-toolchain.toml: channel "1.98.0"
  becomes "1.99.1". These are the only two pins in the tree, and the root one
  governs every other cargo root.
- 64 workflows under .github/workflows (the forge's CI): every `Install Rust
  1.98.0`, `rustup toolchain install / default / component add / target add
  --toolchain 1.98.0` and `--default-toolchain 1.98.0` now names 1.99.1
  (409 lines). Two of those lines are in build steps rather than install
  steps (wai-conformance.yml's two `wasm32 (unix)` steps each
  `rustup target add --toolchain`), and they move with the rest: a target
  added to a toolchain that is not installed is an error.
- Left as they are, because they record what was measured on 1.98.0:
  standards-build.yml's "Verified on a native arm64 Linux container (rustc
  1.98.0)", wai-conformance.yml's note on Rust 1.98's LLD 22, and the
  "rustc 1.98.0 (example)" strings in receipts, vectors and docs. The
  one-codegen-unit workaround that note explains also stays. 1.99.1 ships
  LLD 23.1.1, which the note says links those inputs, but removing the
  workaround should wait for a run at the CI path on x86_64.

Why
- 1.98.0 has a P-critical miscompile, rust-lang/rust#161441 (I-miscompile,
  regression-from-stable-to-stable). rustc emits a vacant (null) method slot
  in a trait-object vtable, so a safe dynamic call jumps to address zero
  (undefined behaviour). RELEASES.md records the fix in 1.98.1 ("rustc: fix
  miscompilation in generating vtables").
- 1.99.1 is the current stable (channel manifest dated 2026-10-15; rustc
  58cf8f9c3 2026-10-13). It also fixes 1.99.0's own regressions: wcslen on
  UEFI and embedded targets, x86_64 FFI `bool` returns, and the rust-lld rpath
  on macOS.

Evidence
All of it ran on the build host ([email protected], aarch64-apple-darwin)
through ~/kani-logs/remote/rb. Nothing was built on the dev Mac.

- `rustup show`: the active toolchain is 1.99.1-aarch64-apple-darwin,
  "overridden by .../rust-toolchain.toml" (and by eoc/eoc-rs's own file
  there). rustc 1.99.1 (58cf8f9c3 2026-10-13), LLVM 23.1.1, clippy 0.1.99,
  rustfmt 1.10.0. The baseline is rustc 1.98.0 (88d9e12ae 2026-08-18).
- Scope: every cargo root the pin governs, which is 46 of the 49 tracked
  lockfiles. The other three: two are vendored crates that resolve inside
  their parents, and wai/wai-rs/fuzz builds on its own pinned nightly.
- Trees. The final tree is main at 96117c570 plus these two commits. Main
  moved four times while this ran, and each root's evidence comes from the
  newest tree it was run on:
  - 13 roots on the final tree: every root main changed after 1a465f23d,
    and every root that consumes such a crate by path.
  - 12 roots on 1a465f23d plus these two commits.
  - 7 roots on b16816671 plus these two commits.
  - 14 roots on aa61ab3b9 plus the pin change.
  For each root in the last three groups, checked with git diff and the
  lockfiles' path packages: none of its files, and no crate it reaches by
  path, differs on the final tree.
- Each root got:
  (a) `cargo fmt --all -- --check` on the pin and on 1.98.0. The output is
      byte-identical in all 46. CI gates no root on rustfmt, and none is
      rustfmt-clean on main.
  (b) `cargo clippy --locked --keep-going --workspace --all-targets` on both
      toolchains, with the diagnostics compared line by line. After the
      previous commit, no root has a diagnostic that only 1.99.1 reports.
      openpay's one differing line is the same lint at the same site,
      reworded.
  (c) `cargo test --workspace --locked`.
  (d) the root's other CI steps that can run on this host: feature-gated
      tests, conformance suites, release-profile tests, the aac page-set
      checks, and every clippy -D warnings gate. The gates are
      standards-build's macOS meter and omni lints (jouleclaw-energy x2,
      jouleclaw-omni metal, jouleclaw-loader-gguf, jcp, proof, eoc, sandbox),
      wai-pack, wai-quantum-cli (default, no-default and metal),
      wai-quantum-service, wai-quantum-qpu and wai-quantum-desktop.
- Totals: `cargo test --workspace` ran in 43 roots: 12,532 passed, 1 failed,
  101 ignored. The other 3 roots are wasm32-only, and their
  `cargo build --release --target wasm32-unknown-unknown` passed. Every
  other CI step passed (62 of 62).
- On the final tree: scripts/check-lockfiles.sh (cargo 1.99.1) found all 47
  lockfiles current, and scripts/check-advisories.py passes.
- tokio is 1.54.1 in every lockfile cargo reads. That is patched for both
  RUSTSEC-2026-0386 (>= 1.53.3) and RUSTSEC-2026-0384 (>= 1.54.1). The 1.53.1
  in vendor/wtransport/Cargo.lock is the upstream file kept with the vendored
  source; cargo resolves wtransport inside its parents, and both gates skip
  that file.
- What is not green, each one reproduced on 1.98.0:
  - wai-ops-gpu: under the debug profile, `corpus` trips the debug_assert at
    exec.rs:187 on both toolchains. CI runs it in release only, and that
    passes (6/6).
  - wai-ops: clippy::derived_hash_with_manual_eq (deny-by-default) on both
    toolchains. No CI job runs clippy there.
  - wai-vector/wasm: `--all-targets` cannot build the lib-test target (its
    own `panic_impl`) on either toolchain. `clippy --lib` for wasm32 reports
    0 diagnostics on both.
  - eoc-cascade's hit_calibration_process_energy test reads real energy
    counters, and it fails some of the time on the loaded shared host. In
    interleaved runs each toolchain passed 18 of 20. The full eoc-rs suite
    passed on the final tree (741 passed).
- Environment, not code:
  - wai-quantum-desktop embeds the Studio's build, so wai/quantum-studio was
    built first (`npm ci`, `node build.mjs`), as CI does.
- Not covered here: the x86_64 and arm64 Linux and Windows legs; the GPU,
  NPU, FPGA, emulator and hardware-meter legs; wasm32 tests under Node,
  wasmtime and wasip2; and the fuzz job.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 07:34:06 -05:00

338 lines
19 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: WAI JPEG-AI whole decode (pinned inputs, required)
# WAI states that the exact decoder, `wai::jpegai_decode::decode`, decodes an
# ISO/IEC 6048 JPEG-AI codestream to RGB deterministically, so a hard binding
# taken over one decode verifies a second one, and that on one reference
# codestream its output stays within max|Δ| ≤ 2 of the reference decoder's
# (recorded max|Δ| = 1; wai/SPEC.md §5, the wai.image.jpegai row).
# Across machines the registry states less: it classes wai.image.jpegai as
# NeuralEntropyExact, a conservative class that guarantees only the entropy decode
# (the decoded symbols and their entropy parameters) to be byte-identical on every
# machine. That the exact decoder's pinned output is the same on other machines is
# a measurement, recorded in wai/extensions/determinism-tiers.md §6. The tests that
# carry these statements (tests/jpegai_e2e_full.rs,
# tests/jpegai_reconstruction_binding.rs) read their inputs from outside the tree
# and used to report PASS without them.
#
# This job fetches those inputs from WAI's versioned models root (jpegai/v1/),
# checks every file against the SHA-256 manifest committed in
# wai/tools/jpegai-e2e-v1.sha256, and runs both tests with
# WAI_REQUIRE_SOTA_VECTORS=1, so a missing input is a failure. What passes here:
# - the whole chain, codestream → RGB, through the one public `decode()` call,
# lands within max|Δ| ≤ 2 of the reference decoder's output, and at most 5%
# of samples differ from it at all (the test's bar);
# - two decodes in one process are byte-identical and the reconstruction binding
# verifies the second and rejects a one-byte change;
# - the bundle's bounds certificate (wai/extensions/integer-operators.md §8.5,
# §13.6: the two scale graphs and the four graphs of its other integer
# networks) is byte for byte the one committed under the set's digest in
# wai/ops-conformance/certificates/, which is the listing digest the set-form
# pin below covers, from both certifiers (wai-verify and the independent
# tools/wai_ops_check.py); its verdict meets acc64, and the scale path's graphs
# meet acc32 (§11, role_profiles);
# - the decoded pixels hash to WAI_JPEGAI_EXPECT_SHA256 below: the value measured
# from these inputs on an Apple Silicon Mac (aarch64 macOS, native) and
# reproduced by an x86_64 Linux build (glibc, run under QEMU user-mode
# emulation), and the value the four-platform comparison in determinism-tiers
# §6 (macOS arm64, wasm32-wasip2, Linux arm64, Linux x86_64 under user-mode
# emulation) found on every platform. This runner is x86_64 hardware, so the
# job adds a decode on one more machine to that measurement. A match is a
# measurement on this runner, not something the registry class promises; a
# mismatch is a departure from the measured agreement.
# The pinned decode is max|Δ| = 1 from the reference on 4.446% of samples
# (on the Mac and the emulated x86_64 build), so a hash match also confirms
# that recorded max|Δ| = 1 for this codestream; the test's own tolerance
# above is looser than that.
#
# What this job does not cover:
# - Other codestreams: it decodes one 256×256 test codestream, so the
# max|Δ| ≤ 2 bound and the determinism statement are checked on that input
# only.
# - The extraction: the inputs are an extraction of the JPEG-AI
# reference-software assets (tools/wai_jpegai_build_e2e_inputs.py), which are
# not in the repository, so the extraction is not re-run here; the manifest
# pins its published bytes.
# - The ONNX-runtime decode (`neural::jpegai`, tests/jpegai_live.rs), which needs
# those local assets and is not run in CI. It also needs the `neural` feature,
# whose prebuilt ONNX Runtime does not link on the `linux` runner's image
# (glibc 2.35; the library references glibc 2.38 symbols), which is where
# wai-neural-e2e.yml's runs fail once they reach the Rust build. The
# features built here (neural_int, provenance) link no prebuilt native
# library.
# The job depends on the models root being reachable; an outage fails the job.
#
# The path filters list the source files the two tests' decode path imports,
# among them src/float_repro.rs (the exact decoder's `exp` and its roundings to
# an integer) and src/int_kernels.rs (the fast convolution and parallel-map
# kernels the integer networks run through). An entry for a file the tree does
# not have matches nothing until the file exists. A module the decode path
# starts importing belongs here too; otherwise a change to that module alone is
# first checked by the weekly run.
# One run per branch at a time. A push supersedes the run before it.
#
# There is one `macos` runner and it is the dev Mac, so every macOS job in this
# repo queues on it. With no concurrency group, a session pushing four versions
# of a branch queued four complete sets of runs and every one of them had to
# drain: on 2026-10-05 a PR's 21 contexts settled none in 70 minutes behind a
# backlog of 25 runs, and the queue grew faster than it cleared. Only the newest
# commit's verdict is wanted, so the older runs are cancelled.
#
# Verified on this forge (Forgejo 16.0.5) in `ci-test` before being added here:
# the key parses, and a newer push moves an older run to `cancelled` even while
# it is still queued, which is the case that matters.
#
# `cancel-in-progress: true` also applies to `main`. That is deliberate and
# safe here: main advances by merge commits whose tree contains the commits
# before them, so the newer run covers the older one's changes.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
pull_request:
paths:
- 'wai/wai-rs/src/jpegai_*.rs'
- 'wai/wai-rs/src/reconstruction_binding.rs'
# The set-form pin over the exact bundle (tests/jpegai_e2e_full.rs) verifies
# through the pin module.
- 'wai/wai-rs/src/pin.rs'
- 'wai/wai-rs/src/container.rs'
- 'wai/wai-rs/src/int_transformer.rs'
- 'wai/wai-rs/src/int_hyper_synth.rs'
- 'wai/wai-rs/src/int_kernels.rs'
- 'wai/wai-rs/src/float_repro.rs'
- 'wai/wai-rs/src/int_entropy.rs'
- 'wai/wai-rs/src/int_transform.rs'
- 'wai/wai-rs/src/rans.rs'
- 'wai/wai-rs/Cargo.lock'
- 'wai/wai-rs/tests/jpegai_e2e_full.rs'
- 'wai/wai-rs/tests/jpegai_reconstruction_binding.rs'
- 'wai/wai-rs/tests/jpegai_cross_platform.rs'
- 'wai/wai-rs/tests/jpegai_ops.rs'
- 'wai/wai-rs/tests/jpegai_nets_ops.rs'
- 'wai/wai-rs/tests/jpegai_memory.rs'
- 'wai/wai-rs/src/int_set_cache.rs'
- 'wai/wai-rs/src/int_ops.rs'
- 'wai/ops-conformance/sets/jpegai/**'
- 'wai/wai-rs/tests/support/**'
- 'wai/tools/wai_jpegai_fetch_e2e_inputs.sh'
- 'wai/tools/jpegai-e2e-v1.sha256'
# The bounds certificate of the bundle's scale path (the step after the fetch):
# the certifier, and the certificate committed by digest.
- 'wai/wai-ops/src/**'
- 'wai/wai-ops/tests/goldens.rs'
- 'wai/wai-verify/Cargo.toml'
- 'wai/wai-verify/Cargo.lock'
- 'wai/wai-verify/src/bin/**'
- 'wai/ops-conformance/certificates/external.json'
- 'wai/ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json'
- 'wai/tools/wai_ops_check.py'
- '.github/workflows/wai-jpegai-e2e.yml'
# Weekly, independent of changes: the inputs live outside the repository, and
# their disappearing should surface here, not at the next unrelated PR.
schedule:
- cron: '41 6 * * *'
jobs:
# Does this pull request's own diff touch the paths below? This forge matches a
# workflow's `paths:` against the push, so a merge of main into a branch fires the
# workflow whatever the pull request changes; every job here waits on this answer.
# A push to main, a schedule, or anything the script cannot determine answers
# `true` (scripts/pr-touches-paths.py).
relevant:
name: does this change touch it
runs-on: linux-arm64
outputs:
run: ${{ steps.gate.outputs.run }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- id: gate
run: |
set -euo pipefail
r=$(python3 scripts/pr-touches-paths.py .github/workflows/wai-jpegai-e2e.yml \
"${{ github.event.pull_request.base.sha }}" \
"${{ github.event.pull_request.head.sha }}")
echo "this change touches wai-jpegai-e2e: $r"
echo "run=$r" >> "$GITHUB_OUTPUT"
jpegai-e2e:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: fetch pinned JPEG-AI inputs → whole decode + pixel hash, required
runs-on: linux
timeout-minutes: 60
env:
WAI_REQUIRE_SOTA_VECTORS: '1'
WAI_JPEGAI_DIR: ${{ github.workspace }}/jpegai_e2e
# sha256 of the decoded RGB8 pixels for the jpegai/v1 inputs (see header).
WAI_JPEGAI_EXPECT_SHA256: dbc494a5a670914edf55c07c48afc0dd348cd05d3a82fff293bf384b2bb69ea3
steps:
- uses: actions/checkout@v5
# Bootstrap rustup: the docker runner image ships no Rust.
- name: Install Rust 1.99.1
shell: bash
run: |
export PATH="$HOME/.cargo/bin:$PATH"
command -v rustup >/dev/null 2>&1 || \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1
rustup toolchain install 1.99.1 --profile minimal
rustup default 1.99.1
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: Fetch the JPEG-AI inputs and check each against the pinned manifest
shell: bash
working-directory: wai
run: tools/wai_jpegai_fetch_e2e_inputs.sh "$WAI_JPEGAI_DIR"
# The scale path's bounds certificate (integer-operators §8.5, §13.6.1). The
# bundle is not committed, so its certificate is, under the set's digest (the
# listing of norm.json and weights/*, as the set-form pin covers it), and
# listed in wai/ops-conformance/certificates/external.json.
- name: The bundle's bounds certificate is the committed one; it meets acc64, and its scale path acc32
shell: bash
working-directory: wai
run: |
set -euo pipefail
(cd wai-verify && cargo build --locked --release --features cli --bin wai-verify)
D="$WAI_JPEGAI_DIR"
M=(--member "norm.json=$D/norm.json")
for n in hs_y hs_uv hyp_y hyp_uv synth_y synth_uv mcm0_y mcm1_y mcm2_y mcm3_y icci; do
M+=(--member "weights/$n.json=$D/$n.json")
done
wai-verify/target/release/wai-verify bounds --capability wai.image.jpegai "${M[@]}" \
--profile acc64 --role-profile hs_y=acc32 --role-profile hs_uv=acc32 \
--out "${RUNNER_TEMP:-/tmp}/jpegai-bounds.json" \
--check ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json
# The same certificate from the independent certifier (Python standard library
# only, sharing no code with wai-ops).
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: The independent certifier writes the same certificate; it meets acc64, and its scale path acc32
shell: bash
working-directory: wai
run: |
set -euo pipefail
D="$WAI_JPEGAI_DIR"
M=(--member "norm.json=$D/norm.json")
for n in hs_y hs_uv hyp_y hyp_uv synth_y synth_uv mcm0_y mcm1_y mcm2_y mcm3_y icci; do
M+=(--member "weights/$n.json=$D/$n.json")
done
python3 -I tools/wai_ops_check.py certify --capability wai.image.jpegai --lowering jpegai-int/1 "${M[@]}" \
--profile acc64 --role-profile hs_y=acc32 --role-profile hs_uv=acc32 --out "${RUNNER_TEMP:-/tmp}/jpegai-bounds-py.json" \
--check ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json
# The operator set's lowering of the bundle's scale path (integer-operators
# §13.6.1), run through the interpreter with every value held to its certified
# interval, against the legacy decoder's arithmetic on the same bundle.
- name: The scale path's lowering decodes as the legacy arithmetic does
shell: bash
working-directory: wai/wai-ops
run: |
set -euo pipefail
WAI_OPS_JPEGAI_BUNDLE="$WAI_JPEGAI_DIR" \
cargo test --locked --release --test goldens -- --ignored --exact jpegai_scale_path_on_a_supplied_bundle
- name: Whole decode vs the reference, determinism, pinned pixel hash (missing input = failure)
shell: bash
working-directory: wai/wai-rs
run: |
set -o pipefail
log="${RUNNER_TEMP:-/tmp}/jpegai-tests.log"
# Without the switch both tests would skip and report ok.
[ "${WAI_REQUIRE_SOTA_VECTORS:-}" = 1 ] \
|| { echo "::error::WAI_REQUIRE_SOTA_VECTORS must be 1 in this job"; exit 1; }
export WAI_JPEGAI_CODESTREAM="$WAI_JPEGAI_DIR/test256.bin"
export WAI_JPEGAI_WEIGHTS_DIR="$WAI_JPEGAI_DIR"
export WAI_JPEGAI_NORM="$WAI_JPEGAI_DIR/norm.json"
# --show-output rather than --nocapture: each test's output is printed
# after the results, so it cannot split a `test X ... ok` line below.
cargo test --release --no-default-features --features neural_int,provenance \
--test jpegai_e2e_full --test jpegai_reconstruction_binding --test jpegai_cross_platform \
-- --show-output 2>&1 | tee "$log"
# A test that was renamed or compiled out would not fail — it would just
# not run. Require each one by name, and the pinned-hash check by its line.
for t in codestream_to_rgb_matches_reference_png real_decode_to_reconstruction_binding \
decode_matches_pinned_hashes jpegai_e2e_set_pin_verifies; do
grep -q "^test $t \.\.\. ok$" "$log" || { echo "::error::$t did not run and pass"; exit 1; }
done
grep -q "matches the pinned WAI_JPEGAI_EXPECT_SHA256" "$log" \
|| { echo "::error::the pinned pixel hash was not checked"; exit 1; }
# A skip also prints `test X ... ok`; every skip writes a banner with
# "SKIPPED" and "NOT VERIFIED" (tests/support/require_vectors.rs).
if grep -nE 'SKIPPED|NOT VERIFIED' "$log"; then
echo "::error::a JPEG-AI test skipped instead of checking its input"
exit 1
fi
# The scale path and the entropy decodes through the integer operator set
# (integer-operators §13.6.1, lowered by jpegai-int/1), on this bundle: the lowering
# of the bundle as the decoder parses it is the lowering of its bytes and the
# committed certificate's graphs, under acc32; both planes' integers and the whole
# decode through the operator set are the direct decode's; a stream cut at every
# length is refused (stream_exhausted) exactly where the direct decode panics; and a
# codestream out of scope is refused with its reason.
- name: The scale path through the integer operator set, on the pinned bundle (missing input = failure)
shell: bash
working-directory: wai/wai-rs
run: |
set -o pipefail
log="${RUNNER_TEMP:-/tmp}/jpegai-ops.log"
[ "${WAI_REQUIRE_SOTA_VECTORS:-}" = 1 ] \
|| { echo "::error::WAI_REQUIRE_SOTA_VECTORS must be 1 in this job"; exit 1; }
export WAI_JPEGAI_CODESTREAM="$WAI_JPEGAI_DIR/test256.bin"
export WAI_JPEGAI_WEIGHTS_DIR="$WAI_JPEGAI_DIR"
export WAI_JPEGAI_NORM="$WAI_JPEGAI_DIR/norm.json"
cargo test --release --no-default-features --features neural_int,legacy_int --test jpegai_ops --test jpegai_memory \
-- --show-output 2>&1 | tee "$log"
for t in the_committed_bundle_lowers_to_its_committed_graphs_and_verdict \
the_pinned_bundle_lowers_to_its_certificate_and_meets_acc32 \
the_planes_decode_through_the_lowering_as_directly \
the_whole_decode_through_the_lowering_is_the_direct_decode \
every_load_check_of_the_bundle_refuses_model_mismatch \
a_stream_cut_short_is_refused_where_the_direct_decode_panics \
a_stream_cut_short_is_refused_where_the_direct_decode_panics_pinned \
a_codestream_out_of_scope_is_refused_with_its_reason \
every_kernel_policy_decodes_the_planes_alike \
the_decode_holds_no_more_than_the_direct_decode; do
grep -q "^test $t \.\.\. ok$" "$log" || { echo "::error::$t did not run and pass"; exit 1; }
done
if grep -nE 'SKIPPED|NOT VERIFIED' "$log"; then
echo "::error::a JPEG-AI test skipped instead of checking its input"
exit 1
fi
# The other integer networks through the integer operator set (integer-operators
# §13.6.2, lowered by jpegai-int/1 to rec_y, rec_uv, syn_y and syn_uv), on this
# bundle: the lowering of the networks as the decoder parses them is the lowering of
# their bytes and the committed certificate's graphs, under acc64; each network
# through its graph gives the direct network's values on the test codestream; every
# value each operator forms there lies within its certified interval (the measured
# accumulators of §13.6.2); and every kernel policy runs the graphs alike.
- name: The hyper decoders, context stages and synthesis through the integer operator set, on the pinned bundle (missing input = failure)
shell: bash
working-directory: wai/wai-rs
run: |
set -o pipefail
log="${RUNNER_TEMP:-/tmp}/jpegai-nets-ops.log"
[ "${WAI_REQUIRE_SOTA_VECTORS:-}" = 1 ] \
|| { echo "::error::WAI_REQUIRE_SOTA_VECTORS must be 1 in this job"; exit 1; }
export WAI_JPEGAI_CODESTREAM="$WAI_JPEGAI_DIR/test256.bin"
export WAI_JPEGAI_WEIGHTS_DIR="$WAI_JPEGAI_DIR"
export WAI_JPEGAI_NORM="$WAI_JPEGAI_DIR/norm.json"
cargo test --release --no-default-features --features neural_int,legacy_int --test jpegai_nets_ops \
-- --show-output 2>&1 | tee "$log"
for t in the_committed_bundle_lowers_to_its_committed_networks \
the_pinned_bundle_lowers_its_networks_to_its_certificate \
the_networks_decode_through_the_lowering_as_directly \
the_whole_decode_through_the_networks_is_the_pinned_decode \
the_networks_keep_to_their_certificate_on_the_test_codestream \
every_load_check_of_the_networks_refuses_model_mismatch \
a_value_past_its_range_is_refused_field_range \
every_kernel_policy_runs_the_networks_alike; do
grep -q "^test $t \.\.\. ok$" "$log" || { echo "::error::$t did not run and pass"; exit 1; }
done
if grep -nE 'SKIPPED|NOT VERIFIED' "$log"; then
echo "::error::a JPEG-AI test skipped instead of checking its input"
exit 1
fi