open-standards/wai/VERSIONING.md
Transaction Science 6d30693eb2
Some checks failed
WAI operation catalogue / does this change touch it (push) Successful in 19s
wai-fleet service / does this change touch it (push) Successful in 14s
wai-key-proxy / does this change touch it (push) Successful in 13s
wai-ledger service / does this change touch it (push) Successful in 15s
wai-quantum for JavaScript / does this change touch it (push) Successful in 15s
wai-quantum studio and desktop / does this change touch it (push) Successful in 12s
wai-sink-android native sink library / does this change touch it (push) Successful in 18s
wai-sink-swift native sink package / does this change touch it (push) Successful in 14s
WAI Studio / does this change touch it (push) Successful in 13s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Failing after 3m45s
wai-app and Create / wai-app · does this change touch it (push) Successful in 3m15s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 3m18s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 3m26s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 3m28s
wai-audit collector and player integration / does this change touch it (push) Successful in 3m15s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 11s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 7s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 5m57s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 6m47s
wai-key-proxy / proxy · linux (push) Successful in 1m41s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 7m55s
wai-fleet service / service · linux (push) Successful in 3m55s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 50s
wai-fleet service / service · macos (push) Successful in 39s
wai-ledger service / service · linux (push) Successful in 3m24s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m50s
wai-quantum for JavaScript / javascript · linux (push) Successful in 4m55s
wai-ledger service / service · macos (push) Successful in 56s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 9m1s
wai-quantum studio and desktop / studio · browser (push) Successful in 5m40s
wai-audit collector and player integration / collector · linux (push) Successful in 2m25s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 1m42s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 12m34s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 9m12s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 5m34s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 7m6s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 8m6s
WAI Studio / Studio in WebKit · linux (push) Successful in 16m11s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 13m11s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 9m47s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 10m54s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 16m53s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 49s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m6s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 8m3s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 9m22s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 20m47s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 6m19s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 22m54s
WAI core 1.0 candidate: the core named and pinned, its freeze checked, profiles versioned apart
Chips, players and services cannot build on a specification that changes
several times a day. The core, the part meant to stop moving, is now named,
pinned and held: the envelope (WAI1, WAI2), the manifest, capability
dispatch, the model pin, receipts and the determinism tiers, with the
floor capabilities, record formats and conformance suites they need.
Everything else is a profile with its own version.

- wai/CORE.md names the core: spans of SPEC.md and of five extensions between
  <!-- wai-core:begin/end <id> --> markers (determinism-tiers §2,
  prior-carriage §2, jwp-receipts' delivery receipts, claim envelope, binary
  form, verifier, relay rules and key discovery, energy-measurement §2.7,
  conformance-results); the mandatory floor, video floor, recommended set and
  wai.prior.set; the envelopes' magics, the key log and module records and
  conform-result/1; and the suites that hold them. Each core-to-profile
  reference was read and is informative or binds only an implementation of
  that profile; what still resists the split is listed there.
- wai/core/lock.json pins each item by SHA-256; wai/core/profiles.json gives
  each of thirteen profiles its version (0.1), its extensions and the core
  items it builds on; wai/CORE-ERRATA.md is the errata list.
- scripts/check-wai-core-freeze.py fails a change to a core item unless it is
  an erratum row with the item's new digest or the core version is raised and
  the lock rewritten; against the commit a change starts from, it also fails
  a lock rewritten without a bump and an erratum edited. It runs in the
  repository checks after its self-test, which plants each fault and each
  change that must pass.
- SPEC.md, wai/README.md, VERSIONING.md, CONTRIBUTING.md and the repository's
  README say the core is a 1.0 candidate and profiles are versioned
  separately. Not a release: 1.0 is declared by the maintainers.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-10 13:42:23 -05:00

9.4 KiB

The WAI toolchain: versions, stability and deprecations

This page says what anyone building on the wai command line can rely on: which parts are public, what a version number promises about each, and how a change is announced before it happens. It covers the wai binary, the operation catalogue and the doors the catalogue names. WAI Quantum's packages have their own page, wai-quantum/VERSIONING.md.

The deprecated items, each with the version that deprecated it and its replacement, are listed in DEPRECATIONS.md.

One version

wai, the standard's text and the reference implementation are released together, under one version: the wai crate's (wai-rs/Cargo.toml). The newest release heading of CHANGELOG.md names it, the catalogue's export carries it, and a test holds the three equal, so a version can be read from the binary and never has to be read from a page:

wai --version --json
Member What it says
toolchain This binary's version
catalogue The export's format, its operations, and the SHA-256 of wai ops export, which is catalogue/ops.json byte for byte
envelope The version of the JSON envelope --json prints
registry The registered capabilities, and the SHA-256 of registry/capabilities.json
specification The release of the standard this binary implements, and the envelope formats it reads
features The build features the catalogue names that this binary was built with, which decide the operations it holds

What is public

Surface What is public What holds it in CI
The operation catalogue Each operation's id, its command line and declared aliases, its flags and arguments, its effect, when it waits for confirmation, its stability and the schema of its --json data: catalogue/ops.json, which wai ops schema <id> prints one entry of wai ops export --check, and the catalogue's rules (wai-catalogue.yml); wai breaking, category api (surface catalogue, wai-breaking.yml)
The agent rules The exit codes, the envelope envelope/1, its error.code strings, --json, --dry-run, --yes and --no-input wai-rs/tests/cli_ops.rs
The MCP door Each tool's name, the operation of the catalogue it is, and its input schema: catalogue/mcp.json, which the binary's tests hold to the tools wai mcp serves wai-rs/tests/cli_mcp.rs and the binary's tests, in wai-conformance.yml; scripts/check-wai-ops-doors.py; wai breaking, category api (surface catalogue)
The project file wai.json, as schema/wai-json-1.schema.json and, for version 2 (version 1 and breaking), schema/wai-json-2.schema.json state it The reader's tests, which hold the reader to both
The lock and the build record wai.lock and wai-build.json, as schema/wai-lock-1.schema.json and schema/wai-build-1.schema.json state them, and the lock's bytes in project-conformance/ wai-rs/tests/cli_project.rs and the second reader, project_verify.py, in wai-conformance.yml
The C ABI, the Rust API of the library crates, the JavaScript, Swift and Kotlin APIs and the HTTP services' OpenAPI documents wai.h, what the crates document, the browser packages' bindings (wai-web, wai-live-web), the native sinks' public declarations (wai-sink-swift, wai-sink-android), and each document's operations wai breaking, category api (wai-breaking.yml)
The wire and the signed records The registry's capabilities and wire identifiers, the conformance corpora, the signing domains and the published JSON Schemas wai breaking, categories wire and record, and the corpora's generators and verifiers

What is not public: the text a command prints without --json, which is for people and may change in any release; an operation marked internal, which is never published; and the keystore's own files (wai.key/1), which only wai key reads and writes.

An operation's stability says how far its entry is promised. A stable operation changes only with a deprecation window. A preview operation is published and works, and its shape may still change: a change to one is in the changelog, and the window below is not owed.

What a version number promises

The toolchain follows Semantic Versioning 2.0. Every release so far is 0.y.z, for which that promises nothing, so this page does: the first non-zero component is the major.

  • A change of y (0.4.0 to 0.5.0) may break a public surface. Every break is in the changelog with what to do instead, and the deprecation rule below holds for a stable operation.
  • A change of z adds or fixes, and breaks nothing a public surface promised.

The wire format is the exception the standard states. Its core (CORE.md: the envelope, the manifest, dispatch, the model pin, receipts and the determinism tiers) is a core 1.0 candidate, which changes only by an erratum or a raised core version, under a check that runs on every change. Everything else is a profile, versioned on its own in core/profiles.json, and may change, with each change recorded in the changelog.

Deprecation

A renamed command, flag, route or tool stays as an alias for at least two minor releases and six months, and says it is deprecated when used. Removing it after that is a break, in the changelog with what to do instead.

Where it is used How a deprecated item says so
A flag on the command line It still works, and prints one line on standard error: wai: deprecated: --confirm, use --yes instead
An operation's id or spelling Its catalogue entry's deprecated member (since, use_instead)
Help and the catalogue's export wai --help and each operation's help name it, and agent_flags lists it with deprecated
The list DEPRECATIONS.md, from the release that deprecates it

A test holds DEPRECATIONS.md to the catalogue: every flag and operation the catalogue marks deprecated is listed there, and every item listed there is marked in the catalogue or has its removal named.

How a break is acknowledged

wai breaking --against <git-ref> reports what the working tree breaks, by category, and exits 1 on a break the changelog does not acknowledge. A change acknowledges one with a **Breaking:** line naming the finding's id in backticks, in its entry under changes/. CI runs it on every pull request that touches WAI, and on every push to main that does.

The catalogue is read as this page promises it:

  • A change to a stable operation, its flags, its --json output or its MCP tool is a break.
  • A change to a preview operation is no break, and is owed a line: the change's entry names the finding's id in backticks, with or without the word "breaking". Without one the run fails.
  • A stable name the catalogue can keep under its old spelling (an operation's id, kept as a deprecated operation; a flag, kept as a deprecated alias; --confirm) renamed with the old one kept, deprecated, is no break. Removing the old one is a break a line acknowledges only once its window has closed: two minor releases after the release that deprecated it, read from the export's version, and six months after that release's tag (wai-v<version>). Removing it before then, or removing a stable name that was never deprecated, is a break no line acknowledges, and the run says so: keep the old name, deprecated, until its window closes.

A project's breaking changes

wai breaking runs on any project, in its directory (one with wai.json) or with --project <dir>, against the project at a git ref (--against <ref>) or as it was published (--baseline <dir>: the project's directory, or its package alone, as served). It compares:

  • The package wai build wrote under dist/, as the sinks that play it are configured for it (category wire): a class of the packaging policy that is gone, or whose playlists or stage view are gone, or whose objects need a capability they did not, is a break for the sinks set up with that class; so is a floor codec the classical presentation no longer offers, and a MoQ track a subscriber named that is gone or changed. A class that now takes the floor alone is no break: its sinks still play. A run with no package to compare with on either side stops (exit 5); it does not pass what it did not compare.
  • The API the project names under breaking.api in wai.json: JavaScript and TypeScript modules, Swift and Kotlin sources, OpenAPI documents and JSON Schemas, each read by its kind.

A project accepts a break in wai.json, with the reason it is accepted, which the report gives beside the finding; an entry with no reason is refused with the file. breaking is a member of the project file's version 2, which says so, so that a wai that reads version 1 alone refuses the file as a later version:

{ "$schema": "https://wai.transaction.science/schema/wai.json/2", "wai": 2,
  "breaking": { "api": ["sdk/index.d.ts"],
                "allow": [{ "id": "api:js:sdk/index.d.ts:play", "reason": "renamed start in 2.0; call start" }] } }