open-standards/.github/workflows/wai-quantum-pulse.yml
Transaction Science 074f328286 wai-web, CI: pulse calls in the page, and the pulse layer's bits held on every platform
QuantumEngine.pulse gives the page the schedule and check calls, sealed
with the page's key; a pulse run is the page's run with method pulse. A
native test and a wasm32 test run the same pulse job to one pinned digest
of its final density matrix, the engine's own; wai-web-wasm.yml's pins move
from 26 to 27 (native) and from 18 to 19 (wasm32).

wai-quantum-pulse.yml runs the pulse reader's, the simulator's and the pulse
jobs' 26 tests by name in a release build on Linux, builds each feature set
that holds them without warnings, runs the pinned digests in debug and
release builds on arm64 Linux and on macOS, and runs the 26 tests under
wasm32-wasip2 by wasmtime.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 12:05:14 -04:00

201 lines
10 KiB
YAML

name: wai-quantum pulse and dynamics
# Pulse programs (wai/wai-quantum): OpenPulse read into a schedule on frames
# (qasm::pulse), the pulse simulator that integrates it under a Lindblad
# master equation (quantum_pulse), and pulse runs as jobs, their schedules
# and their checks (engine::pulse).
#
# The simulator is held to closed forms within the error it states (a Rabi
# turn, a quarter turn of phase, a detuned drive, T1 decay, T2 dephasing),
# and its result is the same bits on every platform: a test pins the final
# density matrix's digest, and this workflow runs it on x86_64 Linux, arm64
# Linux, arm64 macOS and wasm32-wasip2 (wasmtime). The browser build runs a
# pulse job to the same pinned digest (wai-web-wasm.yml, wai-web's wasm32
# tests).
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches: [main]
paths:
- 'wai/wai-quantum/**'
- 'rust-toolchain.toml'
- '.github/workflows/wai-quantum-pulse.yml'
pull_request:
paths:
- 'wai/wai-quantum/**'
- 'rust-toolchain.toml'
- '.github/workflows/wai-quantum-pulse.yml'
jobs:
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-pulse.yml \
"${{ github.event.pull_request.base.sha }}" \
"${{ github.event.pull_request.head.sha }}")
echo "this change touches the pulse layer: $r"
echo "run=$r" >> "$GITHUB_OUTPUT"
native:
name: reader, simulator and pulse jobs · linux, release
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: linux
timeout-minutes: 60
steps:
- uses: actions/checkout@v5
- name: Install Rust 1.98.0
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.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# A module filter is satisfied by any one test of the module, so the
# count is pinned and each test is required by name to have run and passed.
- name: The pulse reader, the simulator and pulse jobs
shell: bash
working-directory: wai/wai-quantum
run: |
set -euo pipefail
cargo test --locked --release --features full --lib -- qasm::pulse:: quantum_pulse:: engine::pulse:: 2>&1 | tee "$RUNNER_TEMP/pulse.log"
grep -qE '^test result: ok\. 26 passed; 0 failed' "$RUNNER_TEMP/pulse.log" || { echo "::error::the pulse tests did not all pass (26 expected)"; exit 1; }
for t in qasm::pulse::tests::a_program_reads_to_its_schedule_on_frames \
qasm::pulse::tests::barriers_align_frames_and_a_gate_starts_its_frames_together \
qasm::pulse::tests::phase_and_frequency_follow_the_frame_and_the_carrier_runs_on \
qasm::pulse::tests::each_template_samples_as_its_formula_says \
qasm::pulse::tests::a_parametric_calibration_binds_its_angle_and_a_fixed_one_wins \
qasm::pulse::tests::durations_in_nanoseconds_must_be_whole_samples \
qasm::pulse::tests::ports_map_by_name_and_by_the_options \
qasm::pulse::tests::what_the_pulse_reader_does_not_take_is_refused_with_its_code_and_place \
qasm::pulse::tests::the_schedule_writes_as_json_with_every_instruction \
quantum_pulse::tests::a_resonant_drive_turns_the_qubit_as_rabi_says \
quantum_pulse::tests::a_quarter_turn_of_phase_turns_the_axis_to_minus_y \
quantum_pulse::tests::a_detuned_drive_turns_less_and_faster \
quantum_pulse::tests::relaxation_and_dephasing_decay_as_t1_and_t2_say \
quantum_pulse::tests::the_same_schedule_gives_the_same_bits \
quantum_pulse::tests::simultaneous_captures_give_the_joint_reading \
quantum_pulse::tests::three_levels_show_leakage_and_keep_the_trace \
quantum_pulse::tests::the_bound_is_stated_and_a_step_past_it_is_refused \
quantum_pulse::tests::what_the_model_does_not_hold_is_refused \
quantum_pulse::tests::a_detuned_play_split_in_two_is_the_same_play \
engine::pulse::tests::a_pulse_job_runs_end_to_end_and_its_answer_follows_its_schemas \
engine::pulse::tests::a_target_gives_the_qubits_their_frequency_and_times_and_its_hash_is_bound \
engine::pulse::tests::what_a_pulse_job_cannot_be_is_refused_with_its_code \
engine::pulse::tests::a_pulse_job_is_checked_by_running_it_again \
engine::pulse::tests::a_schedule_is_drawn_with_its_digests \
engine::pulse::tests::the_request_schema_holds_the_options_the_engine_reads \
engine::pulse::tests::a_pulse_job_is_the_same_bits_on_every_platform; do
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/pulse.log" || { echo "::error::$t did not run and pass"; exit 1; }
done
# Without warnings: a feature gate that leaves code unreachable or a
# value unused in one feature set shows here.
- name: Each feature set that holds the pulse layer builds, without warnings
shell: bash
working-directory: wai/wai-quantum
env:
RUSTFLAGS: -D warnings
run: |
set -euo pipefail
cargo check --locked --no-default-features --features quantum_pulse --lib
cargo check --locked --no-default-features --features quantum_engine --lib
cargo check --locked --no-default-features --features quantum_engine,quantum_receipt --lib
# The same bits on other processors and operating systems: the pinned
# digests of the simulator's and a pulse job's final density matrix.
bits:
name: the same bits · ${{ matrix.label }}
needs: relevant
if: needs.relevant.outputs.run == 'true'
strategy:
fail-fast: false
matrix:
label: [linux-arm64, macos]
runs-on: ${{ matrix.label }}
timeout-minutes: 60
steps:
- uses: actions/checkout@v5
# launchd's PATH omits cargo on the macOS host runner.
- name: Install Rust 1.98.0
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.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: The pinned digests, in a debug build and a release build
shell: bash
working-directory: wai/wai-quantum
run: |
set -euo pipefail
export PATH="$HOME/.cargo/bin:$PATH"
for profile in "" "--release"; do
nice -n 10 cargo test --locked $profile --no-default-features --features quantum_engine,quantum_receipt --lib -- \
quantum_pulse::tests::the_same_schedule_gives_the_same_bits \
engine::pulse::tests::a_pulse_job_is_the_same_bits_on_every_platform 2>&1 | tee "$RUNNER_TEMP/bits.log"
grep -qE '^test result: ok\. 2 passed; 0 failed' "$RUNNER_TEMP/bits.log" || { echo "::error::the pinned bits differ here ($(uname -sm), ${profile:-debug})"; exit 1; }
done
wasip2:
name: reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime)
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: linux
timeout-minutes: 60
steps:
- uses: actions/checkout@v5
- name: Install Rust 1.98.0 with 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.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
rustup target add --toolchain 1.98.0 wasm32-wasip2
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# The release binary, pinned by version and SHA-256, rather than a build from source.
- name: Install wasmtime 49.0.2
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=49.0.2
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 "a4d6e9e3a5a60f527cf7793d674c48930c80c2e8977995b8a275cad3254b9322 $RUNNER_TEMP/$f" | sha256sum -c -
tar -xJf "$RUNNER_TEMP/$f" -C "$RUNNER_TEMP"
echo "$RUNNER_TEMP/wasmtime-v$v-x86_64-linux" >> "$GITHUB_PATH"
# A debug build, so integer overflow panics instead of wrapping.
- name: The pulse tests under wasmtime, to the pinned bits
shell: bash
working-directory: wai/wai-quantum
env:
CARGO_TARGET_WASM32_WASIP2_RUNNER: wasmtime
run: |
set -euo pipefail
cargo test --locked --target wasm32-wasip2 --features full --lib -- qasm::pulse:: quantum_pulse:: engine::pulse:: 2>&1 | tee "$RUNNER_TEMP/wasip2.log"
grep -qE '^test result: ok\. 26 passed; 0 failed' "$RUNNER_TEMP/wasip2.log" || { echo "::error::the pulse tests did not all pass under wasip2 (26 expected)"; exit 1; }