The six splits CORE.md listed as owed before 1.0, and the video floor's bound, as one re-pin of the candidate. - The freeze rule gains a candidate re-pin: while the lock's status is `candidate`, a change of meaning raises `candidate` by exactly one, rewrites the digests (--write-lock) and adds a dated note naming each changed item and why; the core stays 1.0 until declared. The check fails a changed pin without both, a note that leaves out or adds an item, a candidate raised with no change or by two, a re-pin of a declared core and an edited note; the self-test plants each. Errata of candidate k are `<core>-c<k>-E<n>`. decisions.md D2. - Class membership: SPEC §7's registry classes, the refusal of replicate by class and the standard-codec promise are rules over the registry's `replicate` member (spec.7.classes, spec.7.standard); §5's candidate and companion-only rules read the registry's `status` and `kind` (spec.5.candidates, spec.5.companions); §7.1's companion rules read the kind and the media classes. The member lists are the profiles' text. - Claim receipts: jwp-receipts §2.4.4's rules, §3.1's six steps and §7.5's rules as every class keeps them are core (receipts.2.4.4, receipts.3.1, receipts.7.5); class tables and specifics are the provenance profile's. §7.6 to §7.9 split into units; §7.9's checks 9 and 10 read the profile that defines a module's form. claim- and signer-conformance stay unpinned (decisions D3). - Tiers: determinism-tiers' What a tier covers and §3 are core (tiers.covers, tiers.3), lifted out of the analysis of outside metadata standards. - prior-carriage §5's established-exact list is the models profile's; SPEC §7 reads it by reference. - Profile names in held text restated as rules, but OER/2's signature exception, which stays held (decisions D4); the reference implementation's names move to informative notes. - The video floor is AV1 Main profile, Main tier, level 4.1 and its limits (decisions D1: AV1 Annex A, and a mobile platform's AV1 requirements). wai::video_floor checks a payload; packaging §7.1 makes a video component's first floor rung its floor rendition, which wai-pack refuses outside the bound (floor-av1-profile, floor-av1-level), tested. - floor-conformance: the video-floor case signals level 4.1 (it signalled 31) with the same frames; the bound and two refused streams (High profile, level 5.0) are added; floor_verify.py checks them with planted faults and reports the AV1 decode not run without --dav1d. Co-Authored-By: Claude <[email protected]>
328 lines
18 KiB
YAML
328 lines
18 KiB
YAML
# Repository checks: the script checks every change runs, in one job.
|
|
#
|
|
# Each of these is a script that reads the tree for a few seconds. They were six
|
|
# workflows and nine jobs (lockfiles, tests-in-ci, workflow-hygiene, wai-section-refs,
|
|
# spec-refs and no-vanity-metrics' four), and each job paid for a container and a
|
|
# checkout to run them. On 2026-10-14 the light checks were about half of the 119 jobs
|
|
# waiting for the linux-arm64 runner, queued behind the long standards-build legs, and
|
|
# spec-refs held a place on the one x86_64 runner. One job runs them all now, one step
|
|
# a check: every step runs even after an earlier one fails (`!cancelled()`), so a red
|
|
# job names each failing check in its own step, and the job fails if any did.
|
|
#
|
|
# The two path filters the old workflows had (public text on Markdown and wai/ sources,
|
|
# section references on the WAI documents) are gone: the checks take seconds, and a
|
|
# filter that is wrong skips a check silently.
|
|
name: repository checks
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
checks:
|
|
name: lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text
|
|
runs-on: linux-arm64
|
|
timeout-minutes: 30
|
|
steps:
|
|
# The whole history: the changelog check diffs a pull request against its base and
|
|
# reads, from the base's first-parent history, when the check reached main
|
|
# (scripts/check-changelog-fragment.py), and it fails rather than pass unchecked when
|
|
# it cannot.
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
|
|
# check-lockfiles.sh runs `cargo` against every lockfile.
|
|
- 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"
|
|
|
|
# ── Every Cargo.lock is current ──────────────────────────────────────────
|
|
- name: "lockfiles: the check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: ./scripts/check-lockfiles-selftest.sh
|
|
- name: "lockfiles: every Cargo.lock is current"
|
|
if: ${{ !cancelled() }}
|
|
run: ./scripts/check-lockfiles.sh
|
|
|
|
# ── No workspace carries an advisory nobody has read ─────────────────────
|
|
# cargo-audit reads the lockfile and the advisory database; it builds
|
|
# nothing. The runner is persistent, so this installs once.
|
|
- name: Install cargo-audit
|
|
if: ${{ !cancelled() }}
|
|
shell: bash
|
|
run: command -v cargo-audit >/dev/null || cargo install cargo-audit --locked
|
|
- name: "advisories: the check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: ./scripts/check-advisories-selftest.sh
|
|
- name: "advisories: every advisory is fixed or allowed with a reason"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I scripts/check-advisories.py
|
|
|
|
# ── Every test file is run by a job or listed with its reason ────────────
|
|
- name: "tests in CI: the check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: ./scripts/check-tests-in-ci-selftest.sh
|
|
- name: "tests in CI: every test file is run or listed, and none can run empty"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I scripts/check-tests-in-ci.py
|
|
|
|
# ── A pull request supersedes its runs, main keeps each; the path gate fails open
|
|
- name: "workflow hygiene: the check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: ./scripts/check-workflow-concurrency-selftest.sh
|
|
- name: "workflow hygiene: every workflow is grouped per ref, a push per commit"
|
|
if: ${{ !cancelled() }}
|
|
run: ./scripts/check-workflow-concurrency.sh
|
|
- name: "workflow hygiene: the path gate fails open (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: ./scripts/pr-touches-paths-selftest.sh
|
|
|
|
# ── One pinned wasmtime, run with both determinism settings ─────────────
|
|
- name: "workflow hygiene: the wasmtime pin check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-wasmtime-pin-selftest.sh
|
|
- name: "workflow hygiene: every wasmtime is the pinned release, run with both determinism settings"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I scripts/check-wasmtime-pin.py
|
|
# ── The release runs the quickstart from each archive it attaches ───────
|
|
# wai-release.yml runs only on a tag, so a change that stops it running the
|
|
# quickstart, or lets it fail, would first be seen at a release. This reads the
|
|
# workflow and the two scripts on every change, for the cost of a few lines of text:
|
|
# it refuses the ways of skipping the run or passing a failed one that its header
|
|
# lists, each planted by the self-test, and reads the text, not what it does.
|
|
- name: "release quickstart: the check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-wai-release-quickstart-selftest.sh
|
|
- name: "release quickstart: each archive runs it before it is attached, and the twin keeps its steps"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I scripts/check-wai-release-quickstart.py
|
|
# The release ships wai/wai-rs/include/wai.h as libwai's public header: a stale commit of
|
|
# it, or a name from outside the C interface's four files, would first be seen there.
|
|
- name: "C header: wai.h declares the C interface's functions, and every name in it is WAI's"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I wai/quickstart/libwai_interface.py
|
|
|
|
# ── Code cites no section its SPEC lacks; WAI's cited sections exist ────
|
|
- name: "spec references: the check can fail (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-spec-refs-selftest.sh
|
|
- name: "spec references: every SPEC citation resolves"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 scripts/check-spec-refs.py
|
|
- name: "section references: every section WAI's documents cite exists"
|
|
if: ${{ !cancelled() }}
|
|
run: python scripts/check-wai-section-refs.py
|
|
|
|
# ── JCP's published replay log reads the same to a second reader ────────
|
|
- name: "jcp replay log: a second reader restores the published ledger and refuses every planted fault"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I jcp/conformance/verify_replay.py --selftest
|
|
|
|
# ── …and so does the life of a money hold ───────────────────────────────
|
|
- name: "jcp hold lifecycle: a second reader restores captures, reclaims and refunds, and refuses each broken rule"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I jcp/conformance/verify_lifecycle.py --selftest
|
|
|
|
# ── Every wai.quantum string is registered, listed or a schema's name ────
|
|
# The registry export (wai/registry/capabilities.json, generated from
|
|
# wai/wai-rs/src/codecs/registry.rs) and the quantum crates' schema files are the
|
|
# lists; this reads them and every text file, and names the file and line of any
|
|
# string neither accounts for (wai/REGISTRY.md).
|
|
- name: "quantum names: the check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-wai-quantum-names-selftest.sh
|
|
- name: "quantum names: every wai.quantum string is registered, listed or a schema's name"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I scripts/check-wai-quantum-names.py
|
|
|
|
# ── The lists wai-conformance.yml derives hold the hand lists they replaced ─
|
|
# Its feature lists, test lists, verifier steps, corpora and gate paths are read from
|
|
# the files that own them (.github/wai-conformance/, the tags of wai/wai-rs/tests/).
|
|
- name: "workflow lists: the derivation fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/wai-conformance-lists-selftest.sh
|
|
- name: "workflow lists: every derived list holds every entry of the hand list it replaced"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I scripts/wai-conformance-lists.py selftest
|
|
|
|
# ── A change to WAI carries its changelog entry, in a file of its own ──────
|
|
# wai/changes/README.md states the form; the entries go into wai/CHANGELOG.md at a
|
|
# release (scripts/changelog-assemble.py). A pull request opened before the check
|
|
# reached main passes as it is; the check reads when it was opened from the event
|
|
# payload, and when the check reached main from the base's first-parent history.
|
|
- name: "changelog: the check and the assembler fail closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/changelog-fragments-selftest.sh
|
|
- name: "changelog: every entry file is one entry in the changelog's form"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I scripts/changelog-assemble.py --check
|
|
- name: "changelog: a change to wai/ adds its entry (pull request)"
|
|
if: ${{ !cancelled() && github.event_name == 'pull_request' }}
|
|
run: |
|
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
python3 -I scripts/check-changelog-fragment.py \
|
|
"${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}"
|
|
|
|
# ── WAI's core changes only by an erratum, a candidate re-pin or a version bump ──
|
|
# wai/CORE.md names the core 1.0 candidate; wai/core/lock.json pins each core item (a
|
|
# marked span of SPEC.md or an extension, a core capability's or wire identifier's
|
|
# registry entry, a pinned corpus's data) by its digest. A core item changed with no
|
|
# erratum in wai/CORE-ERRATA.md, no re-pin of the candidate and no core version bump
|
|
# fails; so do a core item removed, an unknown marked span and an extension in no
|
|
# profile. Read against the commit the change starts from (a pull request's base, or the
|
|
# commit a push to main came after), a lock rewritten without a bump or a re-pin, a
|
|
# re-pin without its dated note naming each changed item, and an erratum edited or
|
|
# removed fail too.
|
|
# Profiles change freely. The self-test plants each fault and each change that passes.
|
|
- name: "WAI core: the freeze check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-wai-core-freeze-selftest.sh
|
|
- name: "WAI core: every core item is as pinned, or has its erratum or a version bump"
|
|
if: ${{ !cancelled() }}
|
|
run: |
|
|
set -euo pipefail
|
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
if [ "${{ github.event_name }}" = pull_request ]; then
|
|
base="${{ github.event.pull_request.base.sha }}"
|
|
else
|
|
base="${{ github.event.before }}"
|
|
git rev-parse --verify --quiet "${base}^{commit}" > /dev/null || base=$(git rev-parse HEAD~1)
|
|
fi
|
|
python3 -I scripts/check-wai-core-freeze.py --against "$base"
|
|
|
|
# ── A rule committed before the runs it judges stays as it first reached main ──
|
|
# A research record's rule (wai/research/<record>/*-rule*.json) is worth what it is
|
|
# because it was fixed before the data, and a rule changed together with every copy of
|
|
# its digest passes every check that reads the tree alone. This reads the first-parent
|
|
# history from the start, so a cancelled run hides nothing: the next run finds the same
|
|
# change. The step below runs scripts/check-frozen-rules.sh as it first reached the
|
|
# history and as it stands, and that script runs scripts/check-frozen-rules.py the same
|
|
# way, so an edit of either script hides no change to a rule. The step itself is read
|
|
# from the commit under test: a commit that edits it silences this check from then on,
|
|
# until that edit is undone, and the diff in the history records it. A pull request is
|
|
# also compared with its base. The self-test runs the step's text from its marker on.
|
|
- name: "frozen rules: the check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-frozen-rules-selftest.sh
|
|
- name: "frozen rules: every rule file is as it first reached main"
|
|
if: ${{ !cancelled() }}
|
|
run: |
|
|
set -euo pipefail
|
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
if [ "${{ github.event_name }}" = pull_request ]; then
|
|
set -- "${{ github.event.pull_request.head.sha }}" "${{ github.event.pull_request.base.sha }}"
|
|
else
|
|
set -- "${{ github.sha }}"
|
|
fi
|
|
# frozen rules: the runner as it first reached the history, then as it stands.
|
|
runner=scripts/check-frozen-rules.sh
|
|
first_add() { git log --first-parent -m --diff-filter=A --format=%H "$1" -- "$runner" | tail -n 1; }
|
|
first=$(first_add "$1" || true)
|
|
if [ -z "$first" ] && [ $# -eq 2 ]; then first=$(first_add "$2" || true); fi
|
|
if [ -z "$first" ]; then
|
|
echo "::error::frozen rules: no commit of the first-parent history of $* adds $runner"
|
|
exit 1
|
|
fi
|
|
copy=$(mktemp)
|
|
git show "$first:$runner" > "$copy"
|
|
rc=0
|
|
echo "frozen rules: the runner as it first reached this history, in $first"
|
|
bash "$copy" "$@" || rc=1
|
|
echo "frozen rules: the runner as this checkout holds it"
|
|
bash "$runner" "$@" || rc=1
|
|
rm -f "$copy"
|
|
exit $rc
|
|
|
|
# ── Public text: no vanity metrics, no comparison, no company names ─────
|
|
- name: "public text: no vanity metrics in committed Markdown"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-no-vanity-metrics.sh
|
|
- name: "public text: the two public-text checks fail closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/test-public-text-checks.sh
|
|
- name: "public text: WAI's public text names no comparison"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-comparative-prose.sh
|
|
# The maintainers' product names are public, held in the script itself: this run
|
|
# reads no secret, so it checks every change, a pull request included.
|
|
- name: "public text: WAI's public text names no product of its maintainers"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-public-names.sh --maintainer-products-only
|
|
# NOTICE states WAI's licence from the repository's root, outside the check's default
|
|
# scope, so it is given by name. The rest of its wording is reviewed by hand.
|
|
- name: "public text: the root NOTICE names no product of WAI's maintainers"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-public-names.sh --maintainer-products-only NOTICE
|
|
# The pattern list is a secret, never given to pull-request code: the check runs
|
|
# on the push to main.
|
|
- name: "public text: WAI's public text names no company or product (push to main)"
|
|
if: ${{ !cancelled() && github.event_name != 'pull_request' }}
|
|
env:
|
|
WAI_NAME_DENYLIST: ${{ secrets.WAI_NAME_DENYLIST }}
|
|
run: |
|
|
if [ -z "$WAI_NAME_DENYLIST" ]; then
|
|
echo "::error::WAI_NAME_DENYLIST is not set: the public-name check cannot run"
|
|
exit 1
|
|
fi
|
|
bash scripts/check-public-names.sh
|
|
bash scripts/check-public-names.sh NOTICE
|
|
|
|
# ── Every vector of a corpus that keeps licence records has one ──────────
|
|
- name: "corpus licences: the check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: bash scripts/check-wai-corpus-licences-selftest.sh
|
|
- name: "corpus licences: every vector has a record and a licence that permits redistribution"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I scripts/check-wai-corpus-licences.py
|
|
|
|
# ── Our MoQ catalogs are MSF's, and use only what the MSF packaging draft defines ──
|
|
# wai/ietf/catalog_check.py holds every catalog writer's committed catalogs (the
|
|
# packager's corpus, which the wai-pack workflow recomputes from the packager, and
|
|
# the samples the ingest gateway's, the remote host's, the interop client's and the
|
|
# room page's tests hold them to) to draft-charlot-moq-wai-packaging-01 (its
|
|
# packaging values and its "wai" and "wai-link" track fields) and, with --strict, to
|
|
# MSF's and CMSF's own rules (the version string, isLive, an event timeline's fields,
|
|
# initRef and initDataList). The self-test plants each fault it refuses in a copy of
|
|
# a real catalog.
|
|
- name: "MoQ packaging draft: the catalog check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I wai/ietf/catalog_check.py --selftest
|
|
- name: "MoQ packaging draft: our catalogs are MSF's and use only the packaging values and fields it defines"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 -I wai/ietf/catalog_check.py --strict
|
|
|
|
# ── No library source file is unreachable from its crate root ───────────
|
|
# An orphan `.rs` (one no `mod`, `#[path]` or `include!` names) is never compiled,
|
|
# so nothing else in this repository can see it. Both directions, before trusting
|
|
# the result: a planted orphan must fail the check, and removing it must pass.
|
|
- name: "orphan sources: the check fails closed (self-test)"
|
|
if: ${{ !cancelled() }}
|
|
run: |
|
|
set -euo pipefail
|
|
probe=jcp/jcp-rs/crates/jcp-efficiency/src/_ci_orphan_probe.rs
|
|
printf 'pub fn never_compiled() -> u64 { 0 }\n' > "$probe"
|
|
if python3 scripts/check-orphan-sources.py >/dev/null 2>&1; then
|
|
rm -f "$probe"
|
|
echo "::error::the orphan check passed with a planted orphan present"
|
|
exit 1
|
|
fi
|
|
rm -f "$probe"
|
|
- name: "orphan sources: no new orphan source files"
|
|
if: ${{ !cancelled() }}
|
|
run: python3 scripts/check-orphan-sources.py
|