Re-landed from PR #676 (branch wai/quantum-parse-depth, merged with mainf6e302665at 0cf954bfc) as one commit on main, under the land-it model. Six review rounds; round 6's 16 findings are fixed, each with a test that fails ond5564748e. The public, anonymous job service is hardened on every route: - The reader: QEC indices refused past 2^24 and decodes capped; operator runs, else-if ladders and switches read flat at any length; real nesting bounded (Q006: 64 levels in the text, 256 through calls); arrays at most 7 dimensions. - Every read of a client's program is counted first and runs in a child capped on memory, time and answer size, covering admission, dry runs, checks, engine calls, set receipts, MCP verdicts and /v1/verify. - A result-size bound that is a true upper bound for every job kind (sampled intents' fits, trajectories, diagnostics, RFC 8785 numbers), held by a property test over random jobs, and tight where the method knows better (the stabilizer method's outcomes, a loop's verdict). - Dry runs apply exactly the run's checks, MCP's verdict included. - Turns: reading and check shares per client, a lent turn given back when others wait, at most eight waiting, J032 past them; long polls past a client's holds answer 429/503 with Retry-After and the job's status. - JSON-RPC ids echoed as sent; header and body time limits; large bodies read on one of four large-body turns, one per client. - wasmQ's /v1/verify and MCP verify go through the same admission, turns and reading child; wasmQ's profile states this reader's nesting bound. Passed on the merged tree (Framework, linux; M3, macOS): the service suite under ulimit -Sn 256 (118/119), the wai-quantum library (1,458), the CLI, wai-wasmq (67) and its 83 vectors on three engines, the engine with and without receipts, clippy -D warnings, wai breaking against main (5 acknowledged changes), and every repository check. Co-Authored-By: Claude Opus 5.5 <[email protected]>
4.1 KiB
The job service as a scheduler's resource
An on-premises batch scheduler, or a resource-management interface in front of one, can hand the job service to its batch jobs as a resource, the way it hands out processors or accelerators. The command line's wai-quantum task is the adapter. It follows the shape these interfaces share, described here by function:
| function | wai-quantum task … |
what it does |
|---|---|---|
| describe the resource | target |
the service's methods, limits, store, metering and receipt keys, as JSON |
| check it is accessible, and acquire it | acquire |
checks the service is healthy and takes this client now, and opens a lease (exit 69 if not) |
| start a task | start JOB.json |
submits a job or a set under the lease, prints its id |
| a task's state | status ID |
queued, running, done, failed, cancelled or interrupted (exit 0 done, 1 ended otherwise, 2 still active) |
| wait for a task | wait ID |
follows it to its end, each state on standard error |
| a task's result | result ID |
its request and result as JSON, the receipt checked first (exit 1 if it does not verify) |
| stop a task | stop ID |
cancels it |
| release the resource | release |
stops every task of the lease still queued or running, and closes it |
The exit statuses follow the sysexits convention batch scripts test for: 65 a job file that does not read, 69 the resource unavailable or refusing, 75 a refusal to retry later (the client's limits, a full queue).
The lease
The lease is a file: --lease, or WAI_QUANTUM_LEASE, by default wai-quantum-lease.json in the working directory. It names the service, the moment it was acquired, the service's receipt key and limits then, and every task started under it. The service itself holds no reservation: the lease is the adapter's record of what one allocation started, so that releasing it stops exactly those tasks.
Wiring it to a scheduler
A scheduler runs a prologue before a batch job starts and an epilogue after it ends, however it ends. Point both at the adapter, and give the job the service's address (and, for a private deployment, its key) in its environment:
# prologue, before the batch job: the resource must be there, and take this client
export WAI_QUANTUM_SERVICE=https://quantum.example.org/quantum-jobs
export WAI_QUANTUM_LEASE="$JOB_DIR/wai-quantum-lease.json"
wai-quantum task acquire || exit 69
# the batch job
id=$(wai-quantum task start sweep.json)
wai-quantum task wait "$id"
wai-quantum task result "$id" > result.json # checked against its receipt first
wai-quantum verify result.json # and again, by anyone, later
# epilogue, after the batch job, however it ended: no task outlives the allocation
wai-quantum task release
sweep.json is any job the service takes. A set or a sweep runs as one task, one result per item and one receipt binding them, so a parameter scan is a single task, not one per point:
{ "qasm": "OPENQASM 3.0;\ninput float theta;\nqubit[2] q;\nrx(theta) q[0];\ncx q[0], q[1];\n",
"sweep": { "theta": [0.0, 0.25, 0.5, 0.75, 1.0] },
"observables": ["Z0 Z1"] }
Before committing an allocation to it, a job can be planned without running: wai-quantum submit prog.qasm --dry-run gives the method, the memory, the estimated time and energy with their basis, the bounds that apply, and whether the service would take it now.
Limits and keys
The public service counts a client by its address. A batch system submits from a few login or compute nodes on behalf of many people, so on a shared deployment give the scheduler its own API key (WAI_QUANTUM_API_KEY, see self-host.md). Its limits are then counted by the key's name, and WAI_QSVC_CLIENT_ACTIVE, WAI_QSVC_CLIENT_GB, WAI_QSVC_CLIENT_BURST, WAI_QSVC_CLIENT_READS and WAI_QSVC_CLIENT_CHECKS (how many of its submissions and checks are read at once; more wait behind them) size them. Every answer carries the client's submission window in RateLimit-Policy and RateLimit, and a refusal past it carries Retry-After. The adapter exits 75 on such a refusal, which a scheduler can treat as "requeue".