open-standards/.github/workflows/wai-quantum-contract.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

311 lines
16 KiB
YAML

name: wai-quantum contract
# The version and deprecation contract (wai/wai-quantum/VERSIONING.md), on
# Linux:
#
# - api: cargo-semver-checks, built from crates.io at a pinned version,
# compares wai-quantum, wai-quantum-cli and wai-quantum-qpu with the last
# version of each on crates.io (the baselines below). It checks every change as if for a minor
# release, so that each breaking change is listed, and fails only on a
# breaking change made without a major bump. Before 1.0 the first non-zero
# component is the major (0.6.16 to 0.7.0 is a major bump). A step warns
# when crates.io holds a newer version than a baseline here, so a baseline
# does not go stale unseen.
# - schemas: the schema tests, each by name. The engine's: every schema file
# reads and names itself, every method's job, a set, a result's provenance,
# every error-correction answer, a mitigated job, every answer of the
# variational and algorithm library and every engine tool's
# answer follow their schemas with no member they do not name, and receipts issued
# before results named their engine and schema still verify, their digests
# pinned. Both MCP servers': every tool's answer follows its outputSchema,
# the committed tool lists (wai-quantum-cli/docs/local-mcp.json and
# service-mcp.json) are the live lists, the agent docs are what the binary
# generates, and initialize reports the versions. The job service's job in
# each status, a set's among them, and its receipt key set after a rotation;
# the command line's scheduler lease, its harness's report, corpus and token
# counts, and the course's progress file; the answer layer's documents, a
# correctness record, the views page's manifest, the course, its exercises
# and its checks. The provider protocol's messages and
# answers. Then a full
# JSON Schema implementation (wai/wai-quantum/ci/check_schemas.py) reads
# every schema file and both tool lists, and holds a release build's
# answers to them.
# - policy: every README of a WAI Quantum package links the policy, and the
# deprecations page's table is well formed.
#
# The receipts' legacy pins and the conformance corpora run where they always
# have (wai-energy-receipts.yml, wai-conformance.yml).
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches: [main]
paths:
- 'wai/wai-quantum/**'
- 'wai/wai-quantum-cli/**'
- 'wai/wai-quantum-service/**'
- 'wai/wai-quantum-qpu/**'
# The schema tests read the answer layer's conformance set and the harness's corpus.
- 'wai/quantum-conformance/answers/**'
- 'wai/quantum-conformance/eval/**'
- 'wai/wai-quantum-py/README.md'
- 'wai/wai-quantum-desktop/README.md'
- 'wai/quantum-studio/README.md'
- 'wai/tools/wai-quantum-editor/README.md'
- 'wai/tools/tree-sitter-openqasm/README.md'
- 'rust-toolchain.toml'
- '.github/workflows/wai-quantum-contract.yml'
pull_request:
paths:
- 'wai/wai-quantum/**'
- 'wai/wai-quantum-cli/**'
- 'wai/wai-quantum-service/**'
- 'wai/wai-quantum-qpu/**'
# The schema tests read the answer layer's conformance set and the harness's corpus.
- 'wai/quantum-conformance/answers/**'
- 'wai/quantum-conformance/eval/**'
- 'wai/wai-quantum-py/README.md'
- 'wai/wai-quantum-desktop/README.md'
- 'wai/quantum-studio/README.md'
- 'wai/tools/wai-quantum-editor/README.md'
- 'wai/tools/tree-sitter-openqasm/README.md'
- 'rust-toolchain.toml'
- '.github/workflows/wai-quantum-contract.yml'
jobs:
# Does this pull request's own diff touch the paths above? 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, 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-quantum-contract.yml \
"${{ github.event.pull_request.base.sha }}" \
"${{ github.event.pull_request.head.sha }}")
echo "this change touches the wai-quantum contract: $r"
echo "run=$r" >> "$GITHUB_OUTPUT"
api:
name: API compatibility · linux
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: linux
timeout-minutes: 60
env:
# The last version of each on crates.io. Raise each when a release is published.
WAI_QUANTUM_BASELINE: "0.8.0"
WAI_QUANTUM_CLI_BASELINE: "0.2.3"
WAI_QUANTUM_QPU_BASELINE: "0.4.0"
# Built from its source on crates.io, at this version.
SEMVER_CHECKS: "0.51.0"
steps:
- uses: actions/checkout@v5
- 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: Install cargo-semver-checks ${{ env.SEMVER_CHECKS }}
shell: bash
run: |
set -euo pipefail
cargo install cargo-semver-checks --version "$SEMVER_CHECKS" --locked --root "$RUNNER_TEMP/semver"
echo "$RUNNER_TEMP/semver/bin" >> "$GITHUB_PATH"
- name: The baselines are the last versions published
shell: bash
working-directory: ${{ runner.temp }}
run: |
set -euo pipefail
for pair in "wai-quantum $WAI_QUANTUM_BASELINE" "wai-quantum-cli $WAI_QUANTUM_CLI_BASELINE" "wai-quantum-qpu $WAI_QUANTUM_QPU_BASELINE"; do
set -- $pair
latest=$(cargo info "$1" 2>/dev/null | sed -n 's/^version: *\([^ ]*\).*/\1/p' | head -1 || true)
if [ -z "$latest" ]; then
echo "::warning::crates.io did not say which version of $1 is the last; the check runs against $2"
elif [ "$latest" != "$2" ]; then
echo "::warning::crates.io's last version of $1 is $latest, and this workflow's baseline is $2: raise the baseline"
else
echo "$1: the baseline $2 is the last version on crates.io"
fi
done
- name: API compatibility, against the last versions published
shell: bash
run: |
set -euo pipefail
# The major of a version: the first non-zero component (0.6.16 -> 0.6, 1.2.3 -> 1).
major() { IFS=. read -r a b _ <<< "$1"; if [ "$a" = 0 ]; then echo "0.$b"; else echo "$a"; fi; }
# Every change is checked as if for a minor release, so that each breaking
# change is listed; a breaking change fails the step only when the major
# is still the baseline's. A build that fails is a failure either way.
check() {
local dir=$1 base=$2 cur log
cur=$(sed -n 's/^version *= *"\([^"]*\)".*/\1/p' "$dir/Cargo.toml" | head -1)
log="$RUNNER_TEMP/semver-$(basename "$dir").log"
echo "== $dir: $base -> $cur, the major $(major "$base") -> $(major "$cur")"
if cargo semver-checks check-release --manifest-path "$dir/Cargo.toml" --baseline-version "$base" --release-type minor 2>&1 | tee "$log"; then
echo "$dir: no breaking change against $base"
elif ! grep -q 'semver requires new major version' "$log"; then
echo "::error::$dir: the check did not run to its end (above)"
return 1
elif [ "$(major "$cur")" != "$(major "$base")" ]; then
echo "::warning::$dir: breaking changes against $base, listed above; allowed, as the major is bumped to $(major "$cur")"
else
echo "::error::$dir: a breaking change against $base, listed above, without a major bump: raise $(major "$base") (before 1.0, the 0.y component), and say what to do instead in the changelog"
return 1
fi
}
r=0
check wai/wai-quantum "$WAI_QUANTUM_BASELINE" || r=1
check wai/wai-quantum-cli "$WAI_QUANTUM_CLI_BASELINE" || r=1
check wai/wai-quantum-qpu "$WAI_QUANTUM_QPU_BASELINE" || r=1
exit $r
schemas:
name: schemas and the committed tool lists · linux
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: linux
timeout-minutes: 60
steps:
- uses: actions/checkout@v5
- name: Install Rust 1.99.1, and uv
shell: bash
run: |
export PATH="$HOME/.local/bin:$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
command -v uv >/dev/null 2>&1 || curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: The engine's schemas, and receipts issued before
shell: bash
working-directory: wai/wai-quantum
run: |
set -euo pipefail
cargo test --locked --release --no-default-features --features quantum_engine,quantum_receipt,quantum_qec,quantum_noise --lib engine::schema:: 2>&1 | tee "$RUNNER_TEMP/engine.log"
for t in every_schema_reads_names_itself_and_refers_only_to_what_is_there \
the_checker_reads_the_subset_it_names_and_refuses_what_it_should \
every_check_s_answer_follows_its_schema \
every_method_s_job_follows_the_job_schemas \
a_new_result_names_its_engine_and_schema_and_its_receipt_binds_them \
error_correction_and_mitigation_follow_their_schemas \
the_answer_layer_the_correctness_record_and_the_views_bundle_follow_their_schemas \
the_course_its_exercises_and_its_checks_follow_their_schemas \
the_variational_and_algorithm_answers_follow_their_schema \
receipts_issued_before_results_named_them_still_verify; do
grep -q "^test engine::schema::tests::$t \.\.\. ok$" "$RUNNER_TEMP/engine.log" || { echo "::error::$t did not run and pass"; exit 1; }
done
- name: The command line's MCP server, its committed tool list and its docs
shell: bash
working-directory: wai/wai-quantum-cli
run: |
set -euo pipefail
cargo test --locked --release --bin wai-quantum 2>&1 | tee "$RUNNER_TEMP/cli.log"
for t in mcp::tests::the_schemas_read_and_name_themselves \
mcp::tests::every_tool_s_answer_follows_its_output_schema \
mcp::tests::the_committed_tool_list_is_this_server_s_live_list \
mcp::tests::an_agent_initializes_lists_the_tools_and_runs_a_circuit \
guide::tests::the_committed_docs_are_what_the_binary_generates \
guide::tests::the_docs_list_exactly_the_servers_tools_and_name_no_version \
tests::the_command_line_parses_as_documented \
task::tests::a_lease_follows_its_schema \
eval::tests::a_scripted_run_reports_what_the_engine_found \
eval::tests::the_corpus_is_the_task_set_written_three_ways \
learn::tests::progress_is_kept_in_one_file_and_marks_a_pass_once; do
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/cli.log" || { echo "::error::$t did not run and pass"; exit 1; }
done
- name: The job service's MCP server, its committed tool list, its job and its receipt keys
shell: bash
working-directory: wai/wai-quantum-service
run: |
set -euo pipefail
cargo test --locked --release -- mcp:: jobs:: receipt:: 2>&1 | tee "$RUNNER_TEMP/service.log"
for t in mcp::tests::the_schemas_read_and_the_versions_are_reported \
mcp::tests::every_tool_s_answer_follows_its_output_schema \
mcp::tests::every_tool_has_a_schema_and_a_description \
mcp::tests::the_command_line_s_snapshot_is_this_server_s_live_list \
jobs::tests::a_job_s_form_follows_the_job_schema \
receipt::tests::a_rotation_keeps_the_old_key_published_with_its_window_and_a_signed_transition; do
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/service.log" || { echo "::error::$t did not run and pass"; exit 1; }
done
- name: The provider protocol's messages
shell: bash
working-directory: wai/wai-quantum-qpu
run: |
set -euo pipefail
cargo test --locked --release --test protocol_schema 2>&1 | tee "$RUNNER_TEMP/qpu.log"
for t in the_schema_names_the_protocol_s_own_constants every_message_and_answer_follows_the_protocol_s_schema; do
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/qpu.log" || { echo "::error::$t did not run and pass"; exit 1; }
done
# A second implementation of JSON Schema, sharing no code with the engine's
# checker: every schema file and both tool lists valid 2020-12 schemas, every
# reference resolving, and a release build's answers holding to them.
- name: The schemas, read by a full JSON Schema implementation
shell: bash
run: |
set -euo pipefail
(cd wai/wai-quantum-cli && cargo build --locked --release)
uv venv -q --python 3.12 "$RUNNER_TEMP/schemas"
uv pip install -q --python "$RUNNER_TEMP/schemas/bin/python" --require-hashes -r wai/wai-quantum-py/tests/requirements.lock
"$RUNNER_TEMP/schemas/bin/python" -I wai/wai-quantum/ci/check_schemas.py wai wai/wai-quantum-cli/target/release/wai-quantum
policy:
name: the policy is linked, and the deprecations page reads
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: linux
timeout-minutes: 10
steps:
- uses: actions/checkout@v5
- name: Every README of a WAI Quantum package links the policy
shell: bash
run: |
set -euo pipefail
for f in wai/wai-quantum/README.md wai/wai-quantum-cli/README.md wai/wai-quantum-service/README.md \
wai/wai-quantum-qpu/README.md wai/wai-quantum-py/README.md wai/wai-quantum-desktop/README.md \
wai/quantum-studio/README.md wai/tools/wai-quantum-editor/README.md wai/tools/tree-sitter-openqasm/README.md; do
grep -q 'wai/wai-quantum/VERSIONING.md\|(VERSIONING.md)' "$f" || { echo "::error::$f does not link the policy (wai/wai-quantum/VERSIONING.md)"; exit 1; }
done
echo "every README links the policy"
- name: The deprecations page's table is well formed
shell: bash
run: |
set -euo pipefail
python3 -I - wai/wai-quantum/DEPRECATIONS.md <<'EOF'
import re, sys
lines = open(sys.argv[1], encoding="utf-8").read().splitlines()
head = "| Package | Item | Deprecated in | Replacement | Removed in |"
assert head in lines, "the table's header is " + head
at = lines.index(head)
assert re.fullmatch(r"\|(---\|){5}", lines[at + 1]), lines[at + 1]
semver = re.compile(r"\d+\.\d+\.\d+")
rows = []
for line in lines[at + 2:]:
if not line.startswith("|"):
break
cells = [c.strip() for c in line.strip("|").split("|")]
assert len(cells) == 5 and all(cells[:4]), f"a row names its package, item, version and replacement: {line}"
assert semver.fullmatch(cells[2]), f"deprecated in a version: {line}"
assert cells[4] == "" or semver.fullmatch(cells[4]), f"removed in a version, or not yet: {line}"
rows.append(cells)
print(f"{len(rows)} deprecated item(s) listed")
EOF