open-standards/.github/workflows/wai-pack.yml
Transaction Science a544054098
All checks were successful
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 1h4m33s
standards workspaces build + test / aac-rs (pull_request) Successful in 15m41s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 5m23s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 4m7s
standards workspaces build + test / map-rs (pull_request) Successful in 5m41s
standards workspaces build + test / mesh-rs (pull_request) Successful in 2m16s
standards workspaces build + test / openpay (pull_request) Successful in 13m43s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m13s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m55s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m30s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m13s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m17s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m18s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m16s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m5s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m37s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 4s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 2m59s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 2m47s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 4m54s
wai-pack / wai-pack · linux (pull_request) Successful in 1m48s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 3m0s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 24s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 2m0s
wai-pack / wai-pack · macos (pull_request) Successful in 2m11s
ci: a rebase ran every path-filtered workflow, because paths: matches the push delta
Forgejo matches a workflow's `paths:` filter against the **push delta**, not the
pull request's diff. A rebase moves a branch across every commit main has
gained, so its delta touches nearly every path and every path-filtered workflow
fires.

Measured on this repo, as a clean natural experiment — five PRs, all changing
only `jcp/` or `mesh/`:

| PRs | how pushed | workflows triggered |
|---|---|---|
| #189, #190 | fresh branch, one push | **2** |
| #165, #177, #183 | force-push after rebase | **15** |

Fifteen includes JPEG-AI whole decode, `wai-pack` on three platforms, and
cross-architecture byte-equality on three — none of which a change to
`jcp/jcp-rs/crates/jcp-grant/src/checkpoint.rs` can affect. Rebasing three PRs
put the queue 65 runs deep behind one macOS runner, which delays everyone's real
jobs, and there is no way to rebase without it: a merge of main into the branch
has the same delta.

So the `paths:` filters still gate the *trigger*, and a new `relevant` job gates
the *work*, from the pull request's own diff. It reads the path list out of the
workflow file it guards, so there is one list rather than a third copy to drift
from the two `on:` blocks. On a push to main there is no pull-request context,
the shas are empty, and the gate answers `true` — main runs everything, as
before.

**It fails open, by construction.** A gate that decides whether tests run is
load-bearing in the dangerous direction: a wrong `false` silently skips a whole
workflow, which is the "passes but tested nothing" failure. Every way the script
can fail to decide — a missing workflow file, a filter it cannot parse, an empty
or unresolvable sha, too few arguments, an empty diff — prints `true`. The
self-test pins all six of those, both directions of the real decision, and that
`**` spans a path separator while `*` does not.

Writing that self-test caught one of its own cases: the single-star case first
created a top-level `.md` alongside the nested one, so the glob matched
legitimately and the case proved nothing. It now changes only the nested file,
and asserts separately that the glob does match at its own level — so it cannot
pass by never matching anything.

Applied to `wai-pack.yml` alone, not all eighteen. What a *skipped* job reports
as a commit status on this forge is the open question, and a required context
that never reports would make PRs unmergeable. That failure is at least loud
rather than silent, but it is worth learning on the most expensive workflow —
six job instances across three platforms — before changing the rest. Validated
against real branches first: every WAI workflow answers `false` for #165's
jcp-only diff and `true` for a WAI branch, and `standards-build.yml` correctly
answers `true` for #165 because it builds every workspace.

The hygiene workflow runs the self-test, so the gate cannot regress silently,
and its own `paths:` filter now lists the scripts it checks.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-08 11:40:23 -04:00

277 lines
12 KiB
YAML

name: wai-pack
# The reference packager of WAI's packaging extension (wai/extensions/packaging.md) and
# its conformance corpus (wai/pack-conformance). Four jobs:
#
# - legs: on each architecture of the fleet, clippy with float arithmetic denied (no
# float decides anything in a package), the tests in release with a floor on how many
# each target lists, and the corpus recomputed by the crate: the golden packages
# packed again byte for byte and verified, every mutation's reason.
# - independent: the corpus recomputed by its second implementation, written in Python
# from the extension text and sharing no code with wai-pack, the golden packages
# verified and re-derived from their sources among it.
# - media: the golden's floor, its CMAF initialization segment and fragments, read and
# decoded by a media prober (test 14).
# - licences: every crate in wai-pack's dependency graph is under a licence deny.toml
# allows; a source-available licence fails it.
#
# Push filters match the push's delta, so every path a build or a verifier reads is
# listed: the crate, the wai crate it builds on, the corpus, the BLAKE3 and integer
# payload verifiers and the registry export pack_verify.py reads, and this file.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
pull_request:
paths:
- 'wai/wai-pack/**'
- 'wai/wai-rs/**'
- 'wai/pack-conformance/**'
- 'wai/claim-conformance/_blake3.py'
- 'wai/claim-conformance/_ed25519.py'
- 'wai/int-payload-conformance/int_payload_verify.py'
- 'wai/registry/capabilities.json'
- '.github/workflows/wai-pack.yml'
push:
branches: [main]
paths:
- 'wai/wai-pack/**'
- 'wai/wai-rs/**'
- 'wai/pack-conformance/**'
- 'wai/claim-conformance/_blake3.py'
- 'wai/claim-conformance/_ed25519.py'
- 'wai/int-payload-conformance/int_payload_verify.py'
- 'wai/registry/capabilities.json'
- '.github/workflows/wai-pack.yml'
jobs:
# Forgejo matches the `paths:` filters above against the **push delta**, not
# the pull request's diff. A rebase moves a branch across every commit main
# has gained, so its delta touches nearly every path and this workflow fires
# on changes that cannot affect it. Measured on this repo: a jcp-only change
# pushed to a fresh branch ran 2 workflows; the same change force-pushed after
# a rebase ran 15, this one among them, putting three platforms of wai-pack and
# the JPEG-AI whole decode in a queue they had no business being in.
#
# So the filters above still gate the *trigger*, and this job gates the
# *work*, from the pull request's own diff. It reads the path list out of this
# file, so there is one list and not a third copy to drift. On a push to main
# there is no pull-request context, the shas are empty, and the gate answers
# `true` — a push to main runs everything, as before.
relevant:
name: wai-pack · does this change touch it
runs-on: linux
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-pack.yml \
"${{ github.event.pull_request.base.sha }}" \
"${{ github.event.pull_request.head.sha }}")
echo "this change touches wai-pack: $r"
echo "run=$r" >> "$GITHUB_OUTPUT"
legs:
name: wai-pack · ${{ matrix.os }}
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# Self-hosted fleet labels: x86_64 by linux, arm64 by linux-arm64 and macos.
# A Windows leg waits for its runner (see wai-byte-equality.yml).
os: [linux, linux-arm64, macos]
steps:
- uses: actions/checkout@v5
# The docker runners ship no Rust, so rustup is bootstrapped; the macOS host has
# it, but launchd's PATH omits ~/.cargo/bin.
- name: Install Rust 1.98.0
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.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
rustup component add --toolchain 1.98.0 clippy
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# clippy::float_arithmetic is denied for the library and the CLI (Cargo.toml and
# the crate attributes); -D warnings makes every other lint fail the step too.
- name: clippy, float arithmetic denied
working-directory: wai/wai-pack
run: cargo clippy --locked --all-targets -- -D warnings
- name: Tests (release)
working-directory: wai/wai-pack
run: cargo test --release --locked
# A target that lost its tests (a module dropped, a cfg that compiles them out)
# would still report ok. Each target must list at least as many tests as it had
# when the floor was set; raise a floor when tests are added.
- name: Test-count floor per target
shell: bash
working-directory: wai/wai-pack
run: |
set -euo pipefail
fail=0
while read -r target floor; do
n=$(cargo test --release --locked $target -- --list 2>/dev/null | grep -c ': test$' || true)
echo "$target: $n tests (floor $floor)"
[ "$n" -ge "$floor" ] || { echo "::error::$target lists $n tests, under its floor of $floor"; fail=1; }
done <<'EOF'
--lib 28
--test=conformance 1
--test=packs 7
--test=review 9
--test=refusals 5
--test=scenecut 3
--test=source_alloc 1
EOF
exit $fail
- name: The corpus, recomputed by wai-pack
working-directory: wai/wai-pack
run: cargo run --release --locked --bin wai-pack -- conformance check ../pack-conformance
independent:
name: wai-pack · independent verifier (Python)
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: linux
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v5
with:
python-version: '3.11'
# The standard library (tomllib, hashlib); BLAKE3 from the shared pure-Python module
# beside the claim corpus; the package receipts' Ed25519 equation from the
# `cryptography` package, pinned with its dependencies by SHA-256 so pip installs only
# the files the requirements name.
- name: Install the Ed25519 library (hashes required)
shell: bash
working-directory: wai
run: python -m pip install --require-hashes -r pack-conformance/requirements-verify.txt
- name: pack_verify.py
working-directory: wai
shell: bash
run: python3 pack-conformance/pack_verify.py pack-conformance
- name: Install Rust 1.98.0
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.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# The source readers differentially: seeded Y4M and WAV mutations, every verdict of
# wai-pack (debug and release, both with overflow checks) equal to pack_verify.py's,
# and no reader panicking.
- name: source_diff.py, wai-pack against pack_verify.py
shell: bash
working-directory: wai/wai-pack
run: |
set -euo pipefail
cargo build --locked --bin wai-pack
cargo build --release --locked --bin wai-pack
for profile in debug release; do
python3 ../pack-conformance/source_diff.py "target/$profile/wai-pack" 1 3000
done
# The policy reader differentially: byte-level cases and seeded random policies,
# every verdict and digest of wai-pack equal to pack_verify.py's.
- name: policy_diff.py, wai-pack against pack_verify.py
shell: bash
working-directory: wai/wai-pack
run: python3 ../pack-conformance/policy_diff.py target/release/wai-pack 1 3000
# wai.pack.scenecut/1 differentially: the streaming segmenter against
# pack_verify.py's on-demand form on seeded random clips.
- name: segment_diff.py, wai-pack against pack_verify.py
shell: bash
working-directory: wai/wai-pack
run: python3 ../pack-conformance/segment_diff.py target/release/wai-pack 1 2000
media:
name: wai-pack · the floor through a media prober
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: linux
steps:
- uses: actions/checkout@v5
- name: Install a media prober
shell: bash
run: |
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
$SUDO apt-get update -qq
$SUDO apt-get install -y -qq ffmpeg
# Test 14: the golden's init.mp4 and its fragments, in its floor playlist's order,
# read as one AV1 track of every frame of the source, with a key frame at each piece
# start of the plan and nowhere else, and decode without an error.
- name: The golden's floor reads and decodes
shell: bash
working-directory: wai/pack-conformance/packs/video-base-01/package
run: |
set -euo pipefail
tmp=$(mktemp -d)
cat floor/v/init.mp4 $(grep -v '^#' hls/classic/floor-v.m3u8 | sed 's#^\.\./\.\./##') > "$tmp/floor.mp4"
ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=codec_name,width,height,nb_read_frames -of default=nw=1 "$tmp/floor.mp4" | tee "$tmp/probe.txt"
grep -qx 'codec_name=av1' "$tmp/probe.txt"
grep -qx 'nb_read_frames=200' "$tmp/probe.txt"
keys=$(ffprobe -v error -select_streams v:0 -show_entries packet=pts,flags -of csv=p=0 "$tmp/floor.mp4" | awk -F, '$2 ~ /K/ {print $1}' | tr '\n' ' ')
want=$(tr '\n' ' ' < plan-v.txt)
echo "key frames: $keys"
[ "$keys" = "$want" ] || { echo "::error::key frames at $keys; the plan says $want"; exit 1; }
ffmpeg -v error -xerror -i "$tmp/floor.mp4" -f null -
echo "the floor reads as one AV1 track of 200 frames, a key frame at each piece start"
licences:
name: wai-pack · dependency licences
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: linux
steps:
- uses: actions/checkout@v5
- name: Install Rust 1.98.0
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.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: Install cargo-deny
shell: bash
run: cargo install --locked cargo-deny --version 0.19.8
- name: cargo deny check licenses
working-directory: wai/wai-pack
run: cargo deny --locked check licenses
# deny.toml's MPL-2.0 exception covers cbindgen as wai's build-time tool: it must
# reach wai-pack through no normal (linked) edge. The second query sees the build
# edge, so an empty answer from the first is an answer.
- name: cbindgen is a build dependency only
shell: bash
working-directory: wai/wai-pack
run: |
set -euo pipefail
err=$(mktemp)
if ! linked=$(cargo tree --locked -e normal --target all -i cbindgen 2>"$err"); then
grep -q "did not match any packages" "$err" || { cat "$err"; exit 1; }
linked=""
fi
if [ -n "$linked" ]; then
echo "::error::cbindgen is a linked dependency of wai-pack; its MPL-2.0 exception covers a build tool only"
echo "$linked"
exit 1
fi
cargo tree --locked -e normal,build --target all -i cbindgen | grep -q '^cbindgen v' || { echo "::error::cbindgen not found as wai's build dependency"; exit 1; }
echo "cbindgen is a build dependency only"