All checks were successful
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 12s
wai-quantum for Python / does this change touch it (push) Successful in 12s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 15s
wai-quantum contract / does this change touch it (push) Successful in 14s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 30s
wai-quantum service / does this change touch it (push) Successful in 29s
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Successful in 15s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Successful in 23s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 2m4s
wai-quantum service / service energy · linux packages (push) Successful in 2m11s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 4m51s
wai-quantum for Python / python · macos (push) Successful in 4m39s
wai-quantum views in agent hosts / views · the page and its engine (push) Successful in 4m56s
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Successful in 4m48s
wai-quantum for Python / python · linux (push) Successful in 5m44s
wai-quantum views in agent hosts / views · a scripted host (push) Successful in 6m8s
wai-quantum contract / API compatibility · linux (push) Successful in 6m11s
wai-quantum service / service · macos (push) Successful in 6m33s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 8m44s
wai-quantum contract / schemas and the committed tool lists · linux (push) Successful in 9m30s
wai-quantum service / service · linux (push) Successful in 10m57s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Successful in 21m53s
The service's Linux job has been red on main sincef032d85d3, a different test each time. The line it prints, "unshare: unshare failed: Operation not permitted", is not the failure: it is the probe of the_service_runs_its_jobs_as_pid_1, run with its standard error inherited. The job container (catthehacker/ubuntu:act-22.04 under Docker's default seccomp profile, no CAP_SYS_ADMIN) is refused a user namespace, and the test then passed without running, and said so only in a line the harness swallows. What failed: -e694cb096(run 28659): tests/contract.rs's contract test, "Connection reset by peer" on its first health check, 9 ms after the binary started. Each test picked a port by binding 127.0.0.1:0 and closing it, and handed it to its service. A child another test forks in that moment (the pid 1 probe, a service) inherits the listener until its exec, so the port is held open by that copy: the test's first connection reaches it and is reset, or the next one is refused once it closes, before the service has bound the port. Reproduced on the Framework in catthehacker/ubuntu:act-24.04: 4 runs in 80 of the test binary failed so (reset at contract.rs:23, refused at :18), the ports of the two tests distinct, the service alive and listening 300 ms later. Now each service binds 127.0.0.1:0 itself and the test reads the port from its log, as tests/depth.rs does: 0 failures in 200 runs in the same container, 0 in 20 natively. -f032d85d3,009e44c2dande7c7b209b(runs 28505, 28618, 28732): tests/depth.rs's a_client_s_quick_calls_pass_two_of_its_own_long_checks. The loaded runner refused the README's threshold alone (J031, "the README's threshold is taken"), projecting from a pilot of the call's own shots that it would take 28 s, past the 25 s an error-correction call may take; or took it alone and then refused one of the two sent at once (J031, "threshold 1 #0 at 1.10 s"). Reproduced on the Framework with the test and its service held to two CPUs beside six busy loops: the README's threshold refused alone, or taken in 21 to 22 s and the second of the burst refused, projected at 25 to 27 s. The test now sizes its long check to the host: a threshold refused, or taking more than 14 s alone, has its shots scaled to the 12 s its time (or the refusal's projection) gives, at least 1000, and is sent again, at most three times; a long check past the 10 s a request waits for a turn, with room under the 25 s for two at once. Under that load main's test failed four runs in four (refused alone twice, refused in the burst twice), a version that scaled refusals alone failed two in four, and the test as it is now passed seven in seven: taken alone in 21.7 to 23.5 s and scaled to 11.3 to 12.7 s, or refused and scaled to 10.1 and 8.0 s. -655b366aa(run 28688): "No space left on device" in the runner's checkout, before any test. Not the code's. The pid 1 test now passes without running only on the kernel's refusal of the namespaces (EPERM, ENOSPC, EINVAL from unshare(2), read with LC_ALL=C), and says so on standard error past the harness's capture ("SKIPPED the_service_runs_its_jobs_as_pid_1: ..."); the workflow prints it as a warning, and its image step, which required the test's "ok", now also fails on the skip. Any other failure of the probe fails the test. Running it on CI needs a runner setting, not a weaker test: the job container given --security-opt seccomp=unconfined (or CAP_SYS_ADMIN), or a host-executor label. The service now runs under unshare --kill-child: without it, killing unshare left the service running as pid 1 of its own namespace (one left by an earlier run has been running on the Framework for 31 hours, pid 33931 there and 1 in its namespace). Gates, on the Framework: cargo test --locked --release passes, every test the workflow requires by name among them (and tests/depth.rs's 42 again with its last change), and clippy --release --all-targets -D warnings; the pid 1 test runs there natively and passes. Planted faults the tests still catch: the deadline not held (jobs.rs: contract.rs fails on the run past it), workers started from /proc/<std::process::id()>/exe, 1 in the namespace (the pid 1 test fails: J032, the reader could not start), no unshare on PATH and an unshare that fails another way (both fail the pid 1 test, neither skips), and a turn lent to a client that never goes back for the client's own waiting call (offload.rs Others::waiting: the depth test fails, a critique refused J032 after 10 s, natively and under the load). Co-Authored-By: Claude Opus 5.5 <[email protected]>
299 lines
17 KiB
YAML
299 lines
17 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,
|
|
# one (tests/restart.rs) kills the service mid-job and starts it again on its
|
|
# store, one (tests/write.rs) writes a program for a task with a scripted
|
|
# writer process, sandboxed on the macOS runner as it is in production, and
|
|
# tests/metrics.rs reads its GET /metrics strictly as its jobs move it. Each
|
|
# instance here keeps its job store in the runner's own scratch directory.
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'wai/quantum-conformance/receipts/**'
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/wai-quantum-service/**'
|
|
# The service writes programs with the writer's loop, its model on the
|
|
# loader below, both path dependencies (src/writer.rs).
|
|
- 'wai/wai-quantum-writer/**'
|
|
- 'jouleclaw/jouleclaw-rs/crates/jouleclaw-loader-gguf/**'
|
|
- 'jouleclaw/jouleclaw-rs/crates/jouleclaw-core/**'
|
|
# 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/**'
|
|
# The service answers GET /metrics with wai-metrics, and tests/metrics.rs reads the answer
|
|
# with that crate's reader.
|
|
- 'wai/wai-metrics/**'
|
|
- 'rust-toolchain.toml'
|
|
- '.github/workflows/wai-quantum-service.yml'
|
|
pull_request:
|
|
paths:
|
|
- 'wai/quantum-conformance/receipts/**'
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/wai-quantum-service/**'
|
|
# The service writes programs with the writer's loop, its model on the
|
|
# loader below, both path dependencies (src/writer.rs).
|
|
- 'wai/wai-quantum-writer/**'
|
|
- 'jouleclaw/jouleclaw-rs/crates/jouleclaw-loader-gguf/**'
|
|
- 'jouleclaw/jouleclaw-rs/crates/jouleclaw-core/**'
|
|
# 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/**'
|
|
# The service answers GET /metrics with wai-metrics, and tests/metrics.rs reads the answer
|
|
# with that crate's reader.
|
|
- 'wai/wai-metrics/**'
|
|
- 'rust-toolchain.toml'
|
|
- '.github/workflows/wai-quantum-service.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-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.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 --component clippy
|
|
rustup default 1.99.1
|
|
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; }
|
|
grep -q '^test the_service_gives_every_receipt_the_verdict_the_corpus_gives_it \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service was not held to the corpus of receipts"; exit 1; }
|
|
grep -q '^test jobs::tests::a_route_s_figure_is_an_estimate_and_what_reads_the_run \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service's routes did not say what reads them"; exit 1; }
|
|
grep -q '^test energy::tests::a_mac_whose_counter_reads_nothing_has_no_meter \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::a Mac that reads nothing was given a meter"; exit 1; }
|
|
grep -q '^test a_job_is_stopped_at_its_energy_ceiling_and_its_receipt_says_so \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service did not stop a job at its ceiling"; exit 1; }
|
|
# A job under a contract: met or refused with every route's reason, never routed to a
|
|
# provider, stopped at its deadline, and its reasoning kept across a restart.
|
|
for t in a_contract_is_met_or_refused_and_the_service_never_reaches_a_provider \
|
|
jobs::tests::a_contract_job_keeps_its_reasoning_across_a_restart \
|
|
the_service_answers_metrics_that_move_with_its_jobs; do
|
|
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; }
|
|
done
|
|
# tests/contract.rs runs the service as pid 1 of a user and pid namespace of its own.
|
|
# This job's container (no CAP_SYS_ADMIN, Docker's default seccomp profile) is refused
|
|
# the namespaces, so the test reports ok without running and prints why; the image
|
|
# step below runs the service as a container's pid 1 where an engine is at hand.
|
|
if grep -q 'SKIPPED the_service_runs_its_jobs_as_pid_1' "$RUNNER_TEMP/test.log"; then
|
|
echo "::warning::$(grep -o 'SKIPPED the_service_runs_its_jobs_as_pid_1.*' "$RUNNER_TEMP/test.log" | head -1)"
|
|
fi
|
|
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.
|
|
# The bound on a result the service admits a job by (a circuit's, a
|
|
# set's and a pulse run's): no result passes it, for jobs of every kind
|
|
# drawn at random, and it is close where the method knows its outcomes.
|
|
- name: The engine's sets, provenance, result bounds 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 engine::run::tests::no_result_passes_the_bound engine::pulse::tests::no_pulse_result_passes_the_bound engine::bound_tests:: 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::run::tests::no_result_passes_the_bound_its_plan_gave \
|
|
engine::pulse::tests::no_pulse_result_passes_the_bound_its_plan_gave \
|
|
engine::bound_tests::no_random_job_s_result_passes_its_bound \
|
|
engine::bound_tests::a_failing_intent_trajectories_and_notes_stay_within_their_bounds \
|
|
engine::bound_tests::a_ghz_state_and_a_long_loop_are_bounded_by_what_they_can_list \
|
|
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 \
|
|
engine::energy::tests::a_host_s_estimate_rests_on_its_own_runs_and_says_whose \
|
|
engine::energy::tests::a_live_reading_stops_at_the_ceiling_and_a_silent_second_loses_it \
|
|
engine::energy::tests::an_exited_read_far_below_its_cpu_time_is_no_reading \
|
|
engine::energy::tests::a_package_counter_added_up_read_by_read_keeps_every_range \
|
|
engine::energy::tests::a_counter_s_reading_is_trusted_only_within_one_wrap \
|
|
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
|
|
# The image as it ships: built, run with the service as the container's first
|
|
# process (pid 1, no --init, as deploy/Containerfile and docs/self-host.md run
|
|
# it), and held to the same smoke checks, which run jobs through its workers.
|
|
# A runner with no container engine says so; one with an engine must pass.
|
|
- name: The image as it ships
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if command -v podman >/dev/null 2>&1; then engine=podman
|
|
elif command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then engine=docker
|
|
else echo "::warning::this runner has no container engine, so the shipped image was not run"; exit 0; fi
|
|
ENGINE=$engine JOBS=8 bash wai/wai-quantum-service/deploy/check-image.sh
|
|
# Its own test passed, and ran: a skip reports ok as well, and says so in its line.
|
|
grep -q '^test the_service_runs_its_jobs_as_pid_1 \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service was not run as pid 1"; exit 1; }
|
|
if grep -q 'SKIPPED the_service_runs_its_jobs_as_pid_1' "$RUNNER_TEMP/test.log"; then echo "::error::the_service_runs_its_jobs_as_pid_1 did not run: the kernel refused its namespaces"; exit 1; fi
|
|
|
|
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
|