Some checks failed
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 21s
wai-fleet service / does this change touch it (push) Successful in 17s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 26s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 28s
wai-app and Create / wai-app · does this change touch it (push) Successful in 22s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 15s
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (push) Successful in 50s
wai-quantum editors / does this change touch it (push) Successful in 31s
wai-quantum for JavaScript / does this change touch it (push) Successful in 29s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 40s
wai-audit collector and player integration / does this change touch it (push) Successful in 1m23s
wai-quantum studio and desktop / does this change touch it (push) Successful in 30s
wai-fleet service / service · macos (push) Successful in 59s
wai-quantum for Python / does this change touch it (push) Successful in 31s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 1m27s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 21s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 2m4s
wai-key-proxy / does this change touch it (push) Successful in 1m55s
WAI operation catalogue / does this change touch it (push) Successful in 1m56s
wai-quantum command line / does this change touch it (push) Successful in 1m40s
wai-ledger service / does this change touch it (push) Successful in 1m50s
wai-quantum contract / does this change touch it (push) Successful in 1m41s
WAI Studio / does this change touch it (push) Successful in 12s
wai-sink-swift native sink package / does this change touch it (push) Successful in 25s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 1m43s
wai-sink-android native sink library / does this change touch it (push) Successful in 42s
joule-code conformance gate / Build + round-trip C1-C4 vectors (push) Successful in 2m45s
wai-quantum editors / editors · macos (push) Successful in 2m2s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m21s
wai-fleet service / service · linux (push) Successful in 3m36s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Successful in 12s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 52s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 2m37s
wai-quantum for Python / python · macos (push) Successful in 2m57s
wai-ledger service / service · macos (push) Successful in 1m16s
wai-quantum editors / editors · linux (push) Successful in 3m46s
wai-audit collector and player integration / collector · linux (push) Successful in 3m39s
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Successful in 3m23s
wai-quantum for Python / python · linux (push) Successful in 4m26s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Failing after 6m38s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 5m7s
wai-quantum command line / command line · macos (push) Successful in 2m33s
wai-quantum for JavaScript / javascript · linux (push) Successful in 5m35s
wai-key-proxy / proxy · linux (push) Successful in 1m12s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 7m3s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 7m40s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 7m39s
wai-ledger service / service · linux (push) Successful in 2m5s
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Successful in 7s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 8m36s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 8m36s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m10s
wai-quantum views in agent hosts / views · a scripted host (push) Successful in 4m26s
wai-quantum views in agent hosts / views · the page and its engine (push) Successful in 6m33s
wai-quantum contract / API compatibility · linux (push) Successful in 4m44s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 13m4s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 6m46s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 14m11s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 14m12s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 13m18s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 10m49s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 11m36s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 12m10s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 16m36s
wai-quantum contract / schemas and the committed tool lists · linux (push) Successful in 9m58s
wai-quantum studio and desktop / studio · browser (push) Successful in 16m35s
WAI Studio / Studio in WebKit · linux (push) Successful in 12m22s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Successful in 22m0s
wai release binaries build on Windows / the seven release binaries · windows (push) Successful in 24m31s
joule-code conformance gate / joule-moq-ingest, every target (push) Successful in 28m51s
joule-code conformance gate / joule-moq-relay, every target (push) Successful in 28m59s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 29m41s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 11m58s
wai-quantum command line / command line · linux (push) Successful in 48m17s
Folds, each the program it folds run as itself, so what it prints and its exit status are the program's for the same arguments: wai audit report|check|verify (audit.create, audit.check, audit.verify) is wai-audit, --owner its WAI_AUDIT_OWNER; wai serve <role> [--config F] [--check] (service.start) starts wai-<role>: relay, room, ingest and key-release from a file, audit, fleet, ledger and quantum-service from their environment; wai quantum run|plan|lint|verify|methods (quantum.run, .inspect, .check, .verify, .list) is wai-quantum with that verb, and no other verb of it is reached. A program is its flag, WAI_<NAME>_BIN, beside wai, or on PATH; one not there is exit 5, program-not-found. report is not an N3 verb, so wai audit report is the operation audit.create. --check on the daemons: wai-relay, wai-room (its keys too) and wai-ingest --config F --check, and wai-key-release serve F --check, read the configuration as each starts from it and start nothing, exit 1 with the reason when it does not read. The proxy is installed as wai-key-release; wai-key-proxy is the same program under its earlier name. wai cmcd encode|decode|verify is wai_telemetry's tool compiled in (cmcd.rs, one module behind both; telemetry joins full). wai receipt create <file>... --from <input>... [--key] signs the operation receipt a toolchain write leaves, for files made elsewhere. wai verify reads every record by its kind: by name, and a JSON record by what it holds (a delivery receipt or claim as receipt_verify answers it, a room session, an audit bundle as wai-audit verify does with --owner/--channel, a sealed playlist by its mr/<blake3>.json as check-playlist does); a file of no kind is exit 2, unknown-record. wai mcp --toolset quantum starts wai-quantum mcp and answers each quantum_* tool with that server's own answer and schemas. wai media score build|render alias wai score. The quantum operations' SDK names are registered labels. Tests, each fold against what it folds: cli_folds (cmcd over the whole corpus, receipt create against wrap's receipt, verify on the claim, JWP, room and audit corpora and a sealed playlist, audit|serve|quantum against stand-ins); wai-audit tests/fold.rs, wai-quantum-cli tests/wai_fold.rs and joule-moq-room tests/cli_serve.rs against the real programs; cli_mcp's quantum toolset; the daemons' --check (config_check.rs, check.rs). ops.json, mcp.json, the registry export and Studio's actions regenerated. Co-Authored-By: Claude Opus 5.5 <[email protected]>
386 lines
26 KiB
YAML
386 lines
26 KiB
YAML
name: wai-quantum command line
|
|
|
|
# The wai-quantum command line (wai/wai-quantum-cli): its tests and clippy with
|
|
# warnings as errors, with and without `submit`; its smoke checks (smoke.sh: lint,
|
|
# plan, run, verify and a forged result refused, key, draw, MCP over stdio, the
|
|
# research tools); and the WASI component, whose output under wasmtime equals the
|
|
# native build's byte for byte. On macOS, also with the GPU state vector. Its tests
|
|
# include the model harness (src/eval.rs): every task's reference solved and an
|
|
# empty program not, a scripted run, a model server on this machine asked and one
|
|
# elsewhere refused, and the corpus (wai/quantum-conformance/eval/) held to the
|
|
# task set. On Linux, also the cross-simulator corpus's CI tier
|
|
# (wai/quantum-cross-simulator/: the engine against pinned third-party
|
|
# simulators and integer references, each answer within its stated tolerance), its
|
|
# self-test (every injected fault caught), and its provider template held to the
|
|
# provider protocol's conformance vectors through `providers test` and `run --provider`.
|
|
# And job receipts by two verifiers (wai/quantum-conformance/receipts/):
|
|
# `verify` and receipt_verify.py, written from the provider protocol's section 8
|
|
# alone, each held to the corpus's manifest and to the other on every receipt and
|
|
# every one-member change of each valid one, and each planted defect caught.
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/wai-quantum-cli/**'
|
|
- 'wai/wai-quantum-qpu/**'
|
|
- 'wai/wai-wasmq/**'
|
|
- 'wai/quantum-conformance/eval/**'
|
|
- 'wai/quantum-conformance/wasmq/**'
|
|
- 'wai/wai-quantum-writer/**'
|
|
# The writer's model runs on this crate, which it path-depends on.
|
|
- 'jouleclaw/jouleclaw-rs/crates/jouleclaw-loader-gguf/**'
|
|
- 'wai/quantum-cross-simulator/**'
|
|
- 'wai/quantum-conformance/receipts/**'
|
|
- 'wai/quantum-conformance/tools/receipt_verify.py'
|
|
- 'wai/quantum-conformance/tools/receipt_differential.py'
|
|
- 'wai/quantum-conformance/tools/wasmq_mutants.py'
|
|
- 'wai/quantum-conformance/tools/referee.py'
|
|
- 'wai/extensions/quantum-providers.md'
|
|
- 'wai/extensions/quantum-wasmq.md'
|
|
# tests/wai_fold.rs builds wai and holds `wai quantum` and the quantum toolset to this crate's program.
|
|
- 'wai/wai-rs/src/bin/wai_cli/fold.rs'
|
|
- 'wai/wai-rs/src/bin/wai_cli/mcp/quantum.rs'
|
|
- 'rust-toolchain.toml'
|
|
- '.github/workflows/wai-quantum-cli.yml'
|
|
# Nightly, beside the pushes: each rule's weakenings (below), which take a second build.
|
|
schedule:
|
|
- cron: '41 3 * * *'
|
|
pull_request:
|
|
paths:
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/wai-quantum-cli/**'
|
|
- 'wai/wai-quantum-qpu/**'
|
|
- 'wai/wai-wasmq/**'
|
|
- 'wai/quantum-conformance/eval/**'
|
|
- 'wai/quantum-conformance/wasmq/**'
|
|
- 'wai/wai-quantum-writer/**'
|
|
# The writer's model runs on this crate, which it path-depends on.
|
|
- 'jouleclaw/jouleclaw-rs/crates/jouleclaw-loader-gguf/**'
|
|
- 'wai/quantum-cross-simulator/**'
|
|
- 'wai/quantum-conformance/receipts/**'
|
|
- 'wai/quantum-conformance/tools/receipt_verify.py'
|
|
- 'wai/quantum-conformance/tools/receipt_differential.py'
|
|
- 'wai/quantum-conformance/tools/wasmq_mutants.py'
|
|
- 'wai/quantum-conformance/tools/referee.py'
|
|
- 'wai/extensions/quantum-providers.md'
|
|
- 'wai/extensions/quantum-wasmq.md'
|
|
# tests/wai_fold.rs builds wai and holds `wai quantum` and the quantum toolset to this crate's program.
|
|
- 'wai/wai-rs/src/bin/wai_cli/fold.rs'
|
|
- 'wai/wai-rs/src/bin/wai_cli/mcp/quantum.rs'
|
|
- 'rust-toolchain.toml'
|
|
- '.github/workflows/wai-quantum-cli.yml'
|
|
|
|
jobs:
|
|
relevant:
|
|
name: does this change touch it
|
|
runs-on: gate
|
|
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-cli.yml \
|
|
"${{ github.event.pull_request.base.sha }}" \
|
|
"${{ github.event.pull_request.head.sha }}")
|
|
echo "this change touches the wai-quantum command line: $r"
|
|
echo "run=$r" >> "$GITHUB_OUTPUT"
|
|
|
|
cli-linux:
|
|
name: command line · 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 with clippy and the wasm32-wasip2 target
|
|
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 --component clippy
|
|
rustup default 1.99.1
|
|
rustup target add --toolchain 1.99.1 wasm32-wasip2
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
- name: Tests and clippy, with and without submit
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-cli
|
|
run: |
|
|
set -euo pipefail
|
|
# No test reaches a person's timings: every test here names its file,
|
|
# so none may appear where a person's would be.
|
|
XDG_CONFIG_HOME="$RUNNER_TEMP/no-timings" cargo test --locked --release 2>&1 | tee "$RUNNER_TEMP/test.log"
|
|
grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/test.log" || { echo "::error::no test ran"; exit 1; }
|
|
test ! -e "$RUNNER_TEMP/no-timings/wai/quantum-timings.json" || { echo "::error::a test wrote the timings of whoever runs it"; exit 1; }
|
|
# Your own providers end to end (tests/providers.rs), against the
|
|
# reference provider this binary serves, and their jobs as MCP
|
|
# tasks, each test by name.
|
|
for t in json_output_does_not_skip_the_history_it_was_asked_to_check \
|
|
lines_judge_a_set_as_a_set \
|
|
the_mcp_tool_given_a_job_s_text_gives_the_corpus_s_verdict \
|
|
a_member_named_twice_is_unreadable_on_every_kind_of_job \
|
|
the_mcp_tool_gives_the_corpus_s_verdict_on_what_a_parsed_job_shows \
|
|
a_named_credential_that_is_empty_never_falls_to_the_account_s_keys \
|
|
a_person_adds_tests_plans_and_runs_on_a_provider_and_the_receipt_verifies \
|
|
a_run_that_is_not_free_is_refused_until_the_person_confirms_it \
|
|
a_credential_is_kept_in_a_file_only_its_owner_reads_and_appears_in_nothing_printed \
|
|
a_provider_over_http_runs_with_its_credential_in_the_header \
|
|
an_agent_lists_estimates_is_refused_and_runs_only_with_confirm_cost \
|
|
an_agent_runs_on_a_provider_as_a_task_and_the_server_answers_while_it_waits \
|
|
providers::tasks::tests::a_job_reads_as_its_task \
|
|
providers::tasks::tests::a_cancelled_request_ends_its_wait_and_a_change_wakes_it \
|
|
a_contract_weighs_every_route_and_its_receipt_says_why \
|
|
an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses \
|
|
a_run_is_stopped_at_its_ceiling_by_a_live_reading_and_its_receipt_says_so \
|
|
a_route_nothing_can_stop_is_refused_under_a_ceiling_on_every_surface \
|
|
an_estimate_refuses_a_job_clearly_past_a_ceiling_and_keeps_to_its_build \
|
|
estimates::tests::the_timings_keep_each_method_s_last_runs_and_read_back \
|
|
estimates::tests::three_runs_read_give_an_estimate_and_none_of_them_a_promise \
|
|
estimates::tests::a_route_nothing_can_read_or_stop_has_no_watch \
|
|
estimates::tests::a_run_in_its_own_process_is_killed_at_its_ceiling_and_read_whole \
|
|
estimates::tests::readings_are_kept_under_the_machine_reader_and_build \
|
|
estimates::tests::a_counter_is_asked_twice_and_a_reading_kept_nowhere_is_not_taken \
|
|
a_run_under_a_ceiling_ends_with_its_command_line \
|
|
keys::tests::keys_made_at_once_are_one_key \
|
|
estimates::tests::a_run_is_read_only_where_something_needs_the_reading \
|
|
estimates::tests::the_wait_for_a_counter_is_in_no_run_s_power \
|
|
estimates::tests::a_package_counter_is_read_over_a_few_of_its_updates \
|
|
estimates::tests::the_timings_are_kept_where_their_variables_say \
|
|
estimates::tests::runs_that_finish_together_all_keep_theirs \
|
|
estimates::tests::a_file_that_is_no_store_is_kept_and_a_link_stays_a_link \
|
|
tests::the_command_line_parses_as_documented; do
|
|
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; }
|
|
done
|
|
# The model harness and the views in an agent's host, each test by name.
|
|
for t in eval::tests::every_task_s_reference_is_solved_and_an_empty_program_is_not \
|
|
eval::tests::a_scripted_run_reports_what_the_engine_found \
|
|
eval::tests::a_model_on_this_machine_is_asked_and_one_elsewhere_is_refused \
|
|
eval::tests::the_corpus_is_the_task_set_written_three_ways \
|
|
eval::tests::an_answer_is_read_for_its_program_and_scored \
|
|
mcp::tests::a_host_that_draws_views_gets_them_and_one_that_does_not_gets_words; do
|
|
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; }
|
|
done
|
|
# The token counter needs a model's vocabulary to run; here it is only read.
|
|
python3 -I -c 'import ast, sys; ast.parse(open(sys.argv[1]).read())' ../quantum-conformance/eval/token_cost.py
|
|
cargo clippy --locked --release --all-targets -- -D warnings
|
|
cargo clippy --locked --release --all-targets --no-default-features -- -D warnings
|
|
# wai-quantum-writer: the loop that writes a program for a task, its model on the
|
|
# pure-Rust runtime, checked by the engine as a lesson's answer is. Its tests run the
|
|
# loop with a scripted model (no checkpoint), with and without the model compiled in.
|
|
- name: The writer, with a scripted model, and clippy
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-writer
|
|
run: |
|
|
set -euo pipefail
|
|
cargo test --locked --release
|
|
cargo test --locked --release --no-default-features
|
|
cargo clippy --locked --release --all-targets -- -D warnings
|
|
cargo clippy --locked --release --all-targets --no-default-features -- -D warnings
|
|
- name: The smoke checks
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-cli
|
|
run: |
|
|
set -euo pipefail
|
|
cargo build --locked --release
|
|
bash smoke.sh ./target/release/wai-quantum
|
|
# The cross-simulator corpus's CI tier: the circuits marked `ci` in its manifest, a few
|
|
# seconds of work each, on the engine, pinned third-party simulators (wheels checked
|
|
# against their hashes) and the integer references. Every kind of check runs on at least
|
|
# one circuit but the pairwise comparison of wide circuits (`wide_pairwise`, 26 qubits),
|
|
# which only the full tier makes. A crash, time-out or unlisted refusal of the engine
|
|
# under test fails it. Then each fault compare.py can inject must fail its own check on
|
|
# its own engine; then the provider template end to end. The full corpus is
|
|
# `reproduce.sh --tier full`, run by hand (its README). referee.py is on the paths above
|
|
# because the corpus imports it.
|
|
- name: The cross-simulator corpus (CI tier), its self-test, and the provider template
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
export QCORPUS_CACHE="$HOME/.cache/wai-quantum-cross-simulator"
|
|
bash wai/quantum-cross-simulator/reproduce.sh --tier ci --jobs 2 --out "$RUNNER_TEMP/cross-simulator.json"
|
|
bash wai/quantum-cross-simulator/reproduce.sh --self-test --jobs 2
|
|
# The page's results section is what the committed results files say.
|
|
python3 -I wai/quantum-cross-simulator/tools/report.py --check
|
|
# Job receipts, judged by two verifiers that share no code: this binary's `verify`, and
|
|
# receipt_verify.py, written in Python from wai/extensions/quantum-providers.md section 8
|
|
# alone (standard library only, its BLAKE3 and Ed25519 its own). The corpus's crafted half
|
|
# is what generate.py writes; the second verifier's self-test holds its BLAKE3, Ed25519,
|
|
# RFC 8785 and number text to published answers. Then both verifiers and the manifest must
|
|
# agree on every receipt of the corpus, and the two verifiers on every receipt made from a
|
|
# valid one by changing one member, or by setting a number past a double's whole numbers.
|
|
# Each planted defect of the second verifier (a lenient key check, alg unchecked, the last
|
|
# of a duplicate member kept, inexact numbers let through, a simulator's counts let pass as
|
|
# measured, a ceiling on every whole number, R of small order let through, the canonical
|
|
# spelling of a large double refused, a set's seal checked and nothing of its items,
|
|
# qubit names held to the layouts only, and under a contract each route's outcome, the
|
|
# planner's choice or a shadow's distance taken as it stands) must make the
|
|
# differential fail: the proof that it can. A plant that the corpus alone catches is caught
|
|
# by the second-only run too, in the independent verifiers' step.
|
|
- name: Job receipts, two verifiers
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 -I wai/quantum-conformance/receipts/generate.py --check
|
|
python3 -I wai/quantum-conformance/receipts/generate.py --self-test
|
|
python3 -I wai/quantum-conformance/tools/receipt_verify.py --self-test wai/wai-quantum/src/engine/testdata/es-number-tostring.txt
|
|
python3 -I wai/quantum-conformance/tools/receipt_differential.py --reference wai/wai-quantum-cli/target/release/wai-quantum
|
|
# Each plant runs the whole differential with one verifier broken on purpose, a few
|
|
# minutes each: they run side by side, and every one must be caught.
|
|
printf '%s\n' lenient-key no-alg last-duplicate no-inexact measured-simulator whole-cap lax-small-order-r no-canonical-spelling set-seal-only names-layout-only route-unchecked choice-unchecked distance-unchecked wasmq-unchecked \
|
|
| xargs -P "$(nproc)" -I{} bash -c 'set -o pipefail; python3 -I wai/quantum-conformance/tools/receipt_differential.py --reference wai/wai-quantum-cli/target/release/wai-quantum --plant "{}" | tail -1' \
|
|
| tee "$RUNNER_TEMP/plants.log"
|
|
test "$(grep -c ': caught' "$RUNNER_TEMP/plants.log")" -eq 14 || { echo "::error::not every plant was caught"; exit 1; }
|
|
# Each rule of a wasmQ job's form weakened in each verifier, from its code (the check
|
|
# dropped, a comparison moved by one, a count or a digest read loosely, a null member read
|
|
# as absent and an absent one as null), and every weakening caught by the differential:
|
|
# the second verifier's as files, the engine's as one build that holds every weakening,
|
|
# each switched on alone (wasmq_mutants.py). Counted per rule. Nightly.
|
|
- name: Each rule's weakenings caught, in both verifiers
|
|
if: github.event_name == 'schedule'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 -I wai/quantum-conformance/tools/wasmq_mutants.py python --reference wai/wai-quantum-cli/target/release/wai-quantum --jobs 4
|
|
m="$RUNNER_TEMP/wasmq-mutants"
|
|
rm -rf "$m" && mkdir -p "$m"
|
|
git worktree add --detach "$m/wt" HEAD
|
|
python3 -I wai/quantum-conformance/tools/wasmq_mutants.py rust-schemata "$m/wt/wai/wai-quantum/src/engine/wasmq.rs" "$m/mutants.json"
|
|
(cd "$m/wt/wai/wai-quantum-cli" && CARGO_TARGET_DIR="$m/target" cargo build --locked --release)
|
|
python3 -I wai/quantum-conformance/tools/wasmq_mutants.py rust --reference "$m/target/release/wai-quantum" --mutants "$m/mutants.json" --jobs 4
|
|
git worktree remove --force "$m/wt"
|
|
# The release binary, pinned by version and SHA-256, rather than a build from source.
|
|
# Every WAI workflow that runs wasmtime pins this one version, and every run passes
|
|
# -W nan-canonicalization=y -W relaxed-simd-deterministic=y: every NaN a float
|
|
# instruction makes is the canonical one, and each relaxed SIMD instruction has one
|
|
# behaviour on every host. A stock wasmtime leaves both off. The fixed relaxed
|
|
# behaviour is the engine's own: on 50.0.1 relaxed_madd is fused (measured on arm64 and
|
|
# x86_64), where WebAssembly's deterministic profile prescribes the unfused result.
|
|
# The repository checks (scripts/check-wasmtime-pin.py) fail a workflow that pins another
|
|
# release or runs wasmtime without both settings.
|
|
- name: Install wasmtime 50.0.1
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
[ "$(uname -m)" = x86_64 ] || { echo "::error::the pinned wasmtime archive is x86_64; this host is $(uname -m)"; exit 1; }
|
|
if ! command -v xz >/dev/null 2>&1; then
|
|
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
|
|
$SUDO apt-get update -qq
|
|
$SUDO apt-get install -y -qq xz-utils
|
|
fi
|
|
v=50.0.1
|
|
f="wasmtime-v$v-x86_64-linux.tar.xz"
|
|
curl --proto '=https' --tlsv1.2 -sSfL -o "$RUNNER_TEMP/$f" \
|
|
"https://github.com/bytecodealliance/wasmtime/releases/download/v$v/$f"
|
|
echo "685466455dd42a14774a86c36c8f2e45cbb9bd6d92a850139315df60a75498a5 $RUNNER_TEMP/$f" | sha256sum -c -
|
|
tar -xJf "$RUNNER_TEMP/$f" -C "$RUNNER_TEMP"
|
|
echo "$RUNNER_TEMP/wasmtime-v$v-x86_64-linux" >> "$GITHUB_PATH"
|
|
# The same source as a WASI component: a circuit's state hash, a run's
|
|
# result and a receipt signed with the published key are the native
|
|
# build's, byte for byte.
|
|
- name: The WASI component gives the native build's bytes
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-cli
|
|
run: |
|
|
set -euo pipefail
|
|
cargo build --locked --release --target wasm32-wasip2 --no-default-features
|
|
w=target/wasm32-wasip2/release/wai-quantum.wasm
|
|
n=target/release/wai-quantum
|
|
printf 'OPENQASM 3.0; qubit[3] q; h q[0]; cx q[0], q[1]; t q[2]; cx q[1], q[2];' > "$RUNNER_TEMP/p.qasm"
|
|
for args in "lab run ghz -n 5" "lab receipt ghz -n 3 --demo-key"; do
|
|
$n $args > "$RUNNER_TEMP/native.txt" 2> /dev/null
|
|
wasmtime run -W nan-canonicalization=y -W relaxed-simd-deterministic=y "$w" $args > "$RUNNER_TEMP/wasi.txt" 2> /dev/null
|
|
cmp "$RUNNER_TEMP/native.txt" "$RUNNER_TEMP/wasi.txt" || { echo "::error::$args differs under wasmtime"; diff "$RUNNER_TEMP/native.txt" "$RUNNER_TEMP/wasi.txt" || true; exit 1; }
|
|
done
|
|
$n run --demo-key --json --shots 100 < "$RUNNER_TEMP/p.qasm" 2> /dev/null | python3 -c 'import json,sys; j=json.load(sys.stdin); j["result"].pop("elapsed_ms"); j["result"]["receipt"].pop("digest"); j["result"]["receipt"].pop("signature"); print(json.dumps(j, sort_keys=True))' > "$RUNNER_TEMP/native.json"
|
|
wasmtime run -W nan-canonicalization=y -W relaxed-simd-deterministic=y "$w" run --demo-key --json --shots 100 < "$RUNNER_TEMP/p.qasm" 2> /dev/null | python3 -c 'import json,sys; j=json.load(sys.stdin); j["result"].pop("elapsed_ms"); j["result"]["receipt"].pop("digest"); j["result"]["receipt"].pop("signature"); print(json.dumps(j, sort_keys=True))' > "$RUNNER_TEMP/wasi.json"
|
|
cmp "$RUNNER_TEMP/native.json" "$RUNNER_TEMP/wasi.json" || { echo "::error::a run's result differs under wasmtime"; exit 1; }
|
|
# With a home it can reach, a run still gives its result, and keeps nothing:
|
|
# a wasm build reads no counter and writes no timings.
|
|
mkdir -p "$RUNNER_TEMP/wasi-home"
|
|
for e in HOME=/h WAI_QUANTUM_TIMINGS=/h/timings.json; do
|
|
wasmtime run -W nan-canonicalization=y -W relaxed-simd-deterministic=y --env "$e" --dir "$RUNNER_TEMP/wasi-home::/h" "$w" run --demo-key --json --shots 100 < "$RUNNER_TEMP/p.qasm" 2> /dev/null | python3 -c 'import json,sys; assert sum(json.load(sys.stdin)["result"]["counts"].values())==100'
|
|
done
|
|
test -z "$(find "$RUNNER_TEMP/wasi-home" -type f)" || { echo "::error::a wasm build kept a file"; exit 1; }
|
|
# A compile to Clifford+T (rotation synthesis in exact and fixed-point
|
|
# arithmetic, the passes, the certificate and its seal): byte for byte.
|
|
printf 'OPENQASM 3.0; qubit[2] q; h q[0]; rz(0.3) q[0]; cx q[0], q[1]; ry(1.1) q[1]; cp(0.7) q[0], q[1];' > "$RUNNER_TEMP/angles.qasm"
|
|
$n compile --demo-key --json --level 2 --epsilon 1e-8 < "$RUNNER_TEMP/angles.qasm" > "$RUNNER_TEMP/native-compile.json" 2> /dev/null
|
|
wasmtime run -W nan-canonicalization=y -W relaxed-simd-deterministic=y "$w" compile --demo-key --json --level 2 --epsilon 1e-8 < "$RUNNER_TEMP/angles.qasm" > "$RUNNER_TEMP/wasi-compile.json" 2> /dev/null
|
|
cmp "$RUNNER_TEMP/native-compile.json" "$RUNNER_TEMP/wasi-compile.json" || { echo "::error::a compile differs under wasmtime"; exit 1; }
|
|
# A run on a device target: the layout search, the noise derived and
|
|
# the density matrix, the same bits.
|
|
for t in synthetic-line-5 synthetic-all-5; do
|
|
$n run --demo-key --json --shots 100 --target $t < "$RUNNER_TEMP/p.qasm" 2> /dev/null | python3 -c 'import json,sys; j=json.load(sys.stdin); j["result"]["receipt"].pop("digest"); j["result"]["receipt"].pop("signature"); print(json.dumps(j, sort_keys=True))' > "$RUNNER_TEMP/native-$t.json"
|
|
wasmtime run -W nan-canonicalization=y -W relaxed-simd-deterministic=y "$w" run --demo-key --json --shots 100 --target $t < "$RUNNER_TEMP/p.qasm" 2> /dev/null | python3 -c 'import json,sys; j=json.load(sys.stdin); j["result"]["receipt"].pop("digest"); j["result"]["receipt"].pop("signature"); print(json.dumps(j, sort_keys=True))' > "$RUNNER_TEMP/wasi-$t.json"
|
|
cmp "$RUNNER_TEMP/native-$t.json" "$RUNNER_TEMP/wasi-$t.json" || { echo "::error::a run on $t differs under wasmtime"; exit 1; }
|
|
done
|
|
# A resource estimate (the counts, each rotation's synthesis, the
|
|
# planar model's factory search and the frontier, every receipt and
|
|
# the seal): byte for byte.
|
|
printf 'OPENQASM 3.0; qubit[4] q; h q; ctrl(3) @ x q[0], q[1], q[2], q[3]; rz(0.3) q[0]; ry(1.1) q[2]; t q[1];' > "$RUNNER_TEMP/est.qasm"
|
|
$n estimate --demo-key --json --qubit us-e3 < "$RUNNER_TEMP/est.qasm" > "$RUNNER_TEMP/native-estimate.json" 2> /dev/null
|
|
wasmtime run -W nan-canonicalization=y -W relaxed-simd-deterministic=y "$w" estimate --demo-key --json --qubit us-e3 < "$RUNNER_TEMP/est.qasm" > "$RUNNER_TEMP/wasi-estimate.json" 2> /dev/null
|
|
cmp "$RUNNER_TEMP/native-estimate.json" "$RUNNER_TEMP/wasi-estimate.json" || { echo "::error::an estimate differs under wasmtime"; exit 1; }
|
|
echo "the WASI component's output equals the native build's"
|
|
# verify gives its verdict at its own bound under wasm32 as natively: a job of 384 MiB,
|
|
# one of 2^22 values, and one more of each (too_large).
|
|
- name: The WASI component judges a job at verify's bound
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-cli
|
|
run: |
|
|
set -euo pipefail
|
|
w=target/wasm32-wasip2/release/wai-quantum.wasm
|
|
n=target/release/wai-quantum
|
|
d=$(mktemp -d "$RUNNER_TEMP/bound.XXXX")
|
|
python3 -I tests/verify_at_bound.py "$d"
|
|
for f in long longer many more; do
|
|
$n verify --json "$d/$f.json" > "$d/native-$f.txt" || true
|
|
wasmtime run -W nan-canonicalization=y -W relaxed-simd-deterministic=y --dir "$d" "$w" verify --json "$d/$f.json" > "$d/wasi-$f.txt" || true
|
|
test -s "$d/native-$f.txt" || { echo "::error::no verdict at verify's bound ($f)"; exit 1; }
|
|
cmp "$d/native-$f.txt" "$d/wasi-$f.txt" || { echo "::error::verify at its bound differs under wasmtime ($f)"; exit 1; }
|
|
done
|
|
rm -rf "$d"
|
|
|
|
cli-macos:
|
|
name: command line · macos
|
|
needs: relevant
|
|
if: needs.relevant.outputs.run == 'true'
|
|
runs-on: macos
|
|
timeout-minutes: 60
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
# launchd's PATH omits cargo on the macOS host runner.
|
|
- name: Put cargo on PATH
|
|
shell: bash
|
|
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
- name: Tests and clippy, with the GPU state vector
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-cli
|
|
run: |
|
|
set -euo pipefail
|
|
XDG_CONFIG_HOME="$RUNNER_TEMP/no-timings" nice -n 10 cargo test --locked --release --features metal 2>&1 | tee "$RUNNER_TEMP/test.log"
|
|
test ! -e "$RUNNER_TEMP/no-timings/wai/quantum-timings.json" || { echo "::error::a test wrote the timings of whoever runs it"; exit 1; }
|
|
grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/test.log" || { echo "::error::no test ran"; exit 1; }
|
|
nice -n 10 cargo clippy --locked --release --all-targets --features metal -- -D warnings
|
|
- name: The smoke checks, and a run on the GPU
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-cli
|
|
run: |
|
|
set -euo pipefail
|
|
nice -n 10 cargo build --locked --release --features metal
|
|
bash smoke.sh ./target/release/wai-quantum
|
|
printf 'OPENQASM 3.0; qubit[12] q; bit[12] c; h q; rx(0.3) q[0]; cx q[0], q[1]; c = measure q;' > "$RUNNER_TEMP/gpu.qasm"
|
|
./target/release/wai-quantum run "$RUNNER_TEMP/gpu.qasm" --method statevector_single --shots 200 --demo-key --json > "$RUNNER_TEMP/gpu.json" 2> /dev/null
|
|
python3 -c 'import json,sys; j=json.load(open(sys.argv[1])); r=j["result"]; assert r["accuracy"]["class"]=="single" and sum(r["counts"].values())==200, r' "$RUNNER_TEMP/gpu.json"
|
|
echo "statevector_single ran on $(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["result"]["accuracy"]["device"])' "$RUNNER_TEMP/gpu.json")"
|