open-standards/wai/CONTRIBUTING.md
Transaction Science 946f3beda9
All checks were successful
joule-moq-remote host agent / joule-moq-remote · does this change touch it (pull_request) Successful in 6s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 7s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 6s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 6s
wai-audit collector and player integration / does this change touch it (pull_request) Successful in 6s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (pull_request) Successful in 6s
WAI operation catalogue / does this change touch it (pull_request) Successful in 6s
WAI conformance / does this change touch it (pull_request) Successful in 6s
WAI energy receipts / does this change touch it (pull_request) Successful in 5s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 6s
wai-fleet service / does this change touch it (pull_request) Successful in 6s
WAI JPEG-AI whole decode (pinned inputs, required) / does this change touch it (pull_request) Successful in 7s
wai-ledger service / does this change touch it (pull_request) Successful in 6s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 1m25s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 6s
wai-quantum for JavaScript / does this change touch it (pull_request) Successful in 6s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 6s
wai-sink-android native sink library / does this change touch it (pull_request) Successful in 6s
wai-sink-swift native sink package / does this change touch it (pull_request) Successful in 6s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 1m57s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 2m7s
WAI Studio / does this change touch it (pull_request) Successful in 6s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 6s
wai-web wasm32 / does this change touch it (pull_request) Successful in 6s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 29s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (pull_request) Successful in 2m1s
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (pull_request) Successful in 2m59s
wai-audit collector and player integration / collector · linux (pull_request) Successful in 1m1s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 26s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 4m19s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 16s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 1m4s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (pull_request) Successful in 1m15s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 5m15s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 6m19s
wai-fleet service / service · macos (pull_request) Successful in 1m2s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (pull_request) Successful in 2m46s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 1m43s
wai-ledger service / service · macos (pull_request) Successful in 1m24s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 1m2s
WAI operation catalogue / the catalogue and every door · linux (pull_request) Successful in 4m18s
wai-quantum studio and desktop / desktop app · windows (pull_request) Successful in 9m19s
wai-pack / wai-pack · macos (pull_request) Successful in 3m8s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 30s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 7m49s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 3m23s
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Successful in 1m39s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 3m9s
wai-fleet service / service · linux (pull_request) Successful in 2m5s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 3m28s
wai-ledger service / service · linux (pull_request) Successful in 1m43s
wai-pack / wai-pack · linux (pull_request) Successful in 1m55s
wai-quantum for JavaScript / javascript · linux (pull_request) Successful in 3m0s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Successful in 1m10s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 16m12s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 11m32s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (pull_request) Successful in 4m51s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 13m12s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 15m2s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 4m3s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 16m34s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m40s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 17m22s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m44s
wai-quantum studio and desktop / desktop app · linux (pull_request) Successful in 5m46s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 34s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 17s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 9m28s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 5m7s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 14m49s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m34s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Successful in 2m16s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 11m4s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 13m6s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 5m58s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 10m55s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 9m51s
WAI Studio / Studio in WebKit · linux (pull_request) Successful in 10m15s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 9m21s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 30m14s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h4m7s
Changelog entries and the conformance workflow's lists move into files a change adds
Every change to WAI added an entry at the head of wai/CHANGELOG.md, and every new module
appended to the hand-kept lists of .github/workflows/wai-conformance.yml. So any two
branches conflicted on those lines and had to merge one after another. This moves both into
files a change adds.

- Changelog entries: a change adds wai/changes/<yyyy-mm-dd>-<slug>.md holding the entry
  text. scripts/changelog-assemble.py renders the entries into CHANGELOG.md's Unreleased
  section for a release, in a stable order. scripts/check-changelog-fragment.py, run by
  repo-checks on every pull request, fails a pull request that changes wai/ and adds or
  edits no entry file directly in wai/changes/ (a release passes, and so does a commit
  with the trailer line "Changelog: none"). A pull request opened before the check reached
  main passes as it is; one opened after it that adds its entry to the head of Unreleased
  fails and is told where the entry goes. wai breaking reads breaking changes from entry
  files too.
- The conformance workflow: each per-module verifier step is a file in
  .github/wai-conformance/verifiers/, each corpus a file in corpora/, and the
  integer-kernel tests carry a tag line. scripts/wai-conformance-lists.py derives every
  list the workflow kept by hand (WAI_FEATURES, the union --bin and --test lists, the
  features-alone lists, the kernel and corpus steps) from those files when the workflow
  runs. Its `selftest --exact` holds the derived lists to the hand lists of the commit
  before this one, and its dry-run prints every command each job runs: the dry-runs before
  and after this change differ only in the gate's path list, which gains the two paths this
  change adds.
- What stays shared, and how to insert there, is written in wai/CONTRIBUTING.md and
  wai/changes/README.md: wai-rs Cargo.toml features and [[test]] entries, lib.rs, registry
  rows, wai/.gitattributes and the live corpus table take an insert beside the related
  entry, never at the end.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-05 01:41:29 -05:00

189 lines
11 KiB
Markdown

# Contributing to WAI
WAI is a specification ([`SPEC.md`](SPEC.md) and its [`extensions/`](extensions/))
with a reference implementation in Rust ([`wai-rs/`](wai-rs/), with
[`wai-quantum/`](wai-quantum/) and the browser crate [`wai-web/`](wai-web/)). Both
are pre-1.0 drafts: substantive changes are welcome.
The canonical repository is the forge at
`https://git.transaction.science/Transaction-Science/open-standards`. Send changes
there; mirrors of it are read-only.
## To the specification
A change is in scope if it:
- names a real ambiguity in the text (point at the section and the case that
breaks);
- adds a missing structural requirement (byte layout, conformance rule, dispatch
behaviour) needed to make another implementation falsifiable;
- registers a capability with a byte-precise payload format and conformance
vectors, not a placeholder (see *Registering a capability*, below).
A change is out of scope if it adds optional fields with no testable conformance
effect. §8 says what a revision may change: a registered capability's payload
format and role are fixed once registered, and a later edition of a standard that
changes its bitstream takes a new capability string.
## Registering a capability
[`REGISTRY.md`](REGISTRY.md) states the procedure: add the string to the registry
table in `wai-rs/src/codecs/`, register it in SPEC §5 under the same heading, run
`wai registry export`, and link it from the codec glossary or list it there as
having no entry. The tests hold SPEC, the registry and the exported files to the
same set of strings.
## To the reference implementation
### Building
The default `codecs` feature links system codec libraries (libjxl, libavif,
libopus, libdav1d, liblzma, libflac); without them the build stops in a codec
crate's build script. Everything else builds without them, and CI builds that way:
```bash
cd wai-rs
cargo test --lib --no-default-features --features world,audio_scene,haptic,splat4d,score,provenance,neural_int,film
cargo run --no-default-features --bin wai -- capabilities
```
Name the features a change touches explicitly; `cargo test` with the defaults is
not what CI runs.
### Tests that CI must see
- A test file gated on a feature (`#![cfg(feature = "...")]`) compiles to an empty
binary, which reports success, in any build without that feature. Declare it in
`wai-rs/Cargo.toml` with a `[[test]]` stanza and `required-features`, and add
`--test <name>` with the right `--features` to a step in
`.github/workflows/`, or to a verifier step's own file (below), or tag the file for
the fast integer kernels' steps (below). A test no workflow names runs nowhere.
- A test that reads inputs from outside the tree skips without them. CI sets
`WAI_REQUIRE_SOTA_VECTORS=1` where it provides them, and a missing input then
fails.
- Falsify every new test once: change the code it guards, show it fails, restore
the code through git, and show it passes again.
### Vectors
Committed conformance vectors and pinned hashes change only through their
generator (the `wai_*_vectors gen` binaries and the export tools in
[`tools/`](tools/)), never by hand. A test whose comment says its hex must never
be edited to make it pass means exactly that.
### Corpus content: where it comes from
Corpus content is generated in this repository, by a generator from a seed or a
formula, or it is an input whose source and licence are recorded and whose licence
permits redistribution. An image, a recording or footage that was not made here and
has no such licence is not committed, as content or as training data.
Every corpus states its provenance: each `*-conformance/README.md` in a line that
begins `**Provenance.**`, and `wai-rs/tests/vectors/README.md` in a row for each
vector directory. The line names the generator and its input, and for an input not
generated here, its source and licence. A word such as "synthetic" is not a
provenance line. `wai-rs/tests/corpus_provenance.rs` requires the line in every
corpus, and `tools/wai_audio_provenance_check.py`, which CI runs, fails when a
committed audio vector correlates with a reference recording the host has.
### Independent implementations
Conformance is defined by the committed corpora (`*-conformance/`) and the
criteria of SPEC §7, not by agreement with this implementation's own tests. A
second implementation in another language is validated against the same corpora;
the OER receipt kernel in C (`oer-conformance/settle/`) is one.
## Changes that add files rather than append to shared lines
Many changes are open here at once, and a line two of them edit is a conflict that holds
one of them back. So a change adds files of its own where the tree lets it (its changelog
entry, and its lists in the conformance workflow), and in a file that stays shared it
inserts beside the entry it builds on:
- **Its changelog entry** is a new file, `changes/<yyyy-mm-dd>-<slug>.md`, holding the
entry as the changelog does ([`changes/README.md`](changes/README.md)). It does not
edit the head of `CHANGELOG.md`. The repository checks require a change under `wai/` to
add or edit an entry file directly in `changes/` (a release, which renders the files and
removes them, passes), or to carry the trailer line `Changelog: none`, exactly, in the
trailer block of one of its commit messages. A pull request opened before the check
reached main passes as it is; one opened since that adds its entry to the head of
`CHANGELOG.md` fails.
- **A step of the independent verifiers** in `wai-conformance.yml` is a new file,
`.github/wai-conformance/verifiers/<name>.sh`: the step's shell body, run in `wai/`,
under a header of `# key: value` lines. `# step:` names it and `# order:` places it;
`# features:` brings its features into `WAI_FEATURES` and its lists into the
features-alone job; `# paths:` brings the extension text it reads into the paths the
workflow's gate runs on (the trigger takes all of `extensions/`; a path under none of the
trigger's paths still needs a line there, which `check` names); `# bins:` and
`# release-features:` cover the rest, and every `--test` it runs with `"$WAI_FEATURES"`
joins the job's first build. `scripts/wai-conformance-lists.py`
states every key; `python3 scripts/wai-conformance-lists.py dry-run` prints every list
and step the workflow runs, and `run --only <name>` runs one step.
- **A cargo-class corpus** is a new file of `.github/wai-conformance/corpora/`, naming
its tool and directory. **A test of the fast integer kernels** carries the first line
`// wai-conformance: int-kernels` (with `int-kernels-amd` when the AVX-512 host runs it
too, or `int-kernels-release` alone when only the release step does), and the steps take
its required features from `Cargo.toml`.
- **A file every change still shares** takes a new entry beside the entry it builds on,
never at the end, and is not re-sorted. `wai-rs/Cargo.toml`'s `[features]`, `[[bin]]`
and `[[test]]` tables, `wai-rs/src/lib.rs`'s `mod` lines and the tables of
`wai-rs/src/codecs/registry.rs` are grouped by topic, not sorted: a feature goes after
the feature it depends on, a target after its sibling's, a module after the module it
extends. `registry/capabilities.json`, the registry table of `REGISTRY.md` and
`vocab/v2.*` are generated from `registry.rs` in sorted order, so a new row lands at its
sorted place: never edit them by hand, and on a conflict in one take either side and run
`wai registry export` again.
- **`.gitattributes`.** A corpus whose bytes must never be converted gives its own
directory a `.gitattributes` (`* -text`), as `pin-conformance/` and
`live-conformance/scene/` do (a verifier that lists its directory's files must admit
that one, as `scene_verify.py` does), and adds no line to `wai/.gitattributes`. A
pattern only that file can hold goes beside the line it is most like, with its comment,
never at the end.
- **The corpus table of `live-conformance/README.md`**, and the list of verifier commands
under it, take a new row beside the row of the extension it builds on or extends (a
delivery record beside its delivery sibling, a live extension beside its live sibling),
never at the end. The table is written by hand: its rows name sections, schemes and
generators that no file of the corpora states.
## Public text
The specification, the extensions, READMEs, research notes, code comments and
the CHANGELOG state what WAI does, plainly:
- name no company, vendor, customer or commercial product. Standards, standards
bodies, protocols, papers and open-source projects may be named, factually;
- make no comparisons with other products or approaches;
- give no counts that drift (crate counts, test counts, line counts).
Three checks enforce this. `scripts/check-no-vanity-metrics.sh` (opt-out marker
`allow-vanity: <reason>`) and `scripts/check-comparative-prose.sh` (opt-out
`allow-phrase: <reason>`, for an identifier or a quotation) run on every change.
`scripts/check-public-names.sh` holds the names of the maintainers' products
that their public site names in the script itself, since they are public
already, and checks them on every change (`--maintainer-products-only`). Its
other patterns are a private list (the `WAI_NAME_DENYLIST` secret in CI, given
only to the run on a push to main, so a pull request is checked against that
list when it lands). A functional identifier — a capability string, a model-hub
id a tool defaults to, a repository URL, an OS API name, a security advisory
id — is kept and its line marked `allow-name: <reason>`. Put the marker in a
comment of the file's own syntax (`<!-- ... -->`, `// ...`, `# ...`); the reason
must contain a letter or a digit. JSON has no comments, so a JSON file carries
no such identifier: the codec glossary titles a format by its own name, FourCC,
file extension or designation, and never by a company, a product or a person
([`glossary/SCHEMA.md`](glossary/SCHEMA.md)). The checks fail closed: a pattern
that does not compile, or any grep error, fails them, and
`scripts/test-public-text-checks.sh` proves that on every run.
Dated research records are not rewritten: a correction is a dated annotation
after the original text, and a name is redacted in place with a dated marker.
## Licence
The specification and the reference implementation are Apache-2.0. By
contributing, you agree your contribution is licensed under the same terms. Each
payload and companion capability carries a licence class (royalty-free,
patent-pool, proprietary, non-commercial) for implementing it, recorded in the
registry; derivations carry the class `codecs::derivation` gives them; records
carry none. Companion implementations outside this tree keep their own licences.
No CLA. The licence is the agreement.