Some checks failed
wai-audit collector and player integration / does this change touch it (push) Successful in 21s
WAI operation catalogue / does this change touch it (push) Successful in 21s
wai-quantum clippy / does this change touch it (push) Successful in 23s
wai-quantum command line / does this change touch it (push) Successful in 27s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 21s
wai-quantum error correction and mitigation / does this change touch it (push) Successful in 15s
wai-quantum qudit jobs / does this change touch it (push) Successful in 18s
wai-quantum for Python / does this change touch it (push) Successful in 22s
wai-quantum extension points / does this change touch it (push) Successful in 23s
wai-quantum service / does this change touch it (push) Successful in 24s
wai-quantum studio and desktop / does this change touch it (push) Successful in 21s
wai-quantum studio and desktop / desktop app · windows (push) Waiting to run
wai-quantum service / service energy · linux packages (push) Failing after 8s
wai-quantum variational and algorithm library / does this change touch it (push) Successful in 26s
wai-quantum verdicts and repairs / does this change touch it (push) Successful in 19s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 19s
wai-quantum on Windows / does this change touch it (push) Successful in 32s
wai-sink-android native sink library / does this change touch it (push) Successful in 21s
wai-quantum on Windows / engine · windows (push) Waiting to run
wai-quantum on Windows / command line · windows (push) Waiting to run
wai-quantum on Windows / job service · windows (push) Waiting to run
wai-quantum on Windows / python · windows (push) Waiting to run
wai-sink-swift native sink package / does this change touch it (push) Successful in 25s
wai-quantum for JavaScript / does this change touch it (push) Successful in 2m37s
WAI Studio / does this change touch it (push) Successful in 12s
wai-quantum OpenQASM reader / does this change touch it (push) Successful in 2m43s
wai-quantum editors / does this change touch it (push) Successful in 2m55s
wai-quantum pulse and dynamics / does this change touch it (push) Successful in 2m42s
wai-quantum contract / does this change touch it (push) Successful in 2m59s
wai-quantum other formats / does this change touch it (push) Successful in 2m48s
wai-quantum-landscape-fpga reference design / does this change touch it (push) Successful in 2m45s
wai-quantum resource estimation / does this change touch it (push) Successful in 2m51s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 11s
WAI examples / WAI examples · does this change touch them (push) Successful in 22s
wai-quantum landscape stage 0, the sampler against the exact law / does this change touch it (push) Successful in 10s
wai-quantum landscape energy to solution / does this change touch it (push) Successful in 17s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 12s
wai-audit collector and player integration / collector · linux (push) Successful in 3m47s
wai-quantum clippy / clippy, warnings denied, every feature set · linux (push) Successful in 3m46s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Successful in 16s
wai-quantum wasmQ / does this change touch it (push) Successful in 19s
wai-quantum qudit jobs / the module and the conformance set under wasm32-wasip2 (wasmtime) (push) Successful in 2m28s
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Successful in 3m53s
wai-quantum studio and desktop / studio · browser (push) Successful in 4m10s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 12m50s
wai-quantum extension points / the registry under wasm32-wasip2 (wasmtime) (push) Successful in 5m9s
wai-quantum verdicts and repairs / the intent set and the verdict under wasm32-wasip2 (wasmtime) (push) Successful in 1m37s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux, release (push) Successful in 2m35s
wai-quantum verdicts and repairs / verdicts, repairs and the intent set · linux (push) Successful in 2m58s
wai-quantum error correction and mitigation / codes, decoders, texts and mitigation · linux, release (push) Successful in 10m5s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 2m21s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 7m30s
wai-quantum OpenQASM reader / corpus under wasm32-wasip2 (wasmtime) (push) Successful in 51s
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Successful in 13s
wai-quantum qudit jobs / the module, the job, the conformance set, the referee and the verb · linux (push) Successful in 12m45s
wai-quantum views in agent hosts / views · the page and its engine (push) Successful in 4m54s
wai-quantum extension points / the registry and the example · linux (push) Successful in 11m13s
wai-quantum for JavaScript / javascript · linux (push) Successful in 4m55s
wai-quantum for Python / python · linux (push) Successful in 12m31s
wai-quantum OpenQASM reader / reader and corpus · linux (push) Successful in 4m0s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime) (push) Successful in 1m22s
wai-quantum command line / command line · linux (push) Successful in 19m37s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs · linux, release (push) Successful in 3m20s
wai-quantum editors / editors · linux (push) Successful in 3m41s
wai-quantum other formats / the set under wasm32-wasip2 (wasmtime) (push) Successful in 3m7s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 2m44s
wai-quantum landscape stage 0, the sampler against the exact law / the small tier, to the byte · linux (push) Successful in 1m4s
wai-quantum service / service · linux (push) Successful in 17m3s
wai-quantum landscape energy to solution / the small tier, to the byte · linux (push) Successful in 2m23s
wai-quantum views in agent hosts / views · a scripted host (push) Successful in 14m9s
wai-quantum contract / schemas and the committed tool lists · linux (push) Successful in 10m9s
wai-quantum other formats / readers, writers and the set · linux (push) Successful in 9m28s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 7m43s
wai-quantum contract / API compatibility · linux (push) Successful in 11m25s
wai-quantum wasmQ / the reference modules rebuild to their modules of record · linux (push) Successful in 34s
WAI Studio / Studio in WebKit · linux (push) Successful in 14m43s
wai-quantum resource estimation / estimation and calibration · linux, release (push) Successful in 10m56s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 8m32s
wai-quantum wasmQ / interpreter and vectors under wasm32-wasip2 (wasmtime) (push) Successful in 6m27s
WAI examples / WAI examples · portable · linux (push) Successful in 11m57s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · linux (push) Successful in 8m56s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 13m28s
wai-quantum-landscape-fpga reference design / the member against the model of the logic, and the logic against the model · linux, release (push) Successful in 22m33s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 17m1s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Successful in 40m14s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m13s
wai-quantum command line / command line · macos (push) Successful in 2m55s
wai-quantum qudit jobs / the same bits · macos (push) Successful in 1m47s
wai-quantum for Python / python · macos (push) Successful in 3m41s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 5m34s
wai-quantum service / service · macos (push) Successful in 7m44s
wai-quantum editors / editors · macos (push) Successful in 1m53s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 9m39s
wai-quantum pulse and dynamics / the same bits · macos (push) Successful in 1m33s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 6m5s
wai-quantum landscape stage 0, the sampler against the exact law / the small tier, to the byte · macos (push) Successful in 33s
wai-quantum extension points / the registry and the example · linux-arm64 (push) Successful in 7m49s
wai-quantum landscape energy to solution / the small tier, to the byte · macos (push) Successful in 2m5s
wai-quantum-landscape-fpga reference design / the board's code on the board's processor's architecture · linux-arm64, release (push) Successful in 1m50s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux-arm64, release (push) Successful in 4m21s
wai-quantum pulse and dynamics / the same bits · linux-arm64 (push) Successful in 3m11s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 11m4s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 7m36s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 10m54s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · macos (push) Successful in 2m40s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (push) Successful in 21m33s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Failing after 28m52s
WAI examples / WAI examples · android-app · linux-arm64 (push) Successful in 15m51s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 19m35s
The sign-off loop (check, grade, attest;4b17804c2) ran on the command line and its MCP server. It now runs wherever the engine does, with the same answers. - engine::front holds the check, the attestation and the loop's MCP tools (check_quantum_program, grade_quantum_program, attest_quantum_job, in one wording with the sealer named), which the command line, both MCP servers, the Python package and the npm package call; the command line keeps its flags and its printing. The output schemas of check and attest move from the command line's local-tools.v1.json into the engine's tools.v1.json ($defs/check, $defs/attest), which both servers name. - The job service serves the three tools on its MCP server and as POST /v1/check, /v1/grade and /v1/attest (GET /v1, the OpenAPI document and the README list them), a grade and a sign-off sealed with its own key, their energy unmetered with the reason. Each is counted as a check, held to its bounds and made in a reading child, each case within half the child's memory. A check of a task, a grade, and a sealed grade POST /v1/verify works out again are now held case by case (analysis::grade_bounds: each case's intent that compares the program with a reference held to the equivalence check's bound with the program written out at that case's inputs, and the task's job read as a job's is), where before a grade was remade within the reading child's budget whole; a case past them is refused at that case (J031, "case N: ...", naming wai-quantum grade). An attestation holds what verifying the job works out again and the intent its sign-off checks to the same bounds (naming wai-quantum attest). - Python: wq.check, wq.grade, wq.attest (and _engine.check/grade/attest); npm: QuantumEngine.check, .grade, .attest; each with a test (test_engine.py, smoke.mjs, a wasm32 test in wai-web) and a README example. - The instructions both MCP servers give at initialize describe the loop (guide::LOOP), and the committed lists (docs/local-mcp.json, docs/service-mcp.json), llms.txt, llms-full.txt and the skill's tools.md are written again from the live lists. - A whole task set graded: wai-quantum grade --set FILE --programs ANSWERS (the model harness's set; the programs a JSON object of programs or of a model's answers as eval run --scripted reads them, or a directory of NAME.qasm files), or --course --programs DIR; engine::grade::batch, wai.quantum.grades/1 (schemas/grades.v1.json), quantum-providers §8.10 "A task set graded": one sealed grade a task, missing and refused tasks said so, the set's digest and a summary. The batch is not sealed; wai-quantum verify works it out again (grade::check_batch): each grade checked and made again, each entry's name and grade held to what its grade seals, a refused entry refused again, the digest and the summary made again from the sealed results. The same set, programs and key give the same bytes. quantum-conformance/grades/ holds a batch and six changed ones with what a reader must say (written by hand from §8.10), natively and under wasm32-wasip2 (tests/grades_conformance.rs), including one that shows what a batch does not: a grade dropped as missing with the summary made to agree is valid; that a task had no program is the grader's statement. - wai-web's pinned digest of a level-2 compile (COMPILE_DIGEST) follows the compile of7c00ef138, which writes each region of CNOT and phase gates again at level 2 and so changed those sealed bytes; wai-web wasm32 runs on pull requests and nightly only, so nothing had run it since. Native and wasm32 give the new digest alike. The npm smoke runs the loop on an engine of 1 GiB: one of 256 MiB says an intent's exact check is unchecked, and why (asserted too). - Which trust list an attester used stays outside the seal: sealing it would add a member to the sign-off's closed request, which every released verifier refuses (J001), and it would show only which keys the attester trusted, which is each reader's to decide; the changes entry and the skill say so. Tests: engine::front, engine::grade (the batch), the guide's instructions, service analysis (bounds case by case), mcp (an agent runs the loop over the service's server; every tool's answer held to its output schema), verify.rs (the loop over HTTP in a running service, its grade and sign-off verified), the command line's front_door.rs (a whole set graded through the binary, verified, a changed summary found) and check_schemas.py (the batch and an attestation held to their schemas). wai-quantum-verdict.yml, -service.yml, -cli.yml and wai-web-wasm.yml require the new tests by name. schema::FILES gains grades.v1.json (acknowledged in the changes entry). Co-Authored-By: Claude Opus 5.5 <[email protected]>
1925 lines
136 KiB
Markdown
1925 lines
136 KiB
Markdown
# WAI Extension: Quantum Providers (`wai.quantum.provider/1`)
|
||
|
||
Status: **Draft.** Client, reference provider and conformance checker:
|
||
`wai-quantum-qpu` (`src/open_provider.rs`, `src/reference.rs`,
|
||
`src/conformance.rs`); vectors: `wai-quantum-qpu/conformance/provider-v1.json`.
|
||
The engine's side of a provider job: `wai-quantum/src/engine/provider.rs`.
|
||
|
||
Keywords **MUST**, **MUST NOT**, **SHOULD** and **MAY** are RFC 2119/8174.
|
||
|
||
## 0. What this extension adds
|
||
|
||
Bring your own quantum. WAI provides the engine, the free job service and the
|
||
verifier at no cost, and never pays for or resells time on anyone's hardware.
|
||
A person connects their own quantum hardware, provider accounts, on-premises
|
||
devices or simulators, and every surface treats a provider's result as it
|
||
treats a WAI result: planned, its cost shown before it is submitted, checked,
|
||
and sealed in a receipt.
|
||
|
||
This text is the protocol a device speaks so that it can be brought without a
|
||
client written for it: JSON messages, one request and one answer at a time,
|
||
over HTTP or to a local process (§2). Six operations (§5) describe the
|
||
device, estimate a job, submit it, follow it, read its counts and cancel it.
|
||
A program travels in the device's own native gates, with every angle an exact
|
||
fraction of a turn (§4), so the program the device runs is the one the client
|
||
compiled and checked. A device may also take energy-landscape jobs
|
||
([quantum-landscape](quantum-landscape.md), and its second version,
|
||
[quantum-landscape-2](quantum-landscape-2.md)), which carry no circuit: they travel in
|
||
that extension's own form, and come back as its answer (§11).
|
||
|
||
A provider is the program or service that answers the messages. A device is
|
||
what it runs programs on: a processor, an emulator or a simulator. A client
|
||
is what sends the messages; a host is the client's process, which holds the
|
||
person's credential and signing key (the command line, the desktop app).
|
||
|
||
## 1. Principles
|
||
|
||
1. **The credential stays with the person.** A host keeps a provider's
|
||
credential in the operating system's keychain (or, where there is none, a
|
||
file only its owner can read, labelled as such) and sends it only to that
|
||
provider (§2). A credential MUST NOT appear in a browser page, a log, a
|
||
receipt, a command line, an answer the host prints, or the hosted job
|
||
service. The job service never routes a job to a provider and never takes
|
||
a credential: a request that names a provider is refused there.
|
||
2. **Cost before submit.** A client MUST show a job's estimate (§5.2) before
|
||
it submits the job, and MUST NOT submit a job that is not free without the
|
||
person's explicit confirmation (§7). An unknown cost is not free.
|
||
3. **Exact programs.** A client compiles a circuit exactly to the device's
|
||
native gates and connectivity and checks the compiled program against the
|
||
circuit before sending it. Angles cross the wire exactly (§4).
|
||
4. **Returned, not recomputed.** A provider's counts are sealed as the device
|
||
it names returned them (§8): `measured` for a processor, `simulated` for a
|
||
simulator or an emulator, which no device measured. The result says where
|
||
the counts come from, since counts rebuilt from probabilities are derived
|
||
and not shot records, and what was set off at the provider. Nothing
|
||
recomputes them.
|
||
|
||
## 2. Transports
|
||
|
||
Every message is a JSON object, and so is every answer. A client sends one
|
||
message and reads its answer before it sends the next on the same transport.
|
||
|
||
### 2.1 HTTP
|
||
|
||
A message is the body of a `POST` to the provider's endpoint (one URL for
|
||
every operation), with `Content-Type: application/json`. The answer is the
|
||
body of a `200` response, also for an answer with `"ok": false` (§3). Any
|
||
other status is a transport failure, not an answer.
|
||
|
||
A credential, when there is one, goes in `Authorization: Bearer <credential>`.
|
||
A client MUST NOT send a credential over `http://` to any host but this
|
||
machine (`localhost`, a loopback address); over the network it uses
|
||
`https://`.
|
||
|
||
### 2.2 A local process
|
||
|
||
The provider is a program the person names, with its arguments, started by
|
||
the client without a shell. Each message is one line of JSON on the program's
|
||
standard input; each answer is one line of JSON on its standard output, in
|
||
order. The program MUST write nothing else to its standard output. Its
|
||
standard error is its own log, and a client MAY discard it. The program runs
|
||
until its standard input ends.
|
||
|
||
A credential, when there is one, is in the program's environment as
|
||
`WAI_PROVIDER_CREDENTIAL`, never on its command line. A client SHOULD NOT
|
||
pass the program another provider's credential.
|
||
|
||
## 3. Messages and errors
|
||
|
||
Every message carries:
|
||
|
||
| field | |
|
||
|---|---|
|
||
| `protocol` | `"wai.quantum.provider/1"` |
|
||
| `op` | `describe`, `estimate`, `submit`, `status`, `result` or `cancel` |
|
||
| `settings` | optional: the person's non-secret settings for this provider (a device name, a region), passed as they are |
|
||
|
||
and the operation's own fields (§5). Every answer carries `"ok": true` and
|
||
the operation's fields, or:
|
||
|
||
```json
|
||
{ "ok": false, "error": { "code": "not_found", "message": "no job j-17" } }
|
||
```
|
||
|
||
The `message` is for a person; it MUST NOT quote a credential. The codes:
|
||
|
||
| code | when |
|
||
|---|---|
|
||
| `invalid` | the message is malformed: a field missing or of the wrong type, a program that does not read (§4), zero shots, a message without `protocol` |
|
||
| `unsupported` | an operation the provider does not offer (`cancel`, `estimate`), or an `op` it does not know |
|
||
| `unsupported_version` | a `protocol` other than this one |
|
||
| `unauthorized` | no credential, or one the provider does not accept |
|
||
| `not_found` | a job the provider does not hold |
|
||
| `refused` | a well-formed program the device cannot run: a gate outside its basis, a qubit it does not have, a pair it does not connect, a resonator used out of turn (§4), too many shots; or a result asked of a job that has not finished or was cancelled |
|
||
| `quota` | the person's account cannot pay for or schedule the job |
|
||
| `unavailable` | the device is offline or in maintenance |
|
||
| `internal` | anything else |
|
||
|
||
## 4. The program
|
||
|
||
`estimate` and `submit` carry a `program` in the device's own gates, on its
|
||
physical qubits:
|
||
|
||
```json
|
||
{
|
||
"format": "wai.native/1",
|
||
"basis": "rzsxxcz",
|
||
"bits": 2,
|
||
"gates": [
|
||
{ "gate": "rz", "qubits": [0], "turns": [[1, 2]] },
|
||
{ "gate": "sx", "qubits": [0] },
|
||
{ "gate": "cz", "qubits": [0, 1] }
|
||
],
|
||
"measure": [{ "qubit": 0, "bit": 0 }, { "qubit": 1, "bit": 1 }],
|
||
"qasm3": "OPENQASM 3.0; …"
|
||
}
|
||
```
|
||
|
||
- `basis` is one of four gate sets, and every gate is of it:
|
||
|
||
| basis | gates |
|
||
|---|---|
|
||
| `rzsxxcz` | `rz(t)`, `sx`, `x`, `cz` |
|
||
| `prxcz` | `prx(t, p)`, `cz` |
|
||
| `gpizz` | `gpi(p)`, `gpi2(p)`, `zz(t)` |
|
||
| `prxrzxx` | `prx(t, p)`, `rz(t)`, `xx(t)` |
|
||
|
||
A program in `rzsxxcz` or `prxcz` may also hold `move` on a device with
|
||
computational resonators (below).
|
||
|
||
- An angle is a fraction of a full turn, `[m, k]` meaning `m/2^k` of 2π, with
|
||
`0 ≤ m < 2^k` and `k ≤ 32`, so every angle crosses the wire exactly. The
|
||
gates, as operators on the named qubits, up to a global phase:
|
||
- `rz(t)` = exp(−iπt·Z); `sx` = √X; `x` = X; `cz` = diag(1, 1, 1, −1);
|
||
- `prx(t, p)` = Rz(2πp)·Rx(2πt)·Rz(−2πp);
|
||
- `gpi(p)` = Rz(2πp)·X·Rz(−2πp); `gpi2(p)` = Rz(2πp)·Rx(π/2)·Rz(−2πp);
|
||
- `zz(t)` = exp(−iπt·Z⊗Z);
|
||
- `xx(t)` = exp(−iπt·X⊗X), the two-qubit gate of the Mølmer–Sørensen
|
||
type: `xx(¼)` = exp(−iπ/4·X⊗X) entangles fully. It is OpenQASM's
|
||
`rxx(2πt)`, and a device that takes its angle θ in units of π, as
|
||
exp(−iπθ/2·X⊗X), takes θ = 2t: `xx(¼)` is θ = ½, and every angle stays
|
||
exact. In `prxrzxx`, `xx(t)` takes 0 ≤ t ≤ ¼ and `prx(t, p)` takes
|
||
0 ≤ t ≤ ½, the ranges devices of that gate set take; a client writes
|
||
`cz` as `xx(¼)` between `prx(¼, ¼)` (Ry(π/2)) on each qubit before and
|
||
`prx(¼, ¾)` (Ry(−π/2)) after, the `Z` rotations it leaves carried in the
|
||
phases, so no program it compiles needs more;
|
||
- `move` on `[q, r]`, a qubit and a computational resonator (§5.1): the
|
||
qubit's state into the empty resonator, leaving the qubit in |0⟩, or back
|
||
out to the qubit that moved it in. It is defined only while one of the
|
||
two holds |0⟩, where it exchanges their states up to a phase the device
|
||
leaves undefined (on |qubit, resonator⟩: |10⟩ → a*·|01⟩ in, |01⟩ →
|
||
a·|10⟩ out), which the `move` back cancels.
|
||
- A program uses a resonator in turn: a `move` into a resonator only when it
|
||
is empty, by a qubit whose state is in no resonator; the `move` out by the
|
||
qubit that moved in; no gate on that qubit between the two; only `move`
|
||
and `cz` on a resonator, which is never measured; and every resonator empty
|
||
at the end. A `cz` between a qubit that moves into a resonator and one
|
||
coupled to it is then `move · cz(partner, resonator) · move`, whatever `a`
|
||
is.
|
||
- `measure` gives, for each classical bit `0 … bits − 1`, the physical qubit it
|
||
reads at the end of the program. Every bit reads exactly one qubit, and no
|
||
qubit is read twice.
|
||
- `qasm3` is the same program as OpenQASM 3 on physical qubits (`$p`), the
|
||
`prxcz`, `gpizz` and `prxrzxx` gates defined in it from the standard gates
|
||
(`xx` in radians, as `rxx`), and `move` as the exchange it is on every state
|
||
a program in turn reaches, for a provider that reads OpenQASM. It is
|
||
informative: where the two differ, the `gates` are the program.
|
||
|
||
A provider MUST refuse (`invalid`) a program of another `format`, a gate
|
||
outside its `basis` (a `move` outside `rzsxxcz` and `prxcz`), an angle out of
|
||
range (in `prxrzxx`, an `xx` past ¼ or a `prx` past ½ of a turn), or a bit
|
||
that reads no qubit; and (`refused`) a program in a basis its device does not
|
||
run, that uses a resonator out of turn, or on qubits or pairs it does not
|
||
have.
|
||
|
||
## 5. Operations
|
||
|
||
An energy-landscape job carries `landscape` in place of `program` and `shots` in
|
||
`estimate` and `submit`, and its `result` carries the landscape answer in place of
|
||
counts: §11 says how. `describe`, `status` and `cancel` are the same for every job.
|
||
|
||
### 5.1 `describe`
|
||
|
||
No fields. The answer describes the device:
|
||
|
||
| field | |
|
||
|---|---|
|
||
| `protocol` | `"wai.quantum.provider/1"` |
|
||
| `provider`, `device` | the provider's name for itself, and the device's |
|
||
| `provenance` | `silicon` (a processor), `emulator`, or `simulator`; with `simulator` (or `emulator`) a sentence naming what it is, in the member of that name (`"simulator": "…"`) |
|
||
| `qubits` | the device's qubit count; with `resonators`, the count of its places, the resonators among them |
|
||
| `native_gates` | the gates it runs; a client compiles to the first of the bases of §4 whose every gate is listed (`rzsxxcz`, `prxcz`, `gpizz`, `prxrzxx`), and a device with resonators lists `move` too |
|
||
| `connectivity` | `"all"`, or the pairs `[a, b]` a two-qubit gate may act on, in either order; a pair with a resonator is where `cz` acts between that qubit and the resonator |
|
||
| `resonators` | optional: the places, among `0 … qubits − 1`, that are computational resonators rather than qubits (a star device's qubits sit round one). A resonator takes no one-qubit gate, is never measured and pairs with no other resonator; a client places no logical qubit on it and compiles to it only in `rzsxxcz` or `prxcz` (§4) |
|
||
| `moves` | optional, with `resonators`: each `[qubit, resonator]` on which `move` runs. A client reaches two qubits through a resonator when one moves into it and the other is coupled to it |
|
||
| `durations` | optional: `{"unit", "gates", "measure"}`: the unit (`ns`, `us`, `ms` or `s`), each native gate's duration wherever it runs (`{"sx": 35, "cz": 68}`), and the measurement's |
|
||
| `calibration` | `{"id"}`, the calibration snapshot the device is under; optionally `qubits` (`{"qubit", "readout_error", "error_1q", "t1_us", "t2_us"}`) and `edges` (`{"qubits": [a, b], "error"}`), each error from 0 to 1 |
|
||
| `billing` | one of three forms: `{"free": true}`, the device is free to use; `{"unit", "price", "currency"}`: the billing unit (`shot`, `job`, `second`, …), the price of one as a decimal string (`"0.0003"`), and the currency or credit it is in; or `{"free": false, "priced": false}`: the device is not free, and the provider sets no price (below). `priced` is in the third form only, which holds no `unit`, `price` or `currency`. In any form, optionally `free_tier`, the free use offered and its limits, as the provider states them |
|
||
| `max_shots` | optional: the most shots a job may ask |
|
||
| `seeded` | optional: `true` when a job's `seed` makes its counts reproducible (a simulator) |
|
||
| `approximate` | optional, with `simulator` or `emulator`: `true` when its results are approximate (a truncated tensor network, a sampled Pauli path); a result is then labelled so (§8.1) |
|
||
| `cancels` | optional: `false` when it cannot cancel a job it took (§5.6), so that a client can say so before it sends one |
|
||
| `landscape` | optional: the energy-landscape jobs it takes (§11.1) |
|
||
|
||
A client MUST NOT take a device to be free unless `billing` says
|
||
`"free": true`, or an estimate says so (§5.2).
|
||
|
||
A device whose `billing` sets no price is not free, and a job on it that no
|
||
estimate prices has an unknown cost, wherever that cost is shown or sealed: a
|
||
client shows the cost as unknown and submits the job only on the person's
|
||
confirmation for that run (§7), and the receipt records its estimate as
|
||
unknown (§8.1). It is the form for a provider that has no prices yet. A
|
||
`billing` of none of the three forms (`{}`, `{"free": false}`) states nothing:
|
||
a client takes the cost to be unknown all the same, and the checker refuses
|
||
the description (§9).
|
||
|
||
A client MAY read a `describe` answer whose `calibration` states errors as a
|
||
device target (`wai.quantum.target/1`, `wai-quantum/src/engine/targets`)
|
||
and place the program on the qubits and pairs most likely to succeed. The
|
||
program it sends is checked against the circuit as every program is (§1), and
|
||
the receipt names how it was placed (§8).
|
||
|
||
### 5.2 `estimate`
|
||
|
||
Fields: `program` (§4), `shots`. The answer, before anything is submitted:
|
||
|
||
| field | |
|
||
|---|---|
|
||
| `free` | whether this job is free |
|
||
| `amount`, `currency` | when it is priced: the cost, the amount as a decimal string |
|
||
| `priced` | in the unpriced form only, and `false` there (below) |
|
||
| `unit` | optional, when it is priced: the billing unit the cost counts |
|
||
| `seconds` | optional: how long it is expected to take, queue included |
|
||
| `at_least` | optional, when it is priced: `true` when the amount is only the least the job can come to, as with a device billed by the time a job turns out to take |
|
||
| `note` | optional |
|
||
|
||
An answer is in one of three forms: **free**, `"free": true`; **priced**,
|
||
`"free": false` with a decimal `amount` and a `currency`; or **unpriced**,
|
||
`{"free": false, "priced": false}` with no `amount`, `currency`, `unit` or
|
||
`at_least`. The unpriced form is the estimate of a job the provider can take and
|
||
count but sets no price for, as `billing`'s third form is of a device (§5.1). It
|
||
is answered as any estimate is, after the job has been read and checked as
|
||
`submit` would check it, so a job the device cannot run is refused here; and it
|
||
states what the job's form counts: a landscape job's `operations` and `bytes`
|
||
(§11.2), and for a circuit nothing beyond `seconds` and `note`. It holds the
|
||
person to no amount and states none: the job's cost is unknown. A client shows
|
||
the estimate as unknown beside its counts, submits the job only on the person's
|
||
confirmation for that run (§7), records the estimate in the receipt as an
|
||
unknown cost (§8.1), and takes it to meet no cost ceiling (§8.7,
|
||
`cost_unknown`). An answer of none of the three forms (`{"free": false}` alone, an
|
||
amount that is a number, an amount with no currency, `priced` beside an amount, a
|
||
unit, `at_least` or `"free": true`, `priced` `true`, or `priced` of another type)
|
||
is refused: the client takes the cost to be unknown and shows no figure of it.
|
||
|
||
A provider that cannot estimate answers `unsupported`; the client then treats
|
||
the cost as unknown (§7). A provider that can count a job but has no price for it
|
||
answers the unpriced form rather than `unsupported`, so that its counts reach the
|
||
person: a counted job's operations and memory are not only in a sentence.
|
||
|
||
### 5.3 `submit`
|
||
|
||
Fields: `program`, `shots`, and optionally `seed` (a seeded simulator uses
|
||
it; a device ignores it). The answer's `job` is the job's id.
|
||
|
||
### 5.4 `status`
|
||
|
||
Field: `job`. The answer's `status` is `queued`, `running`, `done`, `failed`
|
||
or `cancelled`, with an optional `reason`.
|
||
|
||
### 5.5 `result`
|
||
|
||
Field: `job`. The answer, once the job is `done`:
|
||
|
||
| field | |
|
||
|---|---|
|
||
| `counts` | an object from outcomes to counts (§6), summing to the shots, or to `accepted_shots` when it is given |
|
||
| `shots` | the shots |
|
||
| `accepted_shots` | optional: the shots the device kept, when it kept another number than asked (a post-selected or heralded readout discards the shots that fail its test; a device may run more than asked), a whole number of at least 1. The counts are of these shots. A client refuses counts that do not sum to it, or, when it is not given, to the shots |
|
||
| `calibration` | optional: the calibration snapshot the job ran under, when it is not the one `describe` names |
|
||
| `charged` | optional: `{"amount", "currency"}`, what the job cost |
|
||
| `energy` | optional: `{"kwh"}`, the provider's own figure for the job's energy |
|
||
| `counts_source` | optional: where the counts come from (§8.3): `shots` (tallied from one record a shot), `vendor_counts` (the device's or service's own counts), or `probabilities` (rebuilt from probabilities); an answer without it is read as `vendor_counts` |
|
||
| `execution` | optional: how the device ran the program (§8.3): each of `mitigation`, `twirling`, `decoupling`, `remapping` and `optimisation` as `off`, `on`, `none` (the device has no such step) or `unknown` (a step the provider cannot vouch for), `verbatim` (`true` when the gates ran as written, on the qubits named), and an optional `note` |
|
||
|
||
A `result` asked twice of the same job MUST give the same counts.
|
||
|
||
A provider that relays a job to another service (a wrapper around a service's
|
||
own interface) MUST give `execution`, from what it sets in its own request, and
|
||
MUST give `counts_source`, `probabilities` when it rebuilds counts from them.
|
||
Each is the provider's word, and sealed as such (§8.3). A client refuses a
|
||
`counts_source` or an `execution` not of the form above, and seals nothing.
|
||
|
||
### 5.6 `cancel`
|
||
|
||
Field: `job`. The answer's `status` is `cancelled`; or, for a job that had
|
||
already ended, how it ended: `done` for one that had finished, and `failed`,
|
||
with its `reason`, for one that had failed. A provider that cannot cancel
|
||
answers `unsupported`.
|
||
|
||
### 5.7 A job outlasts its client
|
||
|
||
A device's queue can outlast any process waiting on it, so a job is not tied to
|
||
the connection or the process that submitted it. A provider SHOULD answer
|
||
`status` and `result` for a job's id from any later connection, and SHOULD keep
|
||
a finished job's result for as long as it can, and answers `not_found` for one
|
||
it no longer holds. A provider that runs as a local process (§2.2) ends with its
|
||
client unless it keeps its jobs itself.
|
||
|
||
A client:
|
||
|
||
- SHOULD record a job before it submits it, and the job's id as soon as it has
|
||
one, with the program it sent, since a device's calibration can change before
|
||
the counts are read;
|
||
- MUST NOT cancel a job only because it stopped waiting for it, unless it keeps
|
||
no record to come back to;
|
||
- MUST NOT submit a job again when its `submit` did not complete, without the
|
||
person's confirmation: the first may have been taken, and may be billed.
|
||
|
||
## 6. Counts and bit order
|
||
|
||
An outcome is a string of `bits` characters, `0` or `1`, the highest bit
|
||
first: its last character is bit 0. `"01"` is bit 0 read as 1 and bit 1 read
|
||
as 0. This is OpenQASM's order, and the job service's.
|
||
|
||
The client compiles each logical qubit `i` of the person's circuit to end on
|
||
the physical qubit that bit `i` measures, and reads the counts back onto the
|
||
program's own classical bits. The first job on a new provider SHOULD be the
|
||
probe (an `X` on qubit 0, every qubit measured), whose counts must all land
|
||
on `…01`; the conformance vectors begin with it (§9).
|
||
|
||
## 7. Cost and confirmation
|
||
|
||
A job is free when the provider's estimate says `"free": true`, or, for a
|
||
provider that gives no estimate, when its `billing` says so. Every other job,
|
||
an unknown cost included, is not free: a provider whose `billing` sets no price
|
||
(§5.1) and that gives no estimate leaves every job's cost unknown, and so does an
|
||
estimate in the unpriced form (§5.2). A client:
|
||
|
||
- MUST show the estimate (or that the cost is unknown) before submitting;
|
||
- MUST NOT submit a job that is not free without the person's explicit
|
||
confirmation for that run: a command-line flag (`wai-quantum run --provider
|
||
NAME --yes`), an agent tool's argument the agent sets only after the person
|
||
agreed (`run_on_provider` with `confirm_cost: true`), or a dialog (the
|
||
desktop app);
|
||
- MUST NOT hold a standing confirmation across runs.
|
||
|
||
A tool that can submit a job that is not free MUST say in its description
|
||
that it can spend the person's money.
|
||
|
||
## 8. The receipt
|
||
|
||
The host seals each provider job as the job service seals its own, and the
|
||
same verifier checks both: an Ed25519 signature, by the host's key, over the
|
||
request as submitted and the result as returned (§8.2). A job's body is an
|
||
object holding `request`, the job as it was asked, and `result`, which carries
|
||
its `receipt`. This section says what a provider's result carries (§8.1), how
|
||
it is sealed and read (§8.2), what its counts' source and its `execution` say
|
||
(§8.3), what a verifier checks and the reason it gives for each failure
|
||
(§8.4), what the receipt proves (§8.5), what a job under a contract carries
|
||
beside it (§8.7), and how a reader holds a receipt to the keys it trusts and to a
|
||
time (§8.8). A verifier of §8.2, §8.4 and §8.7 checks any job's receipt, a
|
||
provider's or not.
|
||
|
||
### 8.1 What a provider's result carries
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `method` | `provider` |
|
||
| `accuracy` | `class`: `measured` when the provider's `provenance` is `silicon`, `simulated` when it is a simulator's or an emulator's (no device measured those counts); `approximate`: `true`, only on a `simulated` result whose provider's `describe` says `approximate` (§5.1), and absent otherwise; `note`, a sentence |
|
||
| `provider` | `name` (the person's name for it, the request's `provider`), `kind` (`sampler-v2`, `prx-circuits`, `native-turns`, `cloud-tasks`, `http` or `process`), `protocol` (`wai.quantum.provider/1`, or a built-in client's own), `device`, `provenance` (`silicon`; or `simulator` or `emulator`, alone or followed by `:` and the sentence naming it), `qubits` (the device's), `basis` (§4), and `describe`, the BLAKE3 of the RFC 8785 text (§8.2) of the provider's `describe` answer (for a built-in kind, of the description its client makes of the device). `provenance` is `silicon` exactly, or its part before any `:` is `simulator` or `emulator` |
|
||
| `calibration` | the calibration snapshot the job ran under, as the provider names it, or `null` |
|
||
| `compiled` | the program sent: `basis`; `qasm3`, its OpenQASM 3 text, `$i` being index `i` of the coupling map the provider described; `qubit_names`, the device's own name for each index the program uses, where a client sends it under those names (a `cloud-tasks` processor's labels, each index itself on its simulator; a `prx-circuits` device's qubits), each as it was when the job was sent; `program`, the BLAKE3 of `qasm3`'s UTF-8 bytes; `hash`, a sentence saying so; `native_gates`, `two_qubit_gates` and `swaps`, its counts; `layout` and `final_layout`, for each logical qubit the index it starts and ends on; `checked`, the check it passed before it was sent; `placement`, how it was placed (with a calibration read as a target, the target's hash, the layout's expected success and the fewest-swaps layout's) |
|
||
| `job` | `id`, the provider's id for the job, and `polls`, the status checks before it finished |
|
||
| `counts` | keyed by the program's classical bits (§6), each outcome that occurred with its count, at least 1 (a host drops an outcome a provider counts 0); with `distinct_outcomes`, the outcomes that occurred, and `omitted_shots`, the shots of outcomes not listed (at most 65,536 outcomes are listed). Every provider result an engine has sealed carries these, the earlier form's included |
|
||
| `shots` | the shots: the request's, 1024 when it gives none |
|
||
| `accepted_shots` | the shots the counts are of, where the device kept another number than `shots` (§5.5: a post-selected or heralded readout, or a device that runs more than asked), a whole number of at least 1; absent when the counts are of every shot asked. Every host before it refused counts of another sum, so a result without it, of either form, is of every shot asked. Who said the device kept that many is read from `provider.kind`, as for `counts_source` (§8.3) |
|
||
| `counts_source` | where the counts come from (§8.3) |
|
||
| `execution` | how the device was asked to run the program (§8.3) |
|
||
| `ideal` | the circuit's exact distribution p set beside the counts' frequencies q (up to 22 qubits): `computed`, and when it is `true` `total_variation_distance` (½ Σ \|q − p\|), `hellinger_fidelity` ((Σ √(p·q))²), `sampling_tvd_expected` (½ Σ √(2p(1 − p)/(π·shots)), the distance the shots alone leave on average, by the normal approximation) and `ideal_outcomes`; when `false`, `why`. The host computes them, and no verifier can without the program's simulation |
|
||
| `cost` | `free`; `estimate`, the estimate shown before submitting (an object, with `unknown`, a sentence, when none was known; an estimate in the unpriced form of §5.2 has `priced` `false` and `unknown` beside what it stated); `charged`, what the provider says it charged (`{"amount", "currency"}`), or `null`; `confirmed`, `true` exactly when the run was not free: such a run ran only with the person's confirmation (§7), and a free run needs none and records none; `confirmed_by`, on a provider's own record only (below), `submit` |
|
||
| `energy` | `unmetered`, saying why it is not metered here; and, when the provider gives one, its own figure `service_kwh`, labelled as its own by `service_kwh_is` |
|
||
| `engine`, `schema` | the engine that made the result (`{"name": "wai-quantum", "version"}`) and `wai.quantum.job-result/1` |
|
||
|
||
**A provider's own record.** A provider may seal its own record of a job it
|
||
ran, as a host seals a job (§8.2): its own key in the host's place, and a
|
||
result of this form, which the same verifier checks (§8.4). It cannot record
|
||
the person's confirmation, which the person gives their host and which never
|
||
reaches the provider. Its record of a run that is not free has `confirmed`
|
||
`true` and `confirmed_by` `submit`: the provider took the job's authenticated
|
||
`submit` as the confirmation, since a client submits a job that is not free
|
||
only on the person's confirmation for that run (§7). A free run records
|
||
neither. A host's receipt has no `confirmed_by`: its `confirmed` is the
|
||
confirmation the host itself took.
|
||
|
||
A result sealed before results carried `counts_source` and `execution` is of
|
||
the *earlier form*: it carries neither, its class is `measured` whatever ran
|
||
it, and some of the members above are missing. It verifies by §8.4's rules
|
||
for that form. A verifier reads its class by its provenance, and says so: a
|
||
simulator's counts sealed as `measured` are a simulator's.
|
||
|
||
A job's `id` is the provider's, sealed: some name the person's account (a
|
||
cloud account's number inside a task's identifier). Sharing a receipt shares
|
||
it.
|
||
|
||
### 8.2 How it is sealed, and how a job is read
|
||
|
||
**The seal.** The result's `receipt` is an object:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `alg` | `ed25519` |
|
||
| `canon` | `rfc8785`; absent on a receipt of the first form (below) |
|
||
| `key` | the signer's Ed25519 public key `A`, its 32 bytes as 64 hex digits |
|
||
| `digest` | the digest signed, 32 bytes as 64 hex digits |
|
||
| `signature` | the signature `R ‖ S`, 64 bytes as 128 hex digits |
|
||
| `time` | when the receipt was issued; absent on a receipt that seals no time (*The time*, below) |
|
||
|
||
Hex digits are lower case, `0`–`9` and `a`–`f`, and nothing else. The receipt
|
||
is not sealed, so each member has one spelling. Any other member of the
|
||
receipt is ignored.
|
||
|
||
The digest is BLAKE3 (32 bytes, the hash mode) of
|
||
|
||
d ‖ u64(|Q|) ‖ Q ‖ u64(|T|) ‖ T
|
||
|
||
where `d` is the 27 ASCII bytes `wai:quantum-service-receipt` and then the one
|
||
byte `0x02` (`0x01` for the first form); `Q` is the canonical text of `request`;
|
||
`T` is the canonical text of `result` with its `receipt` member removed; and
|
||
`u64(n)` is `n` as 8 bytes, big-endian. The signature is Ed25519 as RFC 8032
|
||
§5.1 defines it, with no context and not prehashed, over the 32 bytes of the
|
||
digest. Since the domain byte is inside the digest, a receipt of one form does
|
||
not verify as the other.
|
||
|
||
**The time.** A receipt may state when it was issued. Its `time` is an object:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `issued_ms` | when the signer sealed the receipt, by its own clock: milliseconds since 1970-01-01T00:00:00Z, a whole number from 0 to 2^53 − 1 |
|
||
| `not_after_ms` | optional: the first moment the receipt is no longer offered, a whole number of the same kind, greater than `issued_ms` |
|
||
|
||
and no other member. A whole number here is a number with that value however it
|
||
is written (`1.5e2` is 150, and `-0` is 0). A receipt with a `time` has `canon`
|
||
`rfc8785`, and its digest is BLAKE3 of
|
||
|
||
d ‖ u64(|Q|) ‖ Q ‖ u64(|T|) ‖ T ‖ u64(|V|) ‖ V
|
||
|
||
with `d` ending in the byte `0x03` and `V` the canonical text of `time`. The time
|
||
is so inside what is signed: one changed, taken off, or put on a receipt sealed
|
||
without it gives another digest, and the receipt does not verify. `Q` and `T` are
|
||
what they are in a receipt with no time, so a job's request and result, and every
|
||
digest taken of them (a set's leaves, §8.6; a replay digest), are the same whether
|
||
its receipt states a time or not: the time is the receipt's alone.
|
||
|
||
A host states its clock's reading and nothing else. One with no clock to read (a
|
||
browser's WebAssembly has none), or whose owner does not want its receipts to
|
||
differ from one run to the next, seals no time: its receipt has no `time`, and is
|
||
the receipt this section has always described. No host writes a time it did not
|
||
read, and none writes a placeholder. The job service seals a time on every receipt
|
||
(a deployment can turn that off); the command line seals none unless it is asked
|
||
(`WAI_QUANTUM_RECEIPT_TIME`), so that the same key and job give the same receipt
|
||
byte for byte. A verifier states what it found: the time, or that none is sealed.
|
||
A receipt that seals none is as valid as it was, and can be placed in no window
|
||
that ends (§8.8).
|
||
|
||
Only `request` and `result` are sealed. Whatever else a job's body holds (its
|
||
`status`, `id`, `method`, `why`, `estimate` and times) is the host's, and
|
||
unsealed: a verifier takes nothing from it, and its verdict does not change
|
||
with it.
|
||
|
||
**Reading.** A job is read from its text, strictly, before anything is
|
||
checked. The text is UTF-8 with no byte order mark, and one JSON value
|
||
(RFC 8259) with whitespace allowed around it. It is unreadable when:
|
||
|
||
- an object names a member twice (names compared after their escapes are read);
|
||
- a string holds a lone surrogate: a `\u` escape of a high surrogate not
|
||
followed at once by one of a low surrogate, or of a low surrogate alone;
|
||
- a string holds a control character (U+0000 to U+001F) not escaped;
|
||
- a number's magnitude is 2^1024 − 2^970 or more, which rounds to an infinite
|
||
double;
|
||
- arrays and objects nest deeper than 127, the outermost counted as the first.
|
||
|
||
A noncharacter (U+FDD0 to U+FDEF, and the last two code points of each plane)
|
||
is a character like any other. Each number is read as the nearest IEEE 754
|
||
double, ties to even; a number too small for any double other than zero reads
|
||
as zero. A whole number written as one (a literal with no fraction and no
|
||
exponent) in the request or the result that no double holds exactly says more
|
||
than the receipt seals, since the seal holds its double (§8.4,
|
||
`inexact_number`), unless it is the canonical text (below) of the double it
|
||
reads as. That one spelling is RFC 8785's for a whole double whose magnitude is
|
||
2^53 or more and under 10^21 (a negative one with its `-`), its shortest digits
|
||
padded with zeros (2^60 as
|
||
1152921504606847000), and what any JSON writer that follows RFC 8785 or
|
||
ECMAScript writes: it reads as the double that was sealed, and no other
|
||
spelling of an inexact whole number is taken. A canonical receipt seals every number as its double; a
|
||
first-form receipt seals a whole number written as one in its writer's integer
|
||
range by its digits, and every other number by its double (below), and only
|
||
what a receipt seals as a double is held to this.
|
||
|
||
**The canonical text** of a value is RFC 8785's:
|
||
|
||
- `true`, `false` and `null` as they are;
|
||
- a string between `"`s, with `"` and `\` escaped as `\"` and `\\`; U+0008,
|
||
U+0009, U+000A, U+000C and U+000D as `\b`, `\t`, `\n`, `\f` and `\r`; every
|
||
other character below U+0020 as `\u00` and two lower-case hex digits; and
|
||
every other character as its own UTF-8 bytes, unescaped (`/` and U+007F
|
||
included) and not normalised;
|
||
- a number as ECMAScript's Number::toString writes the double it reads as
|
||
(ECMA-262, 6.1.6.1.20): zero (also negative zero) as `0`; otherwise, with
|
||
`s` the fewest decimal digits `d1 … dk` that read back as the double (of
|
||
those, the nearest to it, a tie going to the even last digit) and `n` such
|
||
that the value is 0.`s` × 10^n: if k ≤ n ≤ 21, the digits and n − k zeros;
|
||
if 0 < n ≤ 21, the digits with a `.` after the first n; if −6 < n ≤ 0, `0.`,
|
||
−n zeros, and the digits; otherwise `d1`, then `.` and `d2 … dk` when k > 1,
|
||
then `e`, a sign (`+` or `-`), and |n − 1| in decimal; a negative number is
|
||
the same with `-` before it;
|
||
- an array as `[`, its values' texts joined by `,`, and `]`;
|
||
- an object as `{`, its members joined by `,`, each the name's text, `:` and
|
||
the value's text, in the order of their names compared as sequences of
|
||
UTF-16 code units (unsigned), and `}`;
|
||
- with no whitespace anywhere outside strings.
|
||
|
||
So a result verifies after any JSON reader and writer has carried it, even
|
||
one that writes `1.0` as `1` or orders members otherwise.
|
||
|
||
**The first form.** The first receipts, which name no `canon`, sealed the text
|
||
their signer's JSON writer wrote, not the canonical text, under the domain byte
|
||
`0x01`. A verifier reads `Q` and `T` as that writer did: the value's compact
|
||
text (no whitespace outside strings), its object members in the order the job
|
||
gives them (the result's `receipt` removed, the others kept in order), its
|
||
strings as in the canonical text, and its numbers so:
|
||
|
||
- a whole number written as one (no fraction, no exponent), without a `-` and
|
||
from 0 to 2^64 − 1, or with a `-` and from −2^63 to −1, is written as its
|
||
decimal digits, with its `-` (so `-0` is a double: `-0.0`);
|
||
- every other number is written from its double: `-0.0` for negative zero, and
|
||
`0.0` for zero; otherwise, with `s` = `d1 … dk` and `n` as above, if n ≥ k
|
||
and n ≤ 16, the digits, n − k zeros and `.0`; if 0 < n ≤ 16, the digits with
|
||
a `.` after the first n; if −5 < n ≤ 0, `0.`, −n zeros and the digits;
|
||
otherwise `d1`, then `.` and `d2 … dk` when k > 1, then `e`, a sign (`+`
|
||
or `-`), and |n − 1| in decimal (`1e+16`, `1e-7`); a negative number is the
|
||
same with `-` before it.
|
||
|
||
The first form was sealed from 2026-10-17 to 2026-10-20, every receipt by one
|
||
writer, whose text these rules restate.
|
||
|
||
A first-form receipt verifies only as its signer wrote it: reordered members
|
||
break it, and so can a number written another way. No host writes the first
|
||
form now. A `canon` other than `rfc8785` (`null` among them) names no form.
|
||
|
||
**The signature, strictly.** RFC 8032 leaves some choices open, and two
|
||
verifiers that chose differently would disagree on the same receipt. A
|
||
verifier here:
|
||
|
||
- decodes `A` and `R` as RFC 8032 §5.1.3 does, and refuses an encoding whose y
|
||
(its low 255 bits, little-endian) is p = 2^255 − 19 or more, one that is not
|
||
on the curve, and one with x = 0 and the sign bit set;
|
||
- refuses `A` of small order (a point P with [8]P the identity) and `A` not in
|
||
the prime-order subgroup ([ℓ]A not the identity, ℓ = 2^252 +
|
||
27742317777372353535851937790883648493);
|
||
- refuses `R` of small order, and `S` (little-endian) of ℓ or more;
|
||
- accepts exactly when [S]B = R + [k]A, with k = SHA-512(R ‖ A ‖ the 32
|
||
digest bytes) read little-endian, mod ℓ, compared as points with no cofactor
|
||
(and so as their canonical encodings).
|
||
|
||
Without the rules on `A`, the identity as `A`, any `S` and `R` = [S]B hold
|
||
for every digest: a receipt for any content at all. A library's default check
|
||
also takes the identity as `R` with `S` = 0.
|
||
|
||
**Every quantum receipt, by this rule.** The rule above is SPEC §7
|
||
*Signatures* with the prime-order subgroup added, and it is the one rule every
|
||
quantum receipt is verified by, whatever its family: the job receipt here and
|
||
a set's (§8.6), the circuit receipt ([quantum-sim](quantum-sim.md)), the
|
||
calibration, job, mitigation, decode, compile and rearrange receipts
|
||
([quantum-ops](quantum-ops.md)), the bill of materials, the fabric,
|
||
sparse-Pauli, resource-estimate and phasor receipts, each in its labelled
|
||
form too ([energy-measurement](energy-measurement.md) §2.8), and the job
|
||
service's key transitions. Each reads its keys, signatures and hashes, and
|
||
the bits of each double it seals, as lower-case hexadecimal of exactly their
|
||
length, and refuses any other spelling: a reader that took a second spelling
|
||
would give a sealed receipt a second text that also verifies. The reference
|
||
implementation holds one copy of the rule and of the reader
|
||
(`wai_quantum::sig`).
|
||
|
||
### 8.3 Where the counts come from, and how the device was asked to run them
|
||
|
||
**`counts_source`** is one of:
|
||
|
||
| value | the counts are |
|
||
|---|---|
|
||
| `shots` | tallied from the device's records, one a shot |
|
||
| `vendor_counts` | the provider's own counts, as it returned them |
|
||
| `probabilities` | rebuilt from the probabilities the device gave: each `p·shots` rounded down, then the shots left given one each to the largest remainders, a tie to the lower outcome. They are derived, and not shot records |
|
||
|
||
The counts are of the shots the device kept (`accepted_shots`, §8.1), which a post-selected
|
||
or heralded readout makes fewer than asked; the source says how those were counted. A device
|
||
that reads an ensemble (an expectation value of each qubit over many systems at once, rather
|
||
than one outcome a shot) gives none of these: its readings are not counts, rebuilding counts
|
||
from them would state outcomes no shot had, and no provider result carries them.
|
||
|
||
Who did so is read from `provider.kind`. On a built-in kind the host's client
|
||
did, and it is the host's word. On `http` and `process` the host received counts
|
||
and did neither, and it is the provider's word for how it made them (§5.5): the
|
||
rule for rebuilding them is the one the provider says it kept, which the host
|
||
cannot vouch for.
|
||
|
||
**`execution`** says what the host knows of the five steps a provider may
|
||
take between receiving a program and running it: `mitigation` (correcting
|
||
counts after the run, readout correction or debiasing), `twirling` (of gates
|
||
or of measurements), `decoupling` (dynamical decoupling of idle qubits),
|
||
`remapping` (moving the program to other qubits) and `optimisation`
|
||
(rewriting its gates). It is an object of:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `stated_by` | `client`, the host's client from the request it sends; `provider`, the provider in its `result` answer (§5.5); or `nobody` |
|
||
| the five steps | each `off` or `on` (by a setting the client sent, or as the provider states), `default` (said by a client: its request sets nothing for it, so the provider's default stands, whatever it is), `none` (said by a provider: its device has no such step), or `unknown` (when nobody states it, or a provider cannot vouch for the step) |
|
||
| `verbatim` | `true` when the request asks for the gates to run as written, on the qubits named (a verbatim box); `false` when it does not; `null` when nobody states it |
|
||
| `sent` | with `client` only: `fields`, the members of the request's body, each once, in increasing order of their UTF-8 bytes; and `settings`, an object of what the request sets: JSON Pointers (RFC 6901) into the body, each with the value it holds there, and names for settings the body holds otherwise (`verbatim_box`); and nothing else |
|
||
| `note` | optional: a sentence |
|
||
|
||
and nothing else. Its rules: with `stated_by` `client`, each step is `off`,
|
||
`on` or `default`, `verbatim` is `true` or `false`, and `sent` is given; with
|
||
`provider`, each step is `off`, `on`, `none` or `unknown`, `verbatim` is
|
||
`true` or `false`, and there is no `sent`; with `nobody`, each step is
|
||
`unknown`, `verbatim` is `null` and there is no `sent`. Each key of
|
||
`sent.settings` either begins with `/`, and its first reference token (up to
|
||
the next `/`, its `~1` and `~0` read as `/` and `~`) is one of `fields`, the
|
||
rest of it not read; or is a name, not empty, that does not begin with `/`. A program run as written is
|
||
neither remapped nor optimised, so with `verbatim` `true`, `remapping` and
|
||
`optimisation` are each `off` or `none`. A client that says a step is `off` or
|
||
`on` says by which setting: `settings` is then not empty.
|
||
|
||
**What each built-in kind records.** A client builds its `execution` from the
|
||
very body it sends, so that what is stated is what was sent, and its counts'
|
||
source from what the service answered. These are their rows. A later client
|
||
that sends something else adds a row; a row is never removed, so every
|
||
receipt keeps verifying. A kind of the open protocol (`http`, `process`)
|
||
records the provider's word (`provider`), or `nobody` when it says nothing. On
|
||
any kind, a job recorded before its client stated what it sent, and collected
|
||
since, is stated by `nobody`: nothing else is known of what was sent.
|
||
|
||
| kind | `counts_source` | `sent.fields` | `sent.settings` | steps | `verbatim` |
|
||
|---|---|---|---|---|---|
|
||
| `sampler-v2` | `shots` | `backend`, `params`, `program_id` | `/params/options/dynamical_decoupling/enable`: `false`, `/params/options/twirling/enable_gates`: `false`, `/params/options/twirling/enable_measure`: `false` | `decoupling` and `twirling` `off`; the other three `default` | `false` |
|
||
| `prx-circuits` | `vendor_counts` | `circuits`, `shots` | none: the client sends nothing else | all five `default` | `false` |
|
||
| `native-turns` | `probabilities`: the service answers probabilities, so its counts are always rebuilt | `backend`, `input`, `settings`, `shots`, `type`; and `noise`, on its simulator under a device's noise model | `/input/gateset`: `native`, `/settings/error_mitigation/debiasing`: `false`; and `/noise/model`: the model's name, with `noise` | `mitigation` `off`; the other four `default` | `false` |
|
||
| `cloud-tasks`, on a processor (`silicon`) | `shots`, from the task's rows; `probabilities`, when its result holds none | `action`, `clientToken`, `deviceArn`, `outputS3Bucket`, `outputS3KeyPrefix`, `shots` | `verbatim_box`: `true`, the program's gates in the service's verbatim box on physical qubits | `remapping` and `optimisation` `off`; the other three `default` | `true` |
|
||
| `cloud-tasks`, on a simulator | as on a processor | as on a processor | none | all five `default` | `false` |
|
||
|
||
A row is the `execution` its kind states, less its `note`: `stated_by` is
|
||
`client`, and every member is as the row gives it. A row holds for its
|
||
provenance: `cloud-tasks`' first row for `silicon`, its second for any other
|
||
(a simulator or an emulator); `native-turns`' row with `noise` for any
|
||
provenance but `silicon`, its model's name a string, not empty, and its row
|
||
without `noise` for any. `prx-circuits` sends only
|
||
`circuits` and `shots`, so it turns nothing off, and says so. No row says a
|
||
provider runs a program as sent where its client sets nothing that asks it to.
|
||
|
||
### 8.4 What a verifier checks
|
||
|
||
A verifier reads the job (§8.2) and reports every reason below that applies,
|
||
as a set: none for a valid receipt. It is valid exactly when there is none.
|
||
|
||
| reason | when |
|
||
|---|---|
|
||
| `unreadable` | the text breaks a rule of reading (§8.2). Reported alone |
|
||
| `not_a_job` | the value is not an object whose `request` and `result` are both objects. Reported alone |
|
||
| `no_receipt` | the result has no `receipt`. Reported alone |
|
||
| `too_large` | the job is longer than the surface reads, in its bytes or in its values (one, and one more for each `,`, `:`, `[` and `{` outside its strings: what a check holds follows them), which it states with the verdict (`read_at_most`: `{"bytes", "values"}`); it judged none of it. Reported alone. `wai-quantum verify`, on every host, reads 384 MiB and 2^22 values, more than any job holds; the job service's `POST /v1/verify` and `/mcp` read 4 MiB and 2^19 values. A job given as a string is its text's bytes and values; one given parsed in a message, as it is written there |
|
||
| `receipt_form` | the receipt is not an object; its `alg` is not `ed25519`; it has a `canon` other than `rfc8785`; its `key`, `digest` or `signature` is not lower-case hex of its length; or it has a `time` that is not of its form (§8.2), or has one and no `canon`. When it is reported, the next three are not checked |
|
||
| `digest_mismatch` | the digest the receipt states is not the digest (§8.2) of this request and result |
|
||
| `bad_key` | `key` is refused by the strict rules (§8.2). When it is reported, the signature is not checked |
|
||
| `bad_signature` | the signature does not hold, strictly (§8.2), over the digest the receipt states (so a body changed after it was sealed gives `digest_mismatch` alone) |
|
||
| `inexact_number` | a whole number written as one, in what the receipt seals (the request, and the result less its receipt; for a set, the request and its head, §8.6) and sealed as a double (§8.2), is not a double, and is not the canonical text of the double it reads as. A receipt is of the first form when `receipt_form` is not reported and it has no `canon`; one that `receipt_form` refuses names no form, and its numbers are read as a canonical receipt's |
|
||
| `provider_class` | a provider's result whose `accuracy.class` is not the one its form gives: `measured` in the earlier form; in the stated form, `measured` for `silicon` and `simulated` for a provenance whose part before any `:` is `simulator` or `emulator` (none for any other); or whose `accuracy.approximate` is present and not `true`, or `true` in the earlier form or on a class other than `simulated`. Or a result of another method whose class is `measured` or `simulated`, other than a sign-off's (§8.9), which repeats the class of the job it signs off |
|
||
| `request_provider` | a provider's result whose `provider.name` is not a string equal to the request's `provider`; or, when the request gives none (or `null`) and its `contract.providers` is `allowed`, equal to what follows `provider:` in `planner.choice` (§8.7) |
|
||
| `request_shots` | a provider's result whose `shots` is not the request's (1024 when the request gives none, or `null`) |
|
||
| `counts` | a provider's result whose `counts` is not an object of outcomes, all of one length and each of `0` and `1` only, to whole numbers from 1 to 2^53 − 1; or whose `shots` (a whole number of at least 1), `omitted_shots` and `distinct_outcomes` (whole numbers of at least 0) are missing; or that has an `accepted_shots` (whatever its value) that is not a whole number of at least 1; or whose counts and `omitted_shots` do not sum to `accepted_shots` when it has one, and to `shots` when it has none; or whose `distinct_outcomes` is not the number of outcomes listed when `omitted_shots` is 0; or, when it is not 0, lists other than 65,536 outcomes, or no more distinct outcomes than it lists |
|
||
| `provider_members` | a stated provider's result (below) without, or with a wrong type of: `provider`'s `name`, `kind`, `protocol` and `device` (each a string not empty), `provenance` (as `provider_class` reads it), `describe` (64 lower-case hex digits), `qubits` (a whole number of at least 1) and `basis` (equal to `compiled.basis`); `calibration` (a string or `null`); `compiled`'s `basis` (`rzsxxcz`, `prxcz`, `gpizz` or `prxrzxx`), `program` (64 lower-case hex digits), `qasm3` (a string), `native_gates`, `two_qubit_gates` and `swaps` (whole numbers of at least 0), `layout` and `final_layout` (arrays of whole numbers of at least 0) and `checked` (a string); `compiled.qubit_names`, where it is given or required, is below; `job`'s `id` (a string not empty) and `polls` (a whole number of at least 0); `ideal.computed` (`true` or `false`); `cost`'s `free` and `confirmed` (each `true` or `false`), `estimate` (an object) and `charged` (`null`, or an object whose `amount` and `currency` are strings); `energy.unmetered` (a string), and `energy.service_kwh_is` (a string) when there is `energy.service_kwh`; `schema` (`wai.quantum.job-result/1`); `engine.name` (`wai-quantum`) and `engine.version` (a string) |
|
||
| `counts_source` | a stated provider's result whose `counts_source` is not one of §8.3's values, or, for a kind with rows, not one the rows that hold for its provenance give |
|
||
| `execution` | a stated provider's result whose `execution` breaks a rule of §8.3; or, for a kind with rows, is neither one of the rows that hold for its provenance nor stated by `nobody`; or, for `http` and `process`, is not stated by `provider` or `nobody` |
|
||
| `compiled_program` | a stated provider's result whose `compiled.program` is not the BLAKE3 of `compiled.qasm3`'s UTF-8 bytes, when `qasm3` is a string and `program` is 64 lower-case hex digits |
|
||
| `cost_confirmation` | a stated provider's result whose `cost.confirmed` is `true` on a free run or `false` on one that is not free (§7), when both are `true` or `false`; or whose `cost` has a member `confirmed_by` (whatever its value, `null` included) that is not `submit`, or that is `submit` beside a `confirmed` that is not `true`: a submit is taken as the confirmation of a run that is not free, and of no other (§8.1) |
|
||
| `contract_form`, `planner_form`, `planner_route`, `planner_choice`, `planner_stable`, `planner_kept`, `contract_class`, `shadow`, `stopped` | §8.7, for any job's result, a provider's or not |
|
||
| `wasmq_form` | a wasmQ job's result (its `format` is `wai.quantum.wasmq.result/1`, or `/2` for the second version, [quantum-wasmq](quantum-wasmq.md)) whose request or result breaks a rule of [quantum-wasmq §6.5](quantum-wasmq.md#65-verifying), as [§11.6](quantum-wasmq.md#116-verifying) reads them for the second version: the job is not one that profile writes |
|
||
| `landscape_form` | an energy-landscape job's result (its `protocol` or its `schema` is `wai.quantum.landscape/1`, [quantum-landscape](quantum-landscape.md), or `wai.quantum.landscape/2`, [quantum-landscape-2](quantum-landscape-2.md)) whose request or result breaks a rule of [quantum-landscape §5.4](quantum-landscape.md#54-verifying-an-answer), as [quantum-landscape-2 §5.4](quantum-landscape-2.md#54-verifying-an-answer) reads them for a job of the second version, whether it ran here or on a provider (§11.3) |
|
||
|
||
A provider's result is one whose `method` is `provider`. It is *stated* when it
|
||
carries a member `counts_source` or a member `execution` (whatever their
|
||
values), and of the earlier form when it carries neither; the earlier form is
|
||
held to `provider_class`, `request_provider`, `request_shots` and `counts`
|
||
only. A whole number is any number whose value is whole, however it is
|
||
written (`1`, `1.0`, `1e0`), however large; only a count's value has a ceiling,
|
||
and a sum is exact, not a double's. A number's value, in every rule here and on
|
||
every form of receipt, is its nearest double (§8.2): the digits of a first-form
|
||
receipt are for what it sealed, and for nothing checked here. `-0` is 0.
|
||
"The request's" is by value: two equal strings are the same, and that a string
|
||
is no number is another rule's to say.
|
||
A class a verifier does not know is not a reason: a later version may add one
|
||
(VERSIONING.md).
|
||
|
||
`compiled.qubit_names` is required of a stated result of `cloud-tasks` or
|
||
`prx-circuits` whose `execution` is stated by `client`, and optional otherwise.
|
||
When given (`null` is given, and is no object) it is an object: each key an index
|
||
in decimal, with no leading zero; each value a string, not empty; the value of
|
||
every entry of `layout` and `final_layout`, written in decimal in full, is among
|
||
its keys; and so is every index `qasm3` acts on, when `qasm3` is a string: each
|
||
`$` anywhere in it followed by one or more of the ASCII digits 0 to 9 names the
|
||
index those digits read as, written in decimal with no leading zero (a `$`
|
||
followed by no such digit names none). Otherwise it is a `provider_members` reason.
|
||
|
||
**What a host seals, its own verifier accepts.** A host refuses a request holding
|
||
a whole number past ±(2^53 − 1), or any number that it or RFC 8785 would write in
|
||
a spelling this section refuses, where it reads it, on every path to a seal (a
|
||
set's own request, its sweep's values among them, included); and it writes a
|
||
whole number no double holds in a result as the double it seals. A receipt an
|
||
earlier release sealed with such a number is refused with `inexact_number`,
|
||
though its signature holds: what it sealed is the double, and its text says
|
||
more. Written as that double's exact digits, or as its canonical text, it
|
||
verifies. The local hosts' `qec` took a seed of any size; their compile, pulse,
|
||
estimate and `@Seal` took any number in a request; and a set took any number in
|
||
its own request and its sweep's values. The job service refused such a number
|
||
in every request but a set's own.
|
||
|
||
A verifier also states, for a provider's result (one with no receipt
|
||
included), its class as its provenance reads it, and, in the stated form, its
|
||
counts' source and its `execution`, each as the result gives it.
|
||
|
||
A wasmQ job's result is held to `wasmq_form` whatever its `method`, and to the provider
|
||
rules too when its `method` is `provider`. A verifier also states, for a wasmQ job, what
|
||
quantum-wasmq §6.5 says it states beside the verdict: how the run ended, each rule it
|
||
breaks and where the body's unsealed members differ from what is sealed. None of that
|
||
changes the verdict.
|
||
|
||
These are all the rules: what §8.1 names and this table does not check
|
||
(`compiled.hash` and `placement`, the notes, the `ideal` figures, the
|
||
estimate's contents, a route's price where §8.7 does not recompute from it) is
|
||
the host's word, unchecked. The schemas
|
||
(`wai.quantum.job-result/1`, `wai.quantum.receipt/2`) describe what a host
|
||
writes; a verifier judges by this section.
|
||
|
||
### 8.5 What the receipt proves, and what it does not
|
||
|
||
A valid receipt proves that the holder of the key it names signed this
|
||
request and this result, nothing else and nothing less: every member of
|
||
both, the counts, `counts_source` and `execution` among them. It does not
|
||
say whose key it is. The job service publishes its keys and their windows
|
||
(`GET /.well-known/wai-quantum-receipt-keys`); a host's key is the person's
|
||
own, and anyone relying on a receipt decides whether they trust it, and says so
|
||
to the verifier with a trust list (§8.8). A receipt that seals a time (§8.2) says
|
||
when its signer issued it, in the signer's word, and can be held to a key's window,
|
||
to a revocation and to its own end; one that seals none can be shown again at any
|
||
time, and no window that ends can be applied to it. A verifier says which it is. A host can still seal a
|
||
result of the earlier form, stating neither its counts' source nor its
|
||
`execution`; a verifier then holds it to the earlier form's rules, reads its
|
||
class by its provenance, and says that it states neither. A host can likewise
|
||
seal a stated result with `execution` stated by `nobody` on any kind, meant for
|
||
a job recorded before its client said what it sent: that says nothing of what
|
||
was sent, and a verifier says that nobody stated it.
|
||
|
||
A provider's own record (§8.1) is the provider's word, signed with its key,
|
||
and its `confirmed_by` `submit` says only that the provider took the job's
|
||
submit as the confirmation: whether the person was asked is in their host's
|
||
receipt, not in the provider's.
|
||
|
||
Everything the result says the host received, sent and checked is the host's
|
||
own word, signed: that this was the provider's answer, under the calibration
|
||
snapshot named, and that the host compiled the program whose text and hash it
|
||
carries exactly and checked it against the circuit before sending it. The
|
||
compiled program's text is in the receipt, with the device's names for its
|
||
qubits where its client uses them, so anyone can read which gates were sent to
|
||
which qubits and check its hash. It is not the bytes sent: a client writes the
|
||
same gates in what its service takes. `execution` says what the request
|
||
asked of the provider. What it does not prove: that the device ran that
|
||
program, or ran anything. The counts are the provider's word, and they are
|
||
not reproducible by recomputation: the same job run again gives other counts.
|
||
A provider's simulator's counts say what its software gives, which is why
|
||
they are `simulated`, not `measured`. The `ideal` distance says how far the
|
||
counts are from what the circuit gives; a distance well above the sampling
|
||
distance is the device's or the simulator's error, or a program not run as
|
||
sent.
|
||
|
||
### 8.6 A set's receipt
|
||
|
||
A set is one request that runs many jobs (`programs`, a list of programs or
|
||
jobs, or `sweep`, values for the inputs of the request's own `qasm`); its result
|
||
has `"format": "wai.quantum.set/1"`. Its `head` is its result less `items` and
|
||
`receipt`. The set's receipt seals the set's request and its head, by §8.2, as a
|
||
job's seals its request and result; each item that ran carries a result with a
|
||
receipt of its own, over its own request. A verifier reads a set as it reads a
|
||
job (§8.2), and reports, beside §8.4's reasons for the set's request and head
|
||
(`unreadable`, `not_a_job`, `no_receipt`, `receipt_form`, `digest_mismatch`,
|
||
`bad_key`, `bad_signature`, `inexact_number`; the provider rules do not apply to
|
||
a head), each of these that applies:
|
||
|
||
| reason | when |
|
||
|---|---|
|
||
| `set_items` | `items` is not a non-empty array whose `i`-th entry is an object with `index` equal to `i` (a whole number), `request` an object, exactly one of the members `result` (an object) and `error` (a string) present (a member that is present is so whatever its value, `null` included), and `path` an array of strings each of 64 lower-case hex digits. When it is reported so, the next two are not checked. Or: `count` is not the number of items; or the items are not the ones the request gives. With `programs` (an array, and no `sweep`), item `i`'s request is the request less `programs`, `sweep` and `dry_run`, with program `i` over it: a string as `qasm`, or an object's members, each replacing one of the same name. With `sweep` (an object, and no `programs`), each of its values is a non-empty array, the items are as many as the product of their lengths, and each item's request less `qasm` is the request less `programs`, `sweep`, `dry_run` and `qasm`, its `qasm` a string (the request's program written out at its point, which §8 does not check: below). A request with neither, or with both, gives no items; a member that is `null` is none. Requests are compared as JSON values: members in any order, numbers by value |
|
||
| `set_item` | an item with a `result` is not a valid job: `{"request": its request, "result": its result}`, read as §8.2 reads a job, gives any reason of §8.4; or its result is a set's (`format` `wai.quantum.set/1`: an item is one job); or its receipt is valid and names a `key` other than the set's receipt's `key` member as it stands (one the set's receipt does not have included). Or an item with an `error` has a request that writes a whole number its leaf could not seal: as `inexact_number` reads one in a canonical receipt, whatever the set's form, since a leaf is the canonical form's digest |
|
||
| `set_root` | `root` is not 64 lower-case hex digits, or not the Merkle root of the items' leaves; or an item's `path` does not lead from its leaf to `root` |
|
||
|
||
An item's leaf is the digest (§8.2, the canonical form's) of its request and its
|
||
result less its `receipt`, or, for an item with an `error`, of its request and
|
||
`{"error": the error}`. The Merkle tree: a leaf's hash is BLAKE3 of
|
||
`moq-jwp:merkle-leaf` and the byte `0x01`, then the leaf; a node's is BLAKE3 of
|
||
`moq-jwp:merkle-node` and the byte `0x01`, then the left hash and the right; a
|
||
level of odd length pairs its last hash with itself; the root of one leaf is its
|
||
hash. A path lists the sibling at each level from the leaf up: with `n` items it
|
||
has as many entries as halvings (rounding up) take `n` to 1, and a path of any
|
||
other length does not lead to the root; at each level the item's position,
|
||
halved at each step, says whether the sibling is on the right (an even position)
|
||
or the left. This is the tree the WAI worlds' and provenance receipts use, its
|
||
domains theirs, kept so that every set already sealed verifies. Two things
|
||
follow from it. The root alone does not fix the number of items (a last leaf
|
||
paired with itself gives the root a level of one more would), and `count`,
|
||
sealed in the head, does; one item shown with its path and the head alone is
|
||
placed by `count`. And the root does not say whether an item failed: an item
|
||
with an `error` and one whose result is `{"error": …}` have one leaf, and only
|
||
the item's own receipt tells them apart.
|
||
|
||
An item is read for its `index`, `request`, `result`, `error` and `path`; what
|
||
else it holds (its `status`, `method`, `why`, a sweep's `point`) is the host's,
|
||
unsealed, as a job body's members beyond its request and result are, and a
|
||
member its own receipt holds beyond its five is ignored, as a job's is.
|
||
|
||
The engine also writes each item of a sweep out again at its point, and says
|
||
whether each `qasm` is that program (`derived`, beside the reasons); that is the
|
||
engine's check of the set, not a rule of its receipt, and a verifier that does
|
||
not write programs out does not make it.
|
||
|
||
A program that calls WebAssembly between its gates ([quantum-wasmq](quantum-wasmq.md))
|
||
is not a program of §4: it has steps between gates that this protocol does not carry. A
|
||
client MUST NOT send one to a provider; it runs where its runner is (quantum-wasmq §7).
|
||
|
||
### 8.7 A job under a contract
|
||
|
||
A job says what it wants of an answer in its request's `contract`, and the
|
||
planner that took it says why the route it chose was the one, in its result's
|
||
`planner`. A *contract job* is one whose request holds a `contract` member other
|
||
than `null`. A job with none carries neither `planner` nor `shadow`, and plans as
|
||
it did before this section was written, byte for byte.
|
||
|
||
**The contract.** An object of these members, each optional; `null` is absent.
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `exactness` | the class wanted: a string of the table below |
|
||
| `max_cost` | the most a provider's estimate of the run may come to, before it runs: an object of exactly `amount`, an amount in decimals (one or more digits, optionally `.` and one or more digits, at most 64 characters in all), and `currency`, a string not empty. It bounds the estimate, not the charge, which no one knows before the run: what was charged is stated after it, beside the ceiling (`kept.cost`) |
|
||
| `deadline_seconds` | a number above 0: when it must be done by, in seconds, as below |
|
||
| `max_joules` | a number above 0: the most energy the run may take, in joules, enforced while it runs: a live reading stops it when it reaches this, and the receipt says so (below). A route with no live reading is refused under a ceiling. Nothing before a run can promise a figure: a job's work leaves out what drives its time, and the same job read twice differs |
|
||
| `providers` | `never` or `allowed`: whether a route may be one of the person's providers. `never` is the default, given or not, and a request that names a `provider` under a contract that does not allow one is refused (`J070`) |
|
||
|
||
A contract of any other form is refused (`J070`). So is any other member, which
|
||
read as absent would be a requirement dropped in silence.
|
||
|
||
`exactness` is met by these classes of a result (§8.1, and the engine's own):
|
||
|
||
| wanted | met by |
|
||
|---|---|
|
||
| `bit-exact` | `bit-exact` |
|
||
| `exact` | `bit-exact`, `exact` |
|
||
| `single` | `bit-exact`, `exact`, `single` |
|
||
| `bounded` | `bit-exact`, `exact`, `bounded` |
|
||
| `estimate` | `bit-exact`, `exact`, `bounded`, `estimate` |
|
||
| `heuristic` | `bit-exact`, `exact`, `single`, `bounded`, `estimate`, `heuristic` |
|
||
| `measured` | `measured` |
|
||
| `simulated` | `simulated`, on a result that is not `approximate` |
|
||
| `any` | every class |
|
||
|
||
This is a table and not a ladder: `single` states no bound, so it does not meet
|
||
`bounded`, and a device's counts are in no classical class.
|
||
|
||
**What a deadline measures.** For a run of one of the engine's methods, the time
|
||
the engine took over the run itself (the result's `elapsed_ms`): not the queue, the
|
||
planning, a restart before it, the check of its intents, nor the sealing. For a
|
||
provider's run, the time from the job's submission to the moment the host first
|
||
finds it finished: the provider's queue and its run count, and a host that comes
|
||
back to a job late (one sent without waiting, collected later) counts the wait
|
||
too, so its `elapsed_ms` can only overstate. A shadow is not counted: it runs in
|
||
what the deadline leaves, or not at all. A host that can stop a run stops it at
|
||
its deadline: the job service stops its worker, and nothing is sealed (`J074`). A
|
||
provider's job is looked at only while a host follows it: past the deadline, the
|
||
next look cancels it where the client can, and it is `cancelled` once the provider
|
||
says so (`J074`). A job no one follows, or one a client cannot cancel (its route
|
||
says so: `cancel` in `leaves_out`), runs on and can be billed; when it finishes,
|
||
`kept.deadline` says it was missed.
|
||
|
||
**What a ceiling measures, and how it is held.** `max_joules` is held by a live
|
||
reading, while the run goes: a host runs the job in a process of its own, reads the
|
||
route's `watch` every few milliseconds as the host's scheduler allows, and kills that
|
||
process when the reading reaches the ceiling, so the work stops there; only a host
|
||
that can stop a run can give a route a `watch`. The reading is of what `watch` says, and of nothing
|
||
else: a process's own CPU energy leaves out memory, the host's idle draw and any
|
||
device it drives, so a method on a GPU or an accelerator has no `watch`; a processor
|
||
package's counts every process on it, so a busy host stops a run sooner. A run can
|
||
pass the ceiling by what it takes between two reads, and by what a counter has not
|
||
yet shown. A host that runs a job inside a process doing other work, or that reads
|
||
nothing, gives no `watch`, nor does a provider's route: the route is refused under a
|
||
ceiling (`energy_unwatched`). A counter that stops reading during a run leaves nothing
|
||
holding the ceiling: the host stops the run after a second of time without a reading,
|
||
or with one that stood still while the run spent CPU time (a frozen counter is not a
|
||
live one), and seals nothing. The run's process ends with the process that watches
|
||
it, however that one ends. A host reads the run's process whole when it ends, killed or not (a package's
|
||
counter added up read by read, each step corrected for a wrap, so that a run passing
|
||
the counter's range is read in full; a process's read that is far below what its CPU
|
||
time implies is no reading), and seals that figure in `energy`, so a run that passed its ceiling between two reads
|
||
and finished is sealed as having missed it.
|
||
|
||
A run so stopped gave no answer. Its result has no member but `method`, `qubits`,
|
||
`gates`, `accuracy`, `stopped`, `elapsed_ms`, `planner`, `energy`, `engine`, `schema`
|
||
and `receipt`, so no counts, expectations, amplitudes, verdict, outputs, mitigation or
|
||
distribution of any kind; its `accuracy.class` is `none`;
|
||
and it has `stopped`, an object of exactly `at`, the string `max_joules`; `joules`,
|
||
what the reading had come to, a number at or above the ceiling; `max_joules`, the contract's;
|
||
`elapsed_ms`, a whole number and the result's `elapsed_ms`; and `read`, a sentence
|
||
saying what read it and the longest time between two reads, the first counted from
|
||
the start. Its `energy.joules_micro`, where it has one, is no less than `joules` ×
|
||
10^6, less one for its rounding. It is sealed like any result, `energy` the whole
|
||
figure of the process killed where the host could read it, its `kept.energy` says the
|
||
ceiling was not kept, and a command line exits 4. A result whose energy was not read
|
||
whole states `kept.energy.joules` `null`.
|
||
|
||
**The reasoning.** `planner` is an object of:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `format` | `wai.quantum.planner/1` |
|
||
| `routes` | every route the host could see, an array with at least one member, each route's name once |
|
||
| `named` | the route the job names, or `null`: as below |
|
||
| `question` | the question the job asks, as below: `noise`, `counts`, `expectations` or `amplitudes` |
|
||
| `auto` | the route `auto` picks for this job, or `null`, as below |
|
||
| `wanted`, `wanted_from` | the class the routes are held to, and where it comes from, as below |
|
||
| `host` | `job_bytes`, the memory one job may take on the host, a whole number; `providers`, the names of the providers it brought, an array of strings: exactly the provider routes' names, in their order |
|
||
| `choice` | the name of the route chosen: a route of `routes` |
|
||
| `why` | a sentence |
|
||
| `stable` | below |
|
||
| `kept` | below |
|
||
| `shadow` | below: exactly when `choice` is a provider's |
|
||
|
||
A route, an object of:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `route` | its name: `method:<name>`, or `provider:<the person's name for it>`, neither name empty |
|
||
| `kind` | `local` for a method, `provider` for a provider |
|
||
| `class` | a string: the class its result has at worst on this job. A built-in method's is held to the table below; a method a host registered that declares one class has that one, and one that declares several has the first of `bit-exact`, `exact`, `single`, `bounded`, `estimate` and `heuristic` that each of them meets (so `single` and `bounded` together are `heuristic`). A provider's route has the class its `provenance` gives (§8.4), and one that cannot run the job is `unknown` |
|
||
| `host_dependent` | `true` or `false`: whether the route depends on the host. A provider's, a method on a GPU (`statevector_single`, `cutrank_single`) and a method the host registered are, and no other built-in is |
|
||
| `auto_rank` | on a local route: its rank in `auto`'s order for the job's `question`, a whole number, or `null` where `auto` does not try it. A built-in method's is the table's below; a registered method's is the host's word |
|
||
| `price` | `null`, or an object: below |
|
||
| `outcome` | `chosen`, `met` or `rejected`. Exactly one route is `chosen`, and it is `choice` |
|
||
| `rejected` | exactly when `outcome` is `rejected`: `code`, one of the codes below, and `why`, a sentence |
|
||
| `approximate` | `true`, on a provider's route whose provider states its simulator is approximate |
|
||
|
||
and a provider's route may name its `provider`, `device` and `provenance`, a
|
||
method's its `method`, as words a person reads. Where a provider's route names its
|
||
`provenance`, its class is the one that gives (§8.4), and where the route chosen names
|
||
its `device` or `provenance`, they are the result's provider's (`planner_choice`).
|
||
|
||
The classes of the built-in methods, and which of them a route has on a job:
|
||
|
||
| method | classes | a route's |
|
||
|---|---|---|
|
||
| `exact` | `bit-exact` | |
|
||
| `statevector`, `tensor_network`, `density_matrix` | `exact` | |
|
||
| `statevector_single`, `cutrank_single` | `single` | |
|
||
| `pauli`, `pulse` | `bounded` | |
|
||
| `trajectories` | `estimate` | |
|
||
| `mps` | `exact`, `heuristic` | either; a route says `heuristic`, since a run can be truncated, and a result not truncated says `exact` |
|
||
| `stabilizer` | `exact`, `estimate` | `estimate` where the request gives a `noise` or a device `target`, else `exact` |
|
||
| `stabilizer_rank` | `exact`, `estimate` | `estimate` where its `options` give `terms` or `epsilon`, else `exact` |
|
||
| `cutrank` | `exact`, `single` | either: the memory a job has chooses the precision of its table |
|
||
|
||
Each is the class of the route listed in `routes`, priced or not, on a job that names
|
||
a provider as on any other: a shadow's class is its route's. The `accuracy.class` of a
|
||
result of a built-in method, and of a shadow's, is one of its method's; `contract_class`
|
||
and `shadow` hold them.
|
||
|
||
A price, an object of:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `money` | `free`: `true`, or `false` with `amount` and `currency` (strings, the amount as the provider gives it, at most 64 characters, with an optional `unit`), or `false` with `unknown`, a sentence. An unknown cost is not free (§7). A local route's is `free` `true`: only a provider's costs. `at_least`, absent or `true`: the amount is the least the job can come to, and what it takes decides the rest |
|
||
| `time` | `seconds`, a number from 0 to 10^12 or `null`; with a number, `basis`: `nominal`, at the engine's rate for the method's work, or `provider`, the provider's own estimate, queue included; with `null`, `why`. A host takes a provider's estimate past 10^12 seconds, or an amount past 64 characters, as no estimate: `null` here, `unknown` there, with why |
|
||
| `memory_bytes`, `work` | what a method takes, as whole numbers, a double past 2^53 − 1; `null`, and only `null`, on a provider's route |
|
||
| `energy` | `joules`, a number or `null`: an estimate of what the run takes, from past runs, with `basis`, and never a promise: a job's work leaves out what drives its time, and the same job read twice differs. With `null`, `why`. `watch`, a sentence, says what reads the run while it runs, and what that covers; with none, `unwatched`, a sentence, says why nothing can. A route has at most one of the two. A contract's `max_joules` is enforced by that reading, while the run goes (below): an estimate can only refuse a job clearly past a ceiling. No provider states a job's energy before it runs and no host reads one's run, so a provider's `joules` is `null` and it has no `watch` |
|
||
| `leaves_out` | what the price leaves out, an array of: `time`, it states no time; `amount`, it states no amount; `energy`, it states no energy; `mitigation`, what the provider's own mitigation costs or does, unless a client set it off or the device has none; `decoder`, any decoder's latency; `charged`, what the provider charges may differ from what it estimates; `cancel`, its client cannot stop a job it sent |
|
||
| `program` | on a provider's route, optional: the `shots`, `native_gates`, `two_qubit_gates` and `swaps` of what would be sent, and `expected_success` when a calibration states one |
|
||
|
||
**What is named.** `named` is `provider:` the request's `provider`, where it gives
|
||
a string; else `method:` its `method`, where that is a string other than `auto`;
|
||
else, for a request that names a device `target`, the one method that target's
|
||
noise takes, a local route of `routes` (the host's word: the engine's own choice
|
||
for a target); else `null`.
|
||
|
||
**The question** a job asks is read from its request alone: `noise` when it has a
|
||
`noise` other than `null`; else `counts` when its shots are above 0 (its `shots`,
|
||
a whole number written as one from 0 to 2^64 − 1, or, where it gives none or
|
||
another, 1024 when it gives no non-empty `observables` and no non-empty
|
||
`amplitudes`, and 0 otherwise); else `expectations` when it gives non-empty
|
||
`observables` and no non-empty `amplitudes`; else `amplitudes`.
|
||
|
||
**What `auto` picks** is read from the routes: `null` when `named` is not `null`;
|
||
for a request whose `fabric` is neither absent, `null`, `auto` nor `cpu`,
|
||
`method:statevector` where that route's `price` is not `null`, else `null`;
|
||
otherwise the local route whose `price` is not `null` and whose `auto_rank` is
|
||
least, the first in `routes` of equal ranks, or `null` when there is none. Each
|
||
built-in method's rank, by question:
|
||
|
||
| method | noise | counts | expectations | amplitudes |
|
||
|---|---|---|---|---|
|
||
| `exact` | | 20 | 20 | 10 |
|
||
| `statevector` | | 30 | 30 | 20 |
|
||
| `statevector_single` | | 40 | 40 | 30 |
|
||
| `stabilizer` | 20 | 10 | 10 | |
|
||
| `pauli` | | | 60 | |
|
||
| `mps` | | 60 | 70 | 70 |
|
||
| `stabilizer_rank` | | | 50 | 50 |
|
||
| `tensor_network` | | | | 60 |
|
||
| `cutrank` | | 50 | | 40 |
|
||
| `cutrank_single`, `pulse` | | | | |
|
||
| `density_matrix` | 10 | | | |
|
||
| `trajectories` | 30 | | | |
|
||
|
||
(an empty cell is `null`). So what `auto` picks is what a verifier finds: a host
|
||
cannot lower the class a job keeps by naming a weaker route `auto`'s. Whether a
|
||
route has a price is the host's word, held to what the engine gives by
|
||
`--recheck` (below).
|
||
|
||
**What is wanted.** `wanted` is the contract's `exactness` when it gives one,
|
||
with `wanted_from` `contract`. When it gives none, the job keeps what it would
|
||
have had: the class of the `named` route, with `wanted_from` `named`; when `named`
|
||
is `null`, the class of `auto`'s route, with `wanted_from` `auto`; and when `auto`
|
||
is `null` too, both are `null`. `named`, `question`, each built-in method's
|
||
`auto_rank`, `auto`, `wanted` and `wanted_from` must each be what these give.
|
||
|
||
**Each route's outcome.** A verifier recomputes it from the request, the route and
|
||
`host.job_bytes`, by these rules in this order: the first that applies is the
|
||
route's `rejected.code`, and a route to which none applies is not rejected.
|
||
|
||
1. `not_named`: `named` is not `null`, and this is not it.
|
||
2. `fabric`: `named` is `null`, and the request's `fabric` is neither absent,
|
||
`null` nor `auto`, and it is `cpu` and this is `method:statevector_single` or
|
||
`method:cutrank_single`, or it is anything else and this is not
|
||
`method:statevector`.
|
||
3. `cannot`: `class` is `unknown` and `price` is `null`.
|
||
4. `class`: `wanted` is not `null` and `class` does not meet it; or `wanted` is
|
||
`simulated`, the contract names it (`wanted_from` `contract`), and `approximate`
|
||
is `true`; or `wanted` is `null` and this is a provider's route. A contract
|
||
that names no class changes nothing a job already meets: an approximate
|
||
simulator the job names keeps its place.
|
||
5. `cannot`: `price` is `null`.
|
||
6. `memory`: `memory_bytes` is above `host.job_bytes`.
|
||
7. `providers`: this is a provider's route, and `contract.providers` is not
|
||
`allowed`.
|
||
8. `deadline_unknown`, `deadline`: the contract gives `deadline_seconds`, and
|
||
`time.seconds` is `null`, or above it.
|
||
9. For a provider's route whose `money.free` is not `true`: `cost_no_ceiling`, the
|
||
contract gives no `max_cost` and this is not the `named` route;
|
||
`cost_unknown`, it gives one and `money` has no `amount` that is an amount in
|
||
decimals, or no `currency`; `cost_currency`, the two currencies differ;
|
||
`cost`, the amount is above `max_cost.amount`; `cost_at_least`, `money.at_least`
|
||
is `true`, so what it will come to is not known to be within the ceiling.
|
||
Amounts are compared exactly, as decimals, with no double between them, and no
|
||
currency is converted. A
|
||
provider the request names, with no `max_cost`, meets this rule: its cost is
|
||
the person's to confirm (§7), as it is with no contract.
|
||
10. `energy_unwatched`, `energy`: the contract gives `max_joules`, and `energy`
|
||
has no `watch`, so nothing can stop the run at it; or `energy.joules` is above
|
||
it: an estimate past a ceiling refuses a job clearly over it, and one under it
|
||
promises nothing.
|
||
|
||
So an unknown never passes where something is asked of it, and nothing falls back:
|
||
not from exact to approximate, since a less exact route does not meet `wanted`; not
|
||
from a simulator to a device or the reverse, since neither's class meets the
|
||
other's. A cost ceiling confirms nothing: a run that is not free still needs the
|
||
person's word for that run (§7). Where a host chose the provider (the request names
|
||
none), that word names what the person saw: a host gives the route, who it is (its
|
||
kind, device, provenance and description, and what the person's name for it stands
|
||
for: its endpoint, settings and credential's place), its estimate's `money`, the
|
||
program and shots it would send, the job's `contract`, and how many runs of this job
|
||
the host has sent on such a word before, as a short digest, and sends the job only when
|
||
the word it is given is that digest made again at send time; a route, a device, an
|
||
estimate, a program or a contract that changed since is not sent, and a word sends
|
||
one run: the next run of the same job has another word. The count is read and the run
|
||
recorded under one lock, so two sends of one word do not both go; a run the provider
|
||
took is a run whatever became of it, and only one it refused before taking it leaves
|
||
the word unspent. A job that names a provider under a contract that allows one but
|
||
wants a class no provider's counts have is refused (`J071`) before the provider is
|
||
asked anything. A host asks no provider
|
||
anything (an estimate's request carries the compiled program, and a description
|
||
says a job is coming) where the contract does not allow one, or names no class a
|
||
provider's counts are in: with none named the job keeps a classical class, which
|
||
no provider's meets. And a host holds its reasoning to these rules before it sends
|
||
anything, since a receipt it would refuse afterwards would be a run paid for and
|
||
lost. If no route is left, the job is refused (`J071`) with each route's reason, and
|
||
there is no result to seal.
|
||
|
||
**The choice.** Of the routes these rules let through, the job runs the one this
|
||
picks, and `choice` names it:
|
||
|
||
1. when the contract gives no `exactness` and `auto`'s route is let through, it
|
||
stands: a contract that names no class changes nothing a job already meets;
|
||
2. otherwise the least of them in this order: `money.free` `true` first, then an
|
||
`amount` in decimals (at most 64 characters), the lesser first, then any other;
|
||
a `time.seconds` before a `null`, and then the lesser of each `seconds` × 1000
|
||
rounded to the nearest whole number, halves up (the floor of `seconds` × 1000 +
|
||
0.5); `local` before `provider`; the lesser `memory_bytes`, a `null` read as 0;
|
||
and the name, by its UTF-8 bytes.
|
||
|
||
`choice` must also be what ran: `method:` the result's `method`, or, when that is
|
||
`provider`, `provider:` its `provider.name`.
|
||
|
||
**`stable`** says what is the same on every host. It is an object of `scope`, a
|
||
sentence; `routes`, the names of the routes whose `kind` is `local` and whose
|
||
`host_dependent` is `false`, in the order of `routes`; `digest`; and `choice`.
|
||
|
||
- `digest` is the BLAKE3, as 64 lower-case hex digits, of the RFC 8785 text
|
||
(§8.2) of the object with `job_bytes`, `host.job_bytes`, and `routes`, an array
|
||
with one object for each of those routes in that order: `route`, `class`, and
|
||
`seconds`, `memory_bytes` and `work` from its price, each `null` when it has
|
||
none. It is the same for this request and `job_bytes` on every host of one
|
||
engine; a host that gives another has priced them otherwise, and a verifier that
|
||
holds the engine can price them again.
|
||
- `choice` is `true` exactly when `choice` names one of those routes, every route
|
||
with `host_dependent` `true` is rejected with `not_named`, `fabric` or `class`,
|
||
`contract.providers` is not `allowed`, and the contract gives no `max_joules`:
|
||
then the route chosen depends on nothing of the host.
|
||
|
||
**`kept`** says what the contract asked, against what happened. It holds exactly a
|
||
member for each of these the contract gives, each of exactly the members its row
|
||
names (`max_cost` of exactly `amount` and `currency`). A result that missed one is still an
|
||
answer, and it says so: a `kept` of `false` breaks no rule. A host that can stop a
|
||
run stops it at its deadline (`J074`), and seals nothing.
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `deadline` | `seconds`, the contract's; `elapsed_ms`, a whole number or `null`: the result's `elapsed_ms` by value when its `method` is not `provider` and it states one; for a method's result that states none, so that its bits are the same on every host (a device target's, a pulse program's), the host's own time of the run; and for a provider's, the host's time from the job's submission to its counts; `kept`, whether `elapsed_ms` ≤ `seconds` × 1000, or `null` when `elapsed_ms` is `null` |
|
||
| `energy` | `max_joules`, the contract's; `joules`, the result's `stopped.joules`, else its `energy.joules_micro` ÷ 10^6, or `null` when it has neither; `kept`, `false` for a stopped run, else whether `joules` ≤ `max_joules`, or `null` when `joules` is `null` |
|
||
| `cost` | `max_cost`, the contract's; `charged`, equal to the result's `cost.charged` (numbers by value), or `null` when it has none; `kept`: with a `charged` in the ceiling's currency and an amount in decimals, whether it is at most the ceiling; with any other `charged`, `null`; with no `charged`, `true` when the result's `cost.free` is `true` or it has none, and otherwise `null` |
|
||
|
||
**The class given.** The result's `accuracy.class` meets `wanted` when `wanted` is
|
||
not `null`, and a result whose `accuracy.approximate` is `true` does not meet a
|
||
`simulated` the contract names. A route whose result falls short of `wanted`, whether the contract
|
||
named it or the job keeps what it would have had, gives no answer (`J072`): a
|
||
host seals no result this rule refuses.
|
||
|
||
**The shadow.** When a provider answers a contract job, a classical method that can
|
||
reach the same counts within the contract runs too. `planner.shadow` says which,
|
||
before anything runs, and the result's `shadow` carries what it gave. A shadow can
|
||
be run again by anyone; it is the one part of a provider's result that can.
|
||
|
||
`planner.shadow` is an object with `route`, a method's route `method:<name>`, or
|
||
`null`. With a route, which `routes` lists: `class`, a class of `bit-exact`, `exact`,
|
||
`single`, `bounded`, `estimate` and `heuristic`, and the one `routes` gives that route;
|
||
`budget_seconds`, what the contract leaves it: the
|
||
deadline less the chosen route's `time.seconds`, and 0 when that is more, the
|
||
deadline where it is `null`, and 300 with no deadline; `price`, a local route's
|
||
price, whose `time.seconds` is a number at most `budget_seconds`; and `request`,
|
||
an object of exactly `qasm`, the request's (a string); `shots`, the result's
|
||
(by value); `seed`, the request's `seed` (a whole number written as one, from 0 to
|
||
2^64 − 1, and 1 when it gives none or another) plus 2^32, modulo 2^53, a stream of
|
||
its own so that a seeded simulator's counts are not its counts by construction;
|
||
and `method`, what follows `method:` in `route`. No other member: a noise model or
|
||
any option would make the shadow another program. With `null`: `code`, one of
|
||
`budget`, `memory` and `none`; `why`, a sentence; and optionally `tried`, an array,
|
||
each method's own.
|
||
|
||
A result's `shadow` is one of:
|
||
|
||
- `ran` `false`, with `code`, a string, and `why`, a sentence: when `planner.shadow`
|
||
has no `route`, `code` is its `code`; otherwise `failed`, the method's run did not
|
||
complete. The provider's answer stands, alone, and says so; `--recheck` runs the
|
||
planned shadow, and a host whose failed shadow runs there is found.
|
||
- `ran` `true`, where `planner.shadow` has a route: with `route` and `request`,
|
||
equal to those of `planner.shadow` (numbers by value); `shots`, the result's;
|
||
`accuracy`, an object whose `class` is a string that meets `planner.shadow.class`
|
||
and is one of its method's; `counts`, keyed by outcomes all as long as the
|
||
provider's counts' (where they list one) and each of `0` and `1` only, each a whole number written as one from 1 to 2^53 − 1, and
|
||
`omitted_shots`, a whole number of at least 0 by value, which sum exactly to the
|
||
result's `shots` (a whole number by value); `distinct_outcomes`, a whole number
|
||
of at least 0, and, with no shot omitted, the number of outcomes listed; optionally
|
||
`elapsed_ms`; and `distance`.
|
||
|
||
`distance` is an object. With `computed` `false`, it has `why`, and it is `false`
|
||
only when the provider's or the shadow's `omitted_shots` is not 0 (by value: `0`
|
||
however it is written is 0). Otherwise it is `computed` `true` and, with a_k and b_k
|
||
the provider's and the shadow's count of each outcome k in either, S the result's
|
||
`shots` read as a whole number from 0 to 2^64 − 1 (its double's whole part, and
|
||
2^64 − 1 past it), and the outcomes taken in the order of their UTF-8 bytes:
|
||
|
||
- `numerator`, the sum of |a_k − b_k|, and `denominator`, 2·S, whole numbers,
|
||
each exact and written as a double past 2^53 − 1;
|
||
- `total_variation`, `numerator` ÷ `denominator`;
|
||
- `hellinger_fidelity`, R·R ÷ (S·S), with R the sum, in that order, of √(a_k × b_k),
|
||
each count taken as a double and the product a double's;
|
||
- `sampling_tvd_bound`, the lesser of 1 and 0.5·F ÷ S, with F the sum, in that
|
||
order, of m(a_k + b_k): a bound on the total variation these shots alone would
|
||
leave between two samples of one distribution, on average, for every number of
|
||
outcomes and shots. m(n) is what a fair coin's split of n leaves between its two
|
||
sides on average, E|2B − n| with B binomial (n, ½): 0 for n = 0; for n = 2j + 1
|
||
or 2j + 2 with j < 4096, the product, from 1 and in that order, of (2i + 3) ÷
|
||
(2i + 2) for i from 0 to j − 1; and from j = 4096, (2j + 1) × c with c = (1 −
|
||
1 ÷ (8j) + 1 ÷ (128·j·j) + 5 ÷ (1024·j·j·j)) ÷ √(π·j), each term as written. Given
|
||
how many shots of each outcome the two lists hold together, two lists of S shots
|
||
each split them at least as tightly as the coin does, so F ÷ 2S is at least the
|
||
expected total variation.
|
||
|
||
A count is a whole number written as one (no fraction, no exponent) from 0 to
|
||
2^64 − 1, and 0 when it is anything else or absent. S of 0, or counts that sum to
|
||
more than 2·S, gives no distance, and a `distance` that states one then does not
|
||
hold. Each double is IEEE 754, rounded to nearest, computed in the order
|
||
written, so that every verifier gets the same bits.
|
||
|
||
**Reasons.** A verifier reports each of these that applies, beside those of §8.4:
|
||
|
||
| reason | when |
|
||
|---|---|
|
||
| `contract_form` | the request's `contract` is not of its form (of §8.7, then reported alone); or, under a contract, a provider's result of the earlier form (§8.4), which states neither where its counts come from nor what was done to them |
|
||
| `contract_provider` | the request names a `provider` and its contract's `providers` is not `allowed` |
|
||
| `planner_form` | a contract job's result has no `planner`, or one not of the form above: `format`, `routes` and each route's members (a local route's `auto_rank`, its money free, every `seconds` and amount within its bounds), `named`, `auto` and `choice` each naming a route of `routes` or `null` (`choice` a route), `question`, `host`, `why`, `stable` and `kept` an object, each present; or `named`, `question`, a built-in method's `auto_rank`, `auto`, `wanted` or `wanted_from` is not what the request and the routes give. Or a result with no contract carries a `planner`. Reported alone of §8.7, beside `contract_provider` |
|
||
| `planner_route` | a route's `rejected.code` is not what the rules above give it (or it is rejected when they let it through, or not when they do not), or the route `chosen` is not one and `choice` |
|
||
| `planner_choice` | `choice` is not the route the choice's rules pick from those the rules let through, whatever their `outcome` says; or it is not what ran: a method's result is of another method, and a provider's names another provider, or its `cost` is not its route's `money` (`free` alike, and `amount`, `currency`, `unit` and `at_least` in its `estimate` alike), or the route names a `device` or `provenance` that is not its provider's. Members are alike as numbers are by value (`7` and `7.0`, `-0` and `0`), a boolean only to a boolean, and `null` as an absent member |
|
||
| `planner_stable` | `stable.routes`, `digest` or `choice` is not what the routes give |
|
||
| `stopped` | the result's `stopped` is not of its form above, or is on a job whose contract gives no `max_joules` |
|
||
| `planner_kept` | `kept` does not hold exactly a member for each the contract gives, or any of those members is not what the table gives |
|
||
| `contract_class` | the result's class does not meet `wanted` |
|
||
| `shadow` | `planner.shadow` or the result's `shadow` is missing when `choice` is a provider's, or present when it is not; or `planner.shadow` is not of its form above (its route, class, budget, price and request), or the result's `shadow` is not of its form, its `request` is not what `planner.shadow` gives, its counts do not sum to the shots, its class does not meet the plan's, or its `distance` is not what its counts give. Or a result with no contract carries a `shadow` |
|
||
|
||
A verifier also states, for a contract job, its `choice`, `wanted`, the class given,
|
||
`stable.choice`, `kept`, whether its shadow ran, and its `total_variation`. A price
|
||
is the host's word, as everything it says it received, sent and checked is (§8.5):
|
||
what a verifier recomputes is what follows from it. A verifier that holds the engine
|
||
can price the routes again and run the shadow again
|
||
(`wai-quantum verify --recheck`), which holds `digest`, `named` and `auto` to what
|
||
this engine gives (`auto` over the routes that depend on the host as the host stated
|
||
them: a verifier here has neither its GPU nor its registered methods); holds the
|
||
shadow's counts and class to a run here; runs a shadow the host says failed; and,
|
||
on the same engine, plans the shadow again, so that which method ran, or that none
|
||
could, is what this engine gives: a verifier without one takes those on the host's
|
||
word. A receipt sealed by another engine whose shadow did not run is held neither
|
||
way: what this engine plans is said, and the recheck does not say it holds. So is any
|
||
receipt sealed by another engine version: a recheck there gives `holds` `null` unless
|
||
something differs.
|
||
|
||
The free job service reaches no provider. It lists none among its routes, a
|
||
contract that wants a device's class is refused there (`J071`), and a request that
|
||
names a provider is refused there as it always is (`J002`).
|
||
|
||
### 8.8 Whose key, and when
|
||
|
||
§8.4 says whether a key signed a job. It does not say whose key it is, whether
|
||
that key was still its holder's when it signed, or whether the receipt is still
|
||
offered. Those are the reader's to decide, and a verifier takes them as two
|
||
things the reader gives it, each optional: a **trust list**, and a **time**. With
|
||
neither, a verifier judges the seal and the rules of §8.4 and §8.7 alone, and its
|
||
verdict says nothing was held to a list.
|
||
|
||
**The trust list** is a key set in the form the job service publishes
|
||
(`wai.quantum.receipt-keys/1`, at `/.well-known/wai-quantum-receipt-keys`), so a
|
||
reader who trusts a service fetches its set and gives it as it is; a reader who
|
||
trusts a person's key writes one entry. It is an object:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `format` | `wai.quantum.receipt-keys/1` |
|
||
| `algorithm` | optional; `ed25519` when present |
|
||
| `keys` | an array of entries, each an object |
|
||
|
||
and an entry:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `key` | the public key, 64 lower-case hex digits; a key is listed once |
|
||
| `not_before_ms` | optional: the first moment of the window the key signed in. Absent or `null`: open from the start |
|
||
| `not_after_ms` | optional: the first moment after that window. Absent or `null`: no end |
|
||
| `revoked_from_ms` | optional: the time from which whoever keeps the list no longer vouches for what the key signed. Absent or `null`: not revoked |
|
||
| `transition` | optional: for a key retired by rotation, the statement both keys signed (below). Absent or `null`: none |
|
||
|
||
Each time is a whole number of milliseconds since 1970, from 0 to 2^53 − 1,
|
||
however it is written. Any other member (the service's `did`, `current`,
|
||
`successor` and `note`) is ignored. A window is half-open: `not_after_ms` is its
|
||
successor's first moment and not its own last.
|
||
|
||
A **transition** is `{"statement", "retiring_signature", "successor_signature"}`,
|
||
its statement `{"format": "wai.quantum.key-transition/1", "retiring", "successor",
|
||
"at_ms"}` with each key as 64 lower-case hex digits. Each signature (128
|
||
lower-case hex digits) is Ed25519, strictly (§8.2), by the key it is named for,
|
||
over BLAKE3 of the 26 ASCII bytes `wai:quantum-key-transition`, the byte `0x01`,
|
||
and the statement's canonical text. A transition on an entry must name that
|
||
entry's key as the one `retiring` and be signed by both keys.
|
||
|
||
The list is read as a job's text is (§8.2). One that does not read, or is not of
|
||
this form in any entry, is refused whole: the verifier judges nothing by it, says
|
||
why, and gives no verdict (the two verifiers exit 2). A list is never read in
|
||
part.
|
||
|
||
**The reasons.** Held to a list, to a time, or to both, a verifier reports each of
|
||
these that applies beside those of §8.4, for a receipt of its form (one for which
|
||
`receipt_form` is not reported, and none of the reasons reported alone). `issued`
|
||
is the receipt's `time.issued_ms`, and "no time" a receipt with no `time`:
|
||
|
||
| reason | when |
|
||
|---|---|
|
||
| `key_untrusted` | a list is given, and no entry's `key` is the receipt's. The next two are then not reported |
|
||
| `key_window` | the entry has a `not_before_ms` and `issued` is before it; or it has a `not_after_ms`, and `issued` is at or after it or the receipt seals no time |
|
||
| `key_revoked` | the entry has a `revoked_from_ms`, and `issued` is at or after it or the receipt seals no time |
|
||
| `expired` | a time is given, the receipt has a `not_after_ms`, and the time given is at or after it |
|
||
| `issued_later` | a time is given, and `issued` is after it by more than the allowance given with it (0 when none is) |
|
||
|
||
A receipt that seals no time can be shown to precede no moment, so it passes a
|
||
window with no end and a key that is not revoked, and fails a window that ends and
|
||
any revocation. Held to a time alone it gets no reason: it states nothing to hold
|
||
to one. A set (§8.6) is placed by its own receipt; its items are bound by its
|
||
root.
|
||
|
||
A verdict states what it found and what it was held to: `time`, `{"sealed": true,
|
||
"issued_ms", "not_after_ms"}` (the end `null` when the receipt states none) or
|
||
`{"sealed": false}`; with a list, `trust`, `{"listed": true, "not_before_ms",
|
||
"not_after_ms", "revoked_from_ms"}` as the entry gives them (`null` for each it
|
||
does not) or `{"listed": false}`; and with a time, `checked_at_ms` and `skew_ms`.
|
||
`wai-quantum verify --trust KEYS.json --at MS --skew-ms MS` and
|
||
`receipt_verify.py --trust KEYS.json --at MS --skew-ms MS` take them alike;
|
||
`--at now` on the command line reads its machine's clock.
|
||
|
||
**What this proves, and what it does not.** The time is the signer's word, signed.
|
||
An honest signer's receipts are placed where they were made, so a rotation's
|
||
window and a receipt's own end hold against whoever shows an old receipt again.
|
||
It does not hold against the key's holder: whoever has a key can seal any time
|
||
with it. So a key that is retired, or revoked because its holder stopped using it,
|
||
is revoked from that moment, and what it signed before stands. A key that was
|
||
taken by someone else is revoked from 0, or from the moment it was last known
|
||
safe, by whoever keeps the list: every receipt it signed from then is refused,
|
||
whatever time it states, and so is every one that states none. A revocation is in
|
||
the list a reader holds, and reaches a reader when they fetch the list again;
|
||
nothing in a receipt carries one.
|
||
|
||
### 8.9 The verified answer
|
||
|
||
A receipt shows that a result is the one its signer sealed. It does not show that the
|
||
answer is right. A job MAY say what its answer must do, and its result then seals how far
|
||
that was checked, by what, and what that check does not show.
|
||
|
||
**The intent.** A job's `intent` is one intent or a list of them. Each names one target,
|
||
with its tolerance where it has one:
|
||
|
||
| intent | it is of | what must hold |
|
||
|---|---|---|
|
||
| `{"distribution": {"00": 0.5, "11": 0.5}, "tolerance"}` | the program | the exact distribution of the measured bits is within `tolerance` of it in total variation distance |
|
||
| `{"expectation": {"observable": "Z0 Z1", "value": 1.0}, "tolerance"}` | the program | the observable's exact value on the program's state is within `tolerance` of `value` |
|
||
| `{"equivalent": "<program>"}` | the program | the same circuit as the reference, up to a global phase |
|
||
| `{"prepares": "<program>"}` | the program | the same state from \|0…0⟩, the same qubits measured into the same bits |
|
||
| `{"sampled": {…}, "test", "alpha", "shots", "seed"}` | a run made for it | samples of the program, run again as the job runs it, are consistent with the distribution by the test at the level |
|
||
| `{"outcomes": ["00", "11"], "tolerance"}` | the answer | no more than `tolerance` of the answer lies outside the outcomes named |
|
||
| `{"conserves": {"weight": 2}}`, `{"conserves": {"parity": 0}}`, with `tolerance` | the answer | no more than `tolerance` of the answer lies outside the outcomes whose digits sum to `weight`, or whose digits' sum modulo 2 is `parity` (a symmetry of the problem) |
|
||
| `{"counts": {…}, "test", "alpha"}` or `{"counts": {…}, "tolerance"}` | the answer | the counts the job returned are consistent with the distribution by the test at the level, or within `tolerance` of it in total variation distance |
|
||
| `{"agrees": "simulation", "test", "alpha"}` or with `tolerance` | the answer | the counts the job returned are consistent with, or within `tolerance` of, the exact distribution the engine computes of the program |
|
||
|
||
Any intent MAY carry a `name`, a `note`, and `"require": "proof"`, under which a check
|
||
that is only evidence counts as not decided. An intent that does not read is refused
|
||
before anything runs (`J020`). A provider's job is read before it is sent, so a job is
|
||
never paid for and then refused its verdict; a `sampled` intent is refused there, since
|
||
no run of the engine stands for a device's: its samples are held to a distribution by
|
||
`counts`, and to the program's by `agrees`.
|
||
|
||
**The verdict.** The result carries `verdict`, of the form `wai.quantum.verdict/1`
|
||
(`wai-quantum/schemas/verdict.v1.json`), inside what the receipt seals. It states a
|
||
`level` (`refused`, `parsed`, `executed`, `evidence`, `proof`), `holds` (`true`, `false`,
|
||
or `null` when an intent was not decided), each intent's check under `intent`
|
||
(`outcome`: `holds`, `fails` or `unchecked`; `strength`: `proof`, `evidence` or `none`;
|
||
`how`; `why`), and since this section the **layer** that decided it and that layer's
|
||
**limits**, for each check and for the verdict:
|
||
|
||
| `layer` | what the engine did (`how`) | strength | its limits |
|
||
|---|---|---|---|
|
||
| `exact_simulation` | computed the program's exact state, distribution or expectation value and compared (`statevector`, `density_matrix`, `exact`, `state`); for an energy-landscape job, every arrangement (`enumeration`) | proof | only where the engine can simulate: up to 26 qubits without noise, 16 under the job's noise, every basis state up to 8 qubits, every arrangement up to 16 variables; in double precision; of the program as written, not of a device |
|
||
| `stabilizer` | equal stabilizer tableaus (`tableau`) | proof | Clifford circuits only, at any width |
|
||
| `pass_equivalence` | each rewrite or compile pass checked where it acts, the distances added (`rewrites`; a compile's `proof`, `approximate`) | proof | what the engine's rewrite rules reach; an approximate compile holds within its stated bound |
|
||
| `reading` | what the reader found of the two programs decides it (`shape`) | proof | decides a difference only |
|
||
| `certificate` | the answer itself held to the checks its problem states (`checks`) | evidence | the answer passes those checks; nothing shows no better answer exists |
|
||
| `random_states` | the two circuits run on random product states (`random`) | evidence | up to 22 qubits, on the inputs drawn |
|
||
| `agreement` | the counts the job returned held to the exact distribution the engine computed of the program (`chi_squared`, `g_test`, `total_variation`) | evidence | only where the engine can simulate the program; a test that does not reject is no proof |
|
||
| `samples` | samples held to a stated distribution (`chi_squared`, `g_test`, `total_variation`) | evidence | no more than its samples can show; the distribution is the one the intent states |
|
||
| `physical_consistency` | the counts the job returned obey a conserved quantity or lie in a set of outcomes (`counts`) | evidence | a necessary condition on the samples returned: nothing of the outcomes' weights, nor of an outcome too rare to be sampled |
|
||
| `unchecked` | nothing decided it | none | the answer stands on the run alone, by a method of the stated accuracy class |
|
||
|
||
A host that seals a verdict:
|
||
|
||
1. MUST decide each intent by the strongest layer it has for it. An `outcomes` or a
|
||
`conserves` intent is decided by `exact_simulation` where the run is the program's own
|
||
(not a device's, nor a device model's) and the engine can compute its distribution, and
|
||
on the counts otherwise.
|
||
2. MUST name, for each check, the layer its `how` is of, and the strength that layer has in
|
||
the table. It MUST NOT name a stronger one.
|
||
3. MUST say `unchecked`, with why, where no layer decided an intent: the program is wider
|
||
than the engine simulates, measures in the middle, the job returned no counts, or its
|
||
counts leave out some of its shots. A verdict with no intent, or with one intent
|
||
undecided, has the layer `unchecked` and `holds` `null`.
|
||
4. MUST give the verdict the weakest of its checks' layers, in the table's order from the
|
||
bottom, and that layer's limits.
|
||
5. MUST name in `executed` the method the result names and the accuracy class the result
|
||
states.
|
||
|
||
**The accuracy class.** Every result a host seals states what its numbers are, under
|
||
`accuracy.class`: `exact`, `single`, `bounded`, `estimate` or `heuristic` for the engine's
|
||
methods; `bit-exact` for a qudit job and for the bit-exact method; `measured` for a
|
||
processor's counts and `simulated` for a simulator's (§8.1); `exact` for a wasmQ job by
|
||
the tableau and `bit-exact` for one by the state vector (quantum-wasmq §11.4); and
|
||
for an energy-landscape job the parity its member ran at, `bit-exact` or `statistical`
|
||
(`member.parity`). A verdict repeats it under `executed.accuracy`, so the class is beside
|
||
the layer wherever the verdict is read.
|
||
|
||
**Which jobs carry one.** A circuit job run by the engine, a provider's job and a qudit
|
||
job (`wai.quantum.qudit/1`, whose intents are of its counts: `outcomes`, `conserves`,
|
||
`counts`, in its digits, `parity` modulo its dimension) take `intent` in the request and
|
||
seal `verdict` in the result. An energy-landscape job states what its answer must do in
|
||
its program, and seals its own word (quantum-landscape §3.1): a verifier reads `solved`
|
||
with a truth as `holds` by `exact_simulation`, `solved` on the program's checks alone as
|
||
`holds` by `certificate`, `missed` and `failed` as `fails`, and `unchecked` as
|
||
`unchecked`. A wasmQ job's form is closed (quantum-wasmq §6.5) and holds no intent.
|
||
|
||
**A sign-off.** A job whose form holds no intent, or one another host sealed, is given
|
||
one by a job about it. Its request is `{"signoff": {"job": <the job, as its host returned
|
||
it>, "intent": <an intent, a list, or absent>}}`. Its result has `format`
|
||
`wai.quantum.signoff/1`; `job`, with `digest` (the digest that job's own receipt signs,
|
||
§8.2, in hex), `key` and `form`; `accuracy.class`, the job's own (`unstated` where it
|
||
states none); and `verdict`: the job's own sealed verdict where the sign-off gives no
|
||
intent, otherwise the intent checked against the job, a job with counts and no program
|
||
the engine reads being held to its counts. A host MUST refuse to sign off a job whose
|
||
receipt does not verify (`J001`), a job whose sealed verdict or compile certificate
|
||
differs from what the job bears out (`J001`: the job is not valid though its seal holds,
|
||
and a sign-off would seal its verdict again under another key), and a sign-off of a
|
||
sign-off. The sign-off's receipt seals the job, the intent and the verdict together under
|
||
the signing host's key.
|
||
|
||
**What a verifier does.** Given a job whose receipt and every rule of §8.4 hold and whose
|
||
result seals a verdict, a verifier works the verdict out again and states it under
|
||
`answer`, beside the receipt's check:
|
||
|
||
- `level`, `holds`, `layer`, `limits` and `accuracy`, as the verdict's own checks conclude
|
||
them;
|
||
- `again`: `reproduced` when every check was decided again here and is the same;
|
||
`partly` when some were and the rest could not be; `host_statement` when none could be:
|
||
the verdict is then the host's word under its seal, and a reader takes it as that; and
|
||
`differs` when the verdict is not what the job bears out;
|
||
- `checks`, each with the layer, what was sealed, what was found here and its `status`;
|
||
`differences`; and `statement`, in one line.
|
||
|
||
A verdict `differs`, and the job is then not `valid` though its seal holds, when: its
|
||
`level`, `holds` or `layer` is not what its own checks conclude; a check names a
|
||
strength or a layer its `how` does not have; it names a method or an accuracy class the
|
||
result does not; a sign-off names another job (its digest, its key, its receipt's form) or
|
||
another accuracy class than the job it holds gives; it checks other intents than the
|
||
request gives; or a check decided here has another outcome, or only a weaker strength,
|
||
than the one sealed. Two cases are the host's statement and not a difference, since only
|
||
the host could show them. A `sampled` check's samples are of a run the host made: where
|
||
the samples drawn again here give another outcome, the check's own sealed samples
|
||
(`counts`) are held to its test at its level, and where they bear the sealed outcome out
|
||
the check is the host's statement (where they do not, it differs). And a check sealed by
|
||
another version of the engine (`engine.version`) that this one decides with the same
|
||
outcome and only a weaker strength is the host's statement, with both versions named. A verifier decides a
|
||
check again within the state vector of 22 qubits (11 under noise), and reads one past
|
||
that as the host's statement. A distance within 1e-9 of its tolerance on both sides is
|
||
the same. A verdict sealed before layers were named has none to compare, and is held to
|
||
its level and its checks. A record that copies a run's verdict and holds none of the run
|
||
(a project's check, which binds the run's receipt by its digest) is held to the verdict's
|
||
own form, and is otherwise the host's statement. `wai-quantum verify --lines` judges each line as a receipt
|
||
alone, and works no verdict out again.
|
||
|
||
A verifier simulates what a classical machine can. Where it cannot, the receipt says so,
|
||
and never claims a layer that did not hold.
|
||
|
||
|
||
### 8.10 A grade
|
||
|
||
A grade holds a program to a task's cases and seals what it found as a job, so that
|
||
anyone can run the grade again and reach the same answer.
|
||
|
||
**The request.** `{"grade": {"task": <the task>, "program": <the program's text>}}`, and
|
||
no other member. The task is in the exercise form (`wai-quantum/schemas/exercise.v1.json`):
|
||
|
||
- `intent`, one intent or a list, as §8.9 gives them; or `cases`, at most 16, each with a
|
||
`name`, `inputs` (a generator's integer inputs) and its own `intent` or the task's, at
|
||
most 8 intents each;
|
||
- `job`: `shots`, `seed` and `noise`, and nothing else;
|
||
- `constraints` on how the program is written: the gates allowed, gate counts, the T
|
||
count, the two-qubit count, the critique's smells, the resource estimate's counts, the
|
||
qubits, and the input whose value is the qubit an injected error flips;
|
||
- a `title` and a `task` in words.
|
||
|
||
A task MUST NOT carry `reference`, `wrong` or `hints`: the receipt seals the task whole,
|
||
and those would publish its answer with it. A host MUST refuse a task that is not of this
|
||
form (`J001`) or whose intents do not read (`J020`), before anything runs.
|
||
|
||
**Each case.** The program is read at the case's inputs and run as the task's job asks (16
|
||
shots at seed 1 where it names none), with the case's intent. The run's verdict decides
|
||
the case as §8.9 decides a job's, each intent by the strongest layer the host has for it.
|
||
A case is:
|
||
|
||
- `passed` when its intents hold, checked as proof or as evidence;
|
||
- `failed` when one does not hold, or when the reader refuses the program at the case's
|
||
inputs;
|
||
- `unchecked` otherwise: no layer decided an intent, or the run was refused (a job past
|
||
the host's memory).
|
||
|
||
**The result.** Its `format` is `wai.quantum.grade/1` (`wai-quantum/schemas/grade.v1.json`):
|
||
|
||
- `cases`, in the task's order, each with its `name`, `inputs`, `grade` and `passed`, the
|
||
verdict of its run (`verdict`), and that verdict's `level`, `holds` and `layer` beside it;
|
||
- `constraints`, each measured on the program as it reads in every case: `rule`,
|
||
`subject`, `holds` and `found`;
|
||
- `what_went_wrong` and `pointer`: what went wrong and where to look, in English, from the
|
||
reader's diagnostics, the verdicts and the critique, never from an answer;
|
||
- `summary`: how many cases have each grade, how many constraints there are, and how many
|
||
do not hold;
|
||
- `passed`: true when every case passed and every constraint holds;
|
||
- `verdict`: one verdict of every case's checks, in the cases' order. A case that ran no
|
||
check stands as its intents, each `unchecked`, with why. Its level, `holds` and layer are
|
||
what those checks conclude, as for one job, so its layer is the weakest of any case's.
|
||
|
||
The receipt seals the request and the result together: the task, the program and the
|
||
grade under the host's key. A host that seals no time (§8.2) seals the same bytes each time
|
||
it makes the same grade with the same key.
|
||
|
||
**What a verifier does.** A grade's result seals a verdict, so a verifier works it out
|
||
again as §8.9 says, the grade made again standing for the job run again. A grade also
|
||
differs, and is not valid though its seal holds, when:
|
||
|
||
- a case's verdict is not of its own form, or a case's `level`, `holds` or `layer` is not
|
||
its verdict's;
|
||
- a case's `grade` or `passed` is not what its verdict's checks give;
|
||
- the grade's `verdict` does not check its cases' checks;
|
||
- `passed` or `summary` is not what the cases and the constraints give;
|
||
- against the grade made again, a case's name, inputs or the method it ran on, or a
|
||
constraint as measured, is different.
|
||
|
||
A constraint that another version of the engine (`engine.version`) measured differently
|
||
is that host's statement, not a difference.
|
||
|
||
**A task set graded.** A grader MAY grade every task of a set at once. The batch is a
|
||
document, not a job: it is not sealed itself, and each of its grades is. Its `format` is
|
||
`wai.quantum.grades/1` (`wai-quantum/schemas/grades.v1.json`), and it holds:
|
||
|
||
- `grades`, one entry a task in the set's order, each with its `name`: the task's `id`
|
||
where it has one, else its `title`, which the grade's request seals with the task. A
|
||
set whose tasks do not each name themselves, once, is refused whole. An entry is one of:
|
||
- a grade: `job`, the grade as a host returns it (`{"request", "result"}` as above,
|
||
sealed), and `grade`, the task's: `passed` when the grade passed, `failed` when a case
|
||
failed or a constraint does not hold, `unchecked` otherwise;
|
||
- `missing`: no program was given for the task, with the `task`;
|
||
- `refused`: the grade was refused (the task is not of the exercise form, its intents do
|
||
not read, or it carries its answer), with the `task`, the `program` and why.
|
||
- `set`: BLAKE3 of the RFC 8785 canonical text of the list of the tasks, each as its
|
||
grade's request seals it or as its entry gives it, in order, in lower-case hex;
|
||
- `summary`: how many tasks there are, how many were graded, passed, failed and unchecked,
|
||
how many are missing and how many refused; and the graded tasks' cases (passed, failed,
|
||
unchecked) and constraints (broken) added up.
|
||
|
||
A grader that seals no time seals the same grades each time it grades the same set with
|
||
the same programs and the same key, so the batch is the same bytes.
|
||
|
||
**What a reader does with a batch.** It verifies each grade as a job (§8.4) and works it
|
||
out again (§8.9, as above), holding each entry's `name` and `grade` to what that grade's
|
||
request and result seal; grades a refused entry again and finds it refused; makes `set`
|
||
and `summary` again from the entries; and holds the batch valid only when every grade is
|
||
valid and nothing differs. What a batch does not show: that a task listed as missing had
|
||
no program, or that a refused one was given no other. Those are the grader's statements; a
|
||
reader who holds the programs grades them again.
|
||
|
||
## 9. Conformance
|
||
|
||
`wai-quantum-qpu/conformance/provider-v1.json` holds the vectors:
|
||
|
||
- **messages**, sent as they are: an unknown operation (`unsupported`),
|
||
another version (`unsupported_version`), a message without its protocol
|
||
(`invalid`), a job that does not exist (`not_found`), malformed programs
|
||
(`invalid`);
|
||
- **programs**, each compiled to the device, estimated, run with seed 1, and
|
||
checked by its counts: the probe, bits named out of order, a phase only
|
||
interference shows, a phase kicked back by two quarter-turn controlled
|
||
phases, a Bell pair, and a triangle of two-qubit gates that needs routing
|
||
on a line. The thresholds leave room for a device's noise;
|
||
- **reference**: the counts the reference provider gives for each program at
|
||
seed 1, so its determinism is held on every platform;
|
||
- **billing**: `describe` answers' `billing`, each with how a client reads it:
|
||
`free`, `priced`, `unpriced` (not free, and no price set), or `refused`, of
|
||
none of the three forms of §5.1, and so a description that is not complete;
|
||
- **estimates**: `estimate` answers, each with how a client reads it (§5.2):
|
||
`free`, `priced`, `unpriced` (not free, and no price set for the job: its cost
|
||
unknown, a landscape job's counts stated), or `refused`, of none of the three
|
||
forms;
|
||
- **results**: `result` answers to a job of two bits that asked a number of
|
||
shots, each with how a client reads it (§5.5): `kept`, its counts of the
|
||
shots the device kept (its `accepted_shots` when it gives one, else every
|
||
shot asked), or `refused`: counts that sum to neither, or an
|
||
`accepted_shots` that is not a whole number of at least 1. Nothing of a
|
||
refused answer is sealed;
|
||
- **landscape**, for a device whose `describe` has `landscape` (§11): its
|
||
description's form; messages that each break one rule of §11.2, each refused
|
||
with its code; and jobs, each estimated (its `operations` and `bytes` as the
|
||
vector gives them), run when every estimate says free or the person allows the
|
||
spend, followed to `done`, its answer read twice and found the same, of the
|
||
version its request names and held to quantum-landscape §5.4 as that version
|
||
reads it, and, from a member whose parity is `reference` or
|
||
`bit-exact`, its replay digest the vector's; and each job's `cancel` answered by
|
||
how it ended. The set holds messages and jobs of both versions of the landscape
|
||
protocol. A job's version is its request's `protocol` (the first where it names
|
||
none), and a device is sent the jobs of the versions its description lists
|
||
(§11.1). A message that names its `version` is sent to a device that lists that
|
||
version; one that names none holds in every version, and a device that does not
|
||
list the first is sent it with its own version named in the request. A device is
|
||
also sent one job of each version it does not list, which it must not take:
|
||
`unsupported`, or `refused` from a provider of this text as it stood before the
|
||
second version (§11.2).
|
||
|
||
The checker (`wai-quantum providers test NAME`) also checks the `describe`
|
||
answer in full (its `billing` one of the three forms), each `estimate` answer it
|
||
is given (one of §5.2's three forms; an unpriced one is a cost it does not know,
|
||
so the jobs run only with the spend allowed), that zero shots are
|
||
`invalid`, and that a program in another basis is refused. A device that runs no
|
||
circuits (§11.1) is held to the messages and to its landscape vectors, and its
|
||
circuit programs are not run. It runs the
|
||
programs only when every estimate says free, or the person allows the spend
|
||
(`--yes`). A program's counts are of the shots the device kept (§5.5), and its
|
||
vector's shares are read of those. It then asks to cancel each job it ran, and holds the answer to
|
||
§5.6: `done` for a job that finished, and `failed` with its reason for one that
|
||
failed (or `unsupported`, from a provider that cannot cancel).
|
||
|
||
The reference provider (`wai-quantum providers reference --stdio`, or
|
||
`--http ADDR`) is this protocol around WAI's exact simulator. It is the
|
||
provider the tests run against over both transports, and the template to
|
||
copy: a provider for any device is the reference with its simulation replaced
|
||
by the device. It states its counts' source and its `execution` (§5.5). It takes
|
||
energy-landscape jobs of both versions on the reference's own kernels (§11), unless
|
||
it is told not to (`--no-landscape`) or to take one version alone
|
||
(`--landscape-protocol 1`, or `2`); with `--qubits 0` it takes those alone. With `--unpriced` it
|
||
sets no price: its `billing` is §5.1's third form, and every estimate §5.2's
|
||
unpriced form.
|
||
|
||
**Receipts.** `quantum-conformance/receipts/` holds job receipts and what a
|
||
verifier must say of each (§8.4): receipts made by the command line on this
|
||
machine and by the job service, provider jobs of every built-in kind through
|
||
services that follow their contracts, jobs under a contract (§8.7), the earlier
|
||
form, the first (receipts the
|
||
first form's own writer sealed, and others `generate.py` made from §8.2's text),
|
||
receipts that seal a time (§8.2), and receipts sealed to break one rule each. Its
|
||
`held/` holds receipts judged held to a trust list or a time (§8.8), each rule at
|
||
its bound on both sides, with what each is held to and the reasons a verifier must
|
||
then give; and its `trust/` the trust lists, those a verifier reads and those it
|
||
must refuse whole. A
|
||
receipt from a person's account names that account, and is not published: it is
|
||
checked with the differential's `--extra`, outside CI. A receipt once made is
|
||
kept, pinned by its digest. Two verifiers judge every one of them, and every
|
||
receipt made from a valid one by changing one member, numbers among them to
|
||
values past a double's range of whole numbers: `wai-quantum verify`, and
|
||
`quantum-conformance/tools/receipt_verify.py`, written from §8 alone in another
|
||
language and sharing no code with the engine. They must report the same reasons
|
||
for every receipt, and the manifest's for each in the corpus. Every other
|
||
surface that verifies is held to the manifest by its own tests, given each
|
||
receipt's text: the job service over HTTP and as a tool, the command line's tool
|
||
(each takes the job's text), the Python package (text, bytes or a path), the
|
||
desktop app and a browser tab. A job is judged from text wherever there is text:
|
||
a tool or a view given a job as members of its message (the job as an object, a
|
||
call's arguments as the job's own members, a view's object) judges those members
|
||
as the message's text writes them, read as §8.2 reads a job, so that a member
|
||
named twice (`unreadable`) and a whole number past a double (`inexact_number`) are
|
||
seen in a job given either way. Each such verdict says how the job was given
|
||
(`given`): `text`, the job's own text; `members`, as the message wrote them; or
|
||
`parsed`, a value some reader had already parsed with no text behind it (a call
|
||
made inside a program), whose verdict also names what it could not see
|
||
(`not_seen`: a member named twice, and a whole number past what that reader keeps).
|
||
`members` says that the message's own text was judged, and no more: a sender that
|
||
parsed the job before it wrote the message had already lost what parsing loses, so
|
||
a job is sent as its text where that matters. A job parsed deeper than a text is read (127) is
|
||
`unreadable` there too, however deep it is: a message that carries a job (a tool's
|
||
call, a view's request) is read so that the job reaches its verdict (a job nested past
|
||
127, or past what the surface reads, is judged before the message is read whole, and the
|
||
message around it may nest at most 8 more), and a message that does not read is the
|
||
protocol's error, as a line that is not UTF-8 is to the command line's MCP server, which
|
||
answers it and reads on. The Python package judges a dict as the text it writes
|
||
for it, so a dict's nesting and its whole numbers are judged as text's are; only a
|
||
member named twice is past what a dict can hold. It reports every other reason, and is held to the
|
||
manifest on every receipt but those. A tool's text is a JSON string, which holds
|
||
UTF-8 only, so text that is not UTF-8 reaches a verifier only as a file's bytes.
|
||
|
||
## 10. Versioning
|
||
|
||
`wai.quantum.provider/1` is this text. A later version is a new `protocol`
|
||
string; a provider that speaks only this one answers `unsupported_version` to
|
||
another. Fields marked optional may be added to answers without a new
|
||
version, and a client MUST ignore fields it does not know.
|
||
|
||
A result's receipt seals every member it holds, so a member a later text adds
|
||
to the result is in no receipt sealed before it, and every such receipt
|
||
verifies as it did (§8.4's earlier form). `counts_source`, `execution`,
|
||
`compiled.qasm3`, the class `simulated` and `accuracy.approximate` were added
|
||
so, as were the answers' `counts_source` and `execution`, `describe`'s
|
||
`approximate`, and a request's `contract` with a result's `planner` and `shadow`
|
||
(§8.7): a receipt of a request with no contract verifies as it did. So was
|
||
`cost.confirmed_by` (§8.1), which no receipt sealed before it holds.
|
||
|
||
A receipt's `time` (§8.2) was added within this version, and differently: it is
|
||
inside the digest, under a domain byte of its own, so that it cannot be taken off.
|
||
Every receipt sealed without one verifies as it did, and a verifier of this text
|
||
says of it that no time is sealed. A verifier of the earlier text ignores a
|
||
receipt's `time` as a member it does not know, computes the digest of a receipt
|
||
with none, and reports `digest_mismatch`: it fails closed on a receipt that seals
|
||
a time, and never takes one for a receipt that seals none. So a host seals a time
|
||
only for readers whose verifier knows it; the job service does by default and can
|
||
be told not to, and the command line does only when asked. A trust list and a time
|
||
to hold a receipt to (§8.8) are a verifier's inputs, not a receipt's members: a
|
||
verifier given neither answers as it did, with `time` added to what it states.
|
||
|
||
The basis `prxrzxx`, the gate `move` and `describe`'s `resonators` and
|
||
`moves` were added within this version too. A client that does not know
|
||
`prxrzxx` finds no basis it compiles to on such a device and refuses it; one
|
||
that does not know `resonators` takes a resonator's pairs for a qubit's, and
|
||
what it sends there a provider refuses (§4: a one-qubit gate on a resonator,
|
||
a measured resonator), so neither runs a program the device was not meant to
|
||
run. A verifier that does not know `prxrzxx` reports `provider_members` on a
|
||
result in it: it fails closed.
|
||
|
||
A form an earlier client already reads safely may also be added within this
|
||
version. `billing`'s third form, `{"free": false, "priced": false}` (§5.1),
|
||
was added so: a client that does not know it reads a `billing` of no form it
|
||
knows, and so a cost it does not know, which is what the form says; only a
|
||
checker that does not know it refuses the description. So was a `cancel`
|
||
answering `failed`, with its reason, for a job that had failed (§5.6): a client
|
||
reads a job's end from its `status` (§5.4), which has always said `failed`.
|
||
|
||
`estimate`'s third form, `{"free": false, "priced": false}` (§5.2), was added
|
||
the same way. A client that does not know it reads an answer that is not free and
|
||
names no amount, which it refuses as an estimate not of its form, and so takes the
|
||
job's cost to be unknown: it shows no figure, the job is not free, and it is
|
||
submitted only on the person's confirmation for that run, which is what the form
|
||
says. Such a client never runs the job as free, and loses only the counts the
|
||
answer states, which it does not show. A checker that does not know the form fails
|
||
the estimate; one that does reads it as a cost it does not know. A provider of the
|
||
earlier text never sends it, and a client of this text reads every answer such a
|
||
provider sends as it did.
|
||
|
||
Energy-landscape jobs (§11) were added so. `describe`'s `landscape` is optional, and
|
||
a client that does not know it sends no such job. A provider that does not know it
|
||
is sent none, since no client sends one to a device whose description does not
|
||
offer it; sent one all the same, it finds no `program` and answers `invalid`. A
|
||
device that takes landscape jobs and no circuits states `qubits` 0, which a client
|
||
of this version that does not know §11 reads as a device it cannot compile to. A
|
||
landscape job's result is not a provider's result of §8.1 (it has no `method`), so
|
||
§8.4's provider rules, and every receipt they hold, are as they were; its own rules
|
||
are `landscape_form`'s.
|
||
|
||
The second version of the landscape protocol, `wai.quantum.landscape/2`, was added
|
||
to §11 the same way, with `describe`'s `landscape.protocols`. A provider of the
|
||
earlier text states `protocol` alone, `wai.quantum.landscape/1`, and a client of
|
||
this text reads that as a device that takes the first version only, and sends it
|
||
no job of the second. A client of the earlier text sends no job of the second
|
||
version to any provider. It reads `protocol`, which is the earliest version a
|
||
device takes, and ignores `protocols`: a device that takes both is to it the device
|
||
it was, and one that takes the second alone states a `protocol` it does not know,
|
||
whose description it refuses, so it sends that device nothing. A provider of the
|
||
earlier text that is sent a second-version job all the same answers `refused`,
|
||
since its reader reads the first version's requests only; this text asks
|
||
`unsupported` of a device for a version it does not list, and a client reads
|
||
either as a job that was not taken. A receipt of a first-version job verifies as
|
||
it did; a second-version job's result names its version, and `landscape_form`
|
||
holds it to that version's rules (§8.4).
|
||
|
||
## 11. Energy-landscape jobs
|
||
|
||
A device may take jobs of [quantum-landscape](quantum-landscape.md),
|
||
`wai.quantum.landscape/1`, and of its second version,
|
||
[quantum-landscape-2](quantum-landscape-2.md), `wai.quantum.landscape/2`: no
|
||
circuit, but an energy over variables of three states, and a request for a state
|
||
of low energy. Such a job travels in that extension's own form, its operation and
|
||
its request, and its answer comes back as that extension's answer (§3 there): this
|
||
protocol carries them, and defines no second form of either. A device that says
|
||
nothing of them takes none, and nothing here changes a circuit's job.
|
||
|
||
A job's version is the one its request names under `protocol`, and the first
|
||
where it names none, as the extension reads a request (quantum-landscape-2 §2).
|
||
Wherever this section names a section of quantum-landscape, a job of the second
|
||
version is read by that section as quantum-landscape-2 changes it: its request and
|
||
its program (§2 there), its answer and its joules (§3, §4.3), its members (§5) and
|
||
the rules a verifier holds it to (§5.4). The bounds and the counts of
|
||
quantum-landscape §2.0 are the same in both versions.
|
||
|
||
The provider is the host of quantum-landscape §5: its reader, its truth, its
|
||
checks, and its placing of the job on the members it has (a CPU, a GPU, a board).
|
||
The answer says which member ran it, at what parity the provider found that
|
||
member's kernel, what its audit checked and which members it passed over, as that
|
||
extension's §3 says every answer does.
|
||
|
||
### 11.1 Describing it
|
||
|
||
A `describe` answer whose device takes landscape jobs carries `landscape`, an
|
||
object of:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `protocol` | the earliest version of the landscape protocol it takes: `"wai.quantum.landscape/1"` for a device that takes the first version, and `"wai.quantum.landscape/2"` for one that takes the second alone |
|
||
| `protocols` | optional: every version it takes, a non-empty array of `"wai.quantum.landscape/1"` and `"wai.quantum.landscape/2"`, none twice, `protocol` the earliest of them. Where it is absent the device takes `protocol` alone |
|
||
| `ops` | the operations it takes: a non-empty array of `run`, `sweep`, `compare` and `replay`, none twice |
|
||
| `members` | optional: what it places jobs on, in the order it offers them (quantum-landscape §5), each `{"id", "class"}` |
|
||
| `max_bytes` | optional: the most memory a job may hold on it, as quantum-landscape §2.0 counts it, where that is less than 268,435,456 |
|
||
|
||
A device that takes landscape jobs and no circuits gives `qubits` 0,
|
||
`native_gates` `[]` and `connectivity` `[]`; it still reads a program, and answers
|
||
`invalid` for one that does not read and `refused` for one that does (it has no
|
||
qubit to run it on). A client MUST NOT send a landscape job to a device whose
|
||
`describe` has no `landscape`, an operation it does not list, or a job of a
|
||
version it does not list: a device whose `landscape` has no `protocols` takes the
|
||
version its `protocol` names and no other. A device that lists a version takes
|
||
every operation in `ops` in it, on members that run that version
|
||
(quantum-landscape-2 §5): a member that does not is passed over, and the answer
|
||
says so under `refusals`.
|
||
|
||
### 11.2 The messages
|
||
|
||
`estimate` and `submit` carry, in place of `program`, `shots` and `seed`, the
|
||
member `landscape`: an object of exactly
|
||
|
||
- `op`: the operation, `run`, `sweep`, `compare` or `replay` (`examples` runs
|
||
nothing, and is not sent);
|
||
- `request`: the request of quantum-landscape §2, an object, its seed,
|
||
temperatures and parity among its members, and its `protocol`, which a job of
|
||
the second version MUST name (quantum-landscape-2 §2).
|
||
|
||
The provider answers:
|
||
|
||
- `invalid` for a message with both `landscape` and `program`, a `landscape` not of
|
||
that form, or an `op` not one of those four;
|
||
- `unsupported` for a landscape job on a device whose `describe` has no
|
||
`landscape`, for an `op` it does not list, or for a job of a version of the
|
||
landscape protocol it does not list (a provider of this text as it stood before
|
||
the second version answers `refused` to that last, as its reader does, and a
|
||
client reads either as a job not taken);
|
||
- `refused` for a request quantum-landscape's reader refuses (a `protocol` that
|
||
names no version of the extension among them), or one past the
|
||
device's own limit (`max_bytes`): `message` is that refusal's plain sentence, as
|
||
quantum-landscape §2 writes it, and the error object adds `line`, the line of the
|
||
program the sentence names, where it names one.
|
||
|
||
A provider reads a request as quantum-landscape §2 reads it, and checks every bound
|
||
of §2.0 there before it takes it, so a job it cannot run is refused at `estimate`
|
||
and at `submit` alike, and never after it was taken.
|
||
|
||
`estimate`'s answer is §5.2's, with `operations` and `bytes` added: the job's
|
||
operations and memory as quantum-landscape §2.0 counts them before anything runs.
|
||
They are the same for the same request on every host, and a client that counts
|
||
them otherwise refuses the estimate. Any billing unit of §5.2 holds; one operation
|
||
of §2.0 there is the natural one. A provider with no price for a landscape job
|
||
answers §5.2's unpriced form with them, `{"free": false, "priced": false,
|
||
"operations", "bytes"}`, and not `unsupported`, which would leave them unstated.
|
||
|
||
`submit`'s answer is §5.3's `job`. `status` and `cancel` are §5.4's and §5.6's,
|
||
whatever the job.
|
||
|
||
`result`'s answer, once the job is `done`, has `landscape`: the answer of
|
||
quantum-landscape §3 to the job's operation, of the version the request names
|
||
(its `protocol` says which), as the provider gave it; and
|
||
optionally `charged` (§5.5). It has no `counts`, `shots`, `counts_source`,
|
||
`execution` or `energy`, which say nothing of such a job: a member with a meter
|
||
states its reading where quantum-landscape §4.4 puts it, in the answer's
|
||
`joules.metered`. A `result` asked twice of the same job gives the same answer.
|
||
|
||
### 11.3 What the client checks, and what it seals
|
||
|
||
Cost and confirmation are §7's: a client shows a landscape job's estimate, or that
|
||
its cost is unknown, before it submits it, and submits one that is not free only
|
||
on the person's confirmation for that run.
|
||
|
||
A client checks the request before it asks anything, as quantum-landscape §2 reads
|
||
it, and refuses one the reader refuses. It checks the answer before it seals it:
|
||
it is the answer of the operation it sent, of the version it sent, and holds every
|
||
rule of quantum-landscape §5.4 for the request it sent, as that version reads them.
|
||
An answer that does not is refused, and nothing is sealed: an answer of one version
|
||
to a job of the other breaks rule 2 or rule 3 there.
|
||
|
||
The client seals the job as every host seals a job (§8.2): `request` is the
|
||
request it sent, with `provider` added, the person's name for the provider (a
|
||
request that names a provider already is refused before anything is sent); and
|
||
`result` is the answer with these added, each of exactly these members:
|
||
|
||
| member | |
|
||
|---|---|
|
||
| `provider` | `name`, the request's `provider`; `kind`, `http` or `process`; `protocol`, `wai.quantum.provider/1`; `device`; `provenance`; and `describe`, each as §8.1 has it |
|
||
| `job` | `id`, the provider's id for the job, and `polls`, the status checks before it finished |
|
||
| `cost` | `free`, `estimate`, `charged` and `confirmed`, as §8.1 has them: `charged` is `null` or `{"amount", "currency"}`, and `confirmed` is `true` exactly where the run was not free |
|
||
|
||
and `engine` and `schema` (the answer's version, `wai.quantum.landscape/1` or
|
||
`wai.quantum.landscape/2`), as every engine result. The
|
||
result has no `method`: it is no provider's result of §8.1, and §8.4's provider
|
||
rules do not apply to it. quantum-landscape §5.4's do (`landscape_form`), the
|
||
members above among them (rule 13 there).
|
||
|
||
The receipt proves what §8.5 says any receipt proves: that the key it names signed
|
||
this request and this answer, and nothing about whether the device ran it. The
|
||
state is the provider's word, as counts are, and so are the member it names and
|
||
the parity it states. What anyone can work out from the request and the answer is
|
||
held to it by the rules: the program's digest, the state's hash and the replay
|
||
digest. The energy can be worked out from the program, and `wai-quantum verify`
|
||
does so (quantum-landscape §5.4). An answer whose member's parity is `reference` or
|
||
`bit-exact` gives the reference's bits, so anyone can run the job on the reference
|
||
and compare its replay digest.
|
||
|
||
A job service that serves the public reaches no provider, for a landscape job as
|
||
for any (§1): a request there that names a `provider` is refused.
|