With the pulse and the other-format checks both in it, the smoke makes more submissions than a default window's 30, and the service refused the last with J030. Before each POST the script now reads where the client stands from GET /v1/health (RateLimit: r left, t seconds until one more is), and with none left it waits for one. Against production it takes longer and checks the same things. CI starts each instance it smokes with WAI_QSVC_CLIENT_BURST=60, so it never waits there. The agent docs (llms-full.txt, service-mcp.json) are blessed again from both branches' tools. Co-Authored-By: Claude Opus 5.5 <[email protected]>
233 lines
12 KiB
YAML
233 lines
12 KiB
YAML
name: wai-quantum service
|
|
|
|
# The WAI quantum stack as a public job service (wai/wai-quantum-service): its
|
|
# tests, clippy with warnings as errors, and its smoke checks over HTTP against
|
|
# an instance started here, on Linux and on the macOS runner (the host the
|
|
# service is deployed to). Its tests also hold the command line's snapshot of
|
|
# its MCP tools (wai/wai-quantum-cli/docs/service-mcp.json) to the live list,
|
|
# and one (tests/restart.rs) kills the service mid-job and starts it again on
|
|
# its store. Each instance here keeps its job store in the runner's own
|
|
# scratch directory.
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/wai-quantum-service/**'
|
|
# The command line's agent docs list this service's tools from a snapshot
|
|
# there, which this service's tests hold to its live list.
|
|
- 'wai/wai-quantum-cli/docs/**'
|
|
- 'rust-toolchain.toml'
|
|
- '.github/workflows/wai-quantum-service.yml'
|
|
pull_request:
|
|
paths:
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/wai-quantum-service/**'
|
|
# The command line's agent docs list this service's tools from a snapshot
|
|
# there, which this service's tests hold to its live list.
|
|
- 'wai/wai-quantum-cli/docs/**'
|
|
- 'rust-toolchain.toml'
|
|
- '.github/workflows/wai-quantum-service.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-service.yml \
|
|
"${{ github.event.pull_request.base.sha }}" \
|
|
"${{ github.event.pull_request.head.sha }}")
|
|
echo "this change touches wai-quantum-service: $r"
|
|
echo "run=$r" >> "$GITHUB_OUTPUT"
|
|
|
|
service-linux:
|
|
name: service · linux
|
|
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 --component clippy
|
|
rustup default 1.98.0
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
- name: Tests and clippy
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-service
|
|
run: |
|
|
set -euo pipefail
|
|
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; }
|
|
cargo clippy --locked --release --all-targets -- -D warnings
|
|
# The engine's parts of the service, each required by name: sets and
|
|
# sweeps and their Merkle paths, a result's provenance, the package
|
|
# counter's reader and probe (on fake trees; a container hides the real
|
|
# one), and a real-valued input bound by the reader.
|
|
- name: The engine's sets, provenance and package energy
|
|
shell: bash
|
|
working-directory: wai/wai-quantum
|
|
run: |
|
|
set -euo pipefail
|
|
cargo test --locked --release --features full --lib -- engine::sets:: engine::energy:: merkle:: engine::run::tests::a_result_s_provenance qasm::tests::a_bound_parameter 2>&1 | tee "$RUNNER_TEMP/engine.log"
|
|
grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/engine.log" || { echo "::error::the engine's tests did not pass"; exit 1; }
|
|
for t in engine::sets::tests::one_receipt_binds_every_item_and_any_change_breaks_it \
|
|
engine::sets::tests::a_sweep_is_its_grid_each_point_the_program_written_out \
|
|
engine::sets::tests::a_failed_item_is_bound_by_its_error \
|
|
merkle::tests::every_leaf_s_path_leads_to_the_root_and_nothing_else_does \
|
|
engine::run::tests::a_result_s_provenance_names_the_passes_its_certificate_ran \
|
|
engine::energy::tests::the_probe_finds_a_live_counter_s_cadence_and_refuses_a_stalled_one \
|
|
engine::energy::tests::only_top_level_package_zones_are_read_and_a_frozen_one_is_not_live \
|
|
engine::energy::tests::a_package_figure_names_its_scope_and_declares_its_edges \
|
|
qasm::tests::a_bound_parameter_reads_as_the_program_written_with_its_value; do
|
|
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/engine.log" || { echo "::error::$t did not run"; exit 1; }
|
|
done
|
|
- name: The smoke checks over HTTP
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-service
|
|
run: |
|
|
set -euo pipefail
|
|
key="$RUNNER_TEMP/service.key"; rm -f "$key" "$RUNNER_TEMP/service.keys.json"
|
|
store="$RUNNER_TEMP/store"; rm -rf "$store"
|
|
cargo build --locked --release
|
|
WAI_QSVC_KEY="$key" WAI_QSVC_STORE="$store" WAI_QSVC_ADDR=127.0.0.1:18241 WAI_QSVC_BUDGET_GB=8 WAI_QSVC_JOB_GB=4 WAI_QSVC_WORKERS=2 WAI_QSVC_CLIENT_BURST=60 \
|
|
./target/release/wai-quantum-service serve 2> "$RUNNER_TEMP/service.log" &
|
|
pid=$!
|
|
trap 'kill $pid 2>/dev/null || true; cat "$RUNNER_TEMP/service.log"' EXIT
|
|
for _ in $(seq 1 50); do curl -s -o /dev/null http://127.0.0.1:18241/v1/health && break; sleep 0.2; done
|
|
bash smoke.sh http://127.0.0.1:18241
|
|
|
|
service-macos:
|
|
name: service · 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
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-service
|
|
run: |
|
|
set -euo pipefail
|
|
nice -n 10 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; }
|
|
# The single-precision state vector on this host's GPU, against the
|
|
# double-precision one; the GPU is declared, so its absence fails.
|
|
- name: The GPU state vector
|
|
shell: bash
|
|
working-directory: wai/wai-quantum
|
|
env:
|
|
WAI_QUANTUM_SV_METAL_EXPECT: "1"
|
|
run: |
|
|
set -euo pipefail
|
|
nice -n 10 cargo test --locked --release --features quantum_sv_metal --lib quantum_sv_metal 2>&1 | tee "$RUNNER_TEMP/gpu.log"
|
|
grep -qE '^test result: ok\. 4 passed; 0 failed' "$RUNNER_TEMP/gpu.log" || { echo "::error::not every GPU test ran and passed"; exit 1; }
|
|
# The cut-rank table on this host's GPU, against the double-precision
|
|
# walk; the GPU is declared, so its absence fails, and each GPU test is
|
|
# checked by name.
|
|
- name: The GPU cut-rank table
|
|
shell: bash
|
|
working-directory: wai/wai-quantum
|
|
env:
|
|
WAI_QUANTUM_CUTRANK_METAL_EXPECT: "1"
|
|
run: |
|
|
set -euo pipefail
|
|
nice -n 10 cargo test --locked --release --features quantum_cutrank_metal --lib quantum_cutrank 2>&1 | tee "$RUNNER_TEMP/cutrank-gpu.log"
|
|
for t in the_gpu_table_agrees gpu_samples_follow_the_probabilities; do
|
|
grep -q "^test quantum_cutrank::tests::$t ... ok$" "$RUNNER_TEMP/cutrank-gpu.log" \
|
|
|| { echo "::error::quantum_cutrank::tests::$t did not run and pass"; exit 1; }
|
|
done
|
|
- name: The smoke checks over HTTP
|
|
shell: bash
|
|
working-directory: wai/wai-quantum-service
|
|
run: |
|
|
set -euo pipefail
|
|
key="$RUNNER_TEMP/service.key"; rm -f "$key" "$RUNNER_TEMP/service.keys.json"
|
|
store="$RUNNER_TEMP/store"; rm -rf "$store"
|
|
cargo build --locked --release
|
|
WAI_QSVC_KEY="$key" WAI_QSVC_STORE="$store" WAI_QSVC_ADDR=127.0.0.1:18241 WAI_QSVC_BUDGET_GB=8 WAI_QSVC_JOB_GB=4 WAI_QSVC_WORKERS=2 WAI_QSVC_CLIENT_BURST=60 \
|
|
./target/release/wai-quantum-service serve 2> "$RUNNER_TEMP/service.log" &
|
|
pid=$!
|
|
trap 'kill $pid 2>/dev/null || true; cat "$RUNNER_TEMP/service.log"' EXIT
|
|
for _ in $(seq 1 50); do curl -s -o /dev/null http://127.0.0.1:18241/v1/health && break; sleep 0.2; done
|
|
bash smoke.sh http://127.0.0.1:18241
|
|
|
|
# The processor packages' counters on a Linux host that has them readable
|
|
# (the hardware runner, outside any container): the engine's live test
|
|
# required to take its live branch, and the service's smoke checks with a
|
|
# metered figure required on every job.
|
|
energy-linux:
|
|
name: service energy · linux packages
|
|
needs: relevant
|
|
if: needs.relevant.outputs.run == 'true'
|
|
runs-on: linux-hw
|
|
timeout-minutes: 90
|
|
env:
|
|
CARGO_PROFILE_RELEASE_DEBUG: '0'
|
|
CARGO_BUILD_JOBS: '8'
|
|
steps:
|
|
- name: Fetch the source
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
ref="${{ github.event_name == 'pull_request' && format('refs/pull/{0}/head', github.event.pull_request.number) || github.ref }}"
|
|
want="${{ github.event.pull_request.head.sha || github.sha }}"
|
|
rm -rf src && mkdir src && cd src
|
|
git init -q
|
|
git fetch -q --depth 1 http://100.64.224.0:3400/Transaction-Science/open-standards.git "$ref"
|
|
git checkout -q FETCH_HEAD
|
|
got="$(git rev-parse HEAD)"
|
|
echo "fetched $ref at $got"
|
|
if [ "$got" != "$want" ]; then
|
|
echo "::error::$ref is at $got, not $want: it moved after this run started, and a newer run tests it"
|
|
exit 1
|
|
fi
|
|
- name: The package counter, live
|
|
shell: bash
|
|
working-directory: src/wai/wai-quantum
|
|
env:
|
|
WAI_QUANTUM_PACKAGE_ENERGY_EXPECT: "1"
|
|
run: |
|
|
set -euo pipefail
|
|
log=$(mktemp)
|
|
CARGO_TARGET_DIR="$HOME/hw-target/wai-quantum" nice -n 10 cargo test --locked --release --features quantum_engine,quantum_receipt --lib engine::energy:: -- --nocapture --test-threads=1 2>&1 | tee "$log"
|
|
# With --nocapture the test's line follows its name on the same line.
|
|
grep -q 'package counter: {"joules_micro":' "$log" || { echo "::error::the package counter's live path never ran"; exit 1; }
|
|
- name: The service's smoke checks, every job metered
|
|
shell: bash
|
|
working-directory: src/wai/wai-quantum-service
|
|
run: |
|
|
set -euo pipefail
|
|
export CARGO_TARGET_DIR="$HOME/hw-target/wai-quantum-service"
|
|
nice -n 10 cargo build --locked --release
|
|
t=$(mktemp -d)
|
|
WAI_QSVC_KEY="$t/service.key" WAI_QSVC_STORE="$t/store" WAI_QSVC_ADDR=127.0.0.1:18244 WAI_QSVC_BUDGET_GB=4 WAI_QSVC_JOB_GB=2 WAI_QSVC_WORKERS=1 WAI_QSVC_CLIENT_BURST=60 \
|
|
"$CARGO_TARGET_DIR/release/wai-quantum-service" serve 2> "$t/service.log" &
|
|
pid=$!
|
|
trap 'kill $pid 2>/dev/null || true; cat "$t/service.log"; rm -rf "$t"' EXIT
|
|
for _ in $(seq 1 100); do curl -s -o /dev/null http://127.0.0.1:18244/v1/health && break; sleep 0.2; done
|
|
curl -sS http://127.0.0.1:18244/v1 | python3 -I -c 'import json,sys; e=json.load(sys.stdin)["energy"]; assert e["meter"]=="packages", e; print("meter:", e)'
|
|
SMOKE_EXPECT_ENERGY=1 bash smoke.sh http://127.0.0.1:18244
|