open-standards/wai/extensions/quantum-ops.md
Transaction Science 75898a5b97
Some checks failed
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 21s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 15s
wai-app and Create / wai-app · does this change touch it (push) Successful in 22s
wai-audit collector and player integration / does this change touch it (push) Successful in 18s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 1m2s
wai-quantum command line / does this change touch it (push) Successful in 22s
wai-ledger service / does this change touch it (push) Successful in 36s
wai-quantum editors / does this change touch it (push) Successful in 13s
wai-quantum other formats / does this change touch it (push) Successful in 14s
WAI operation catalogue / does this change touch it (push) Successful in 43s
wai-quantum contract / does this change touch it (push) Successful in 21s
wai-fleet service / does this change touch it (push) Successful in 42s
wai-quantum error correction and mitigation / does this change touch it (push) Successful in 17s
wai-quantum qudit jobs / does this change touch it (push) Successful in 23s
wai-quantum studio and desktop / does this change touch it (push) Successful in 16s
wai-quantum extension points / does this change touch it (push) Successful in 24s
wai-quantum verdicts and repairs / does this change touch it (push) Successful in 12s
wai-sink-android native sink library / does this change touch it (push) Successful in 16s
wai-sink-swift native sink package / does this change touch it (push) Successful in 15s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 17s
WAI Studio / does this change touch it (push) Successful in 12s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 1m33s
wai-quantum resource estimation / does this change touch it (push) Successful in 1m27s
wai-quantum pulse and dynamics / does this change touch it (push) Successful in 1m10s
wai-quantum OpenQASM reader / does this change touch it (push) Successful in 1m13s
wai-quantum service / does this change touch it (push) Successful in 59s
wai-quantum variational and algorithm library / does this change touch it (push) Successful in 54s
wai-quantum for Python / does this change touch it (push) Successful in 1m10s
wai-quantum for JavaScript / does this change touch it (push) Successful in 1m25s
wai-quantum service / service energy · linux packages (push) Successful in 2m4s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 2m22s
wai-quantum pulse and dynamics / the same bits · linux-arm64 (push) Successful in 2m46s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 7m5s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux-arm64, release (push) Successful in 3m19s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 5m8s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 6m52s
wai-quantum extension points / the registry and the example · linux-arm64 (push) Successful in 6m26s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 27s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 33s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 24s
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Successful in 16s
wai-quantum other formats / the set under wasm32-wasip2 (wasmtime) (push) Successful in 3m10s
wai-audit collector and player integration / collector · linux (push) Successful in 3m58s
wai-quantum wasmQ / does this change touch it (push) Successful in 11s
wai-ledger service / service · linux (push) Successful in 3m45s
wai-quantum other formats / readers, writers and the set · linux (push) Successful in 4m46s
wai-quantum qudit jobs / the module and the conformance set under wasm32-wasip2 (wasmtime) (push) Successful in 2m29s
wai-quantum contract / API compatibility · linux (push) Successful in 5m16s
wai-quantum error correction and mitigation / codes, decoders, texts and mitigation · linux, release (push) Successful in 3m20s
wai-fleet service / service · linux (push) Successful in 6m2s
wai-quantum extension points / the registry under wasm32-wasip2 (wasmtime) (push) Successful in 2m10s
wai-quantum verdicts and repairs / verdicts, repairs and the intent set · linux (push) Successful in 2m21s
wai-quantum editors / editors · linux (push) Successful in 8m41s
wai-quantum extension points / the registry and the example · linux (push) Successful in 4m40s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 9m15s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m16s
wai-quantum qudit jobs / the module, the job, the conformance set, the referee and the verb · linux (push) Failing after 6m56s
wai-quantum verdicts and repairs / the intent set and the verdict under wasm32-wasip2 (wasmtime) (push) Successful in 3m20s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Successful in 31s
wai-quantum contract / schemas and the committed tool lists · linux (push) Successful in 9m12s
wai-quantum studio and desktop / studio · browser (push) Successful in 6m53s
wai-quantum views in agent hosts / views · the page and its engine (push) Successful in 4m12s
wai-quantum OpenQASM reader / corpus under wasm32-wasip2 (wasmtime) (push) Successful in 53s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime) (push) Successful in 1m12s
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Successful in 3m32s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 12m52s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs · linux, release (push) Successful in 3m15s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux, release (push) Successful in 3m50s
wai-quantum for Python / python · linux (push) Successful in 4m23s
wai-quantum for JavaScript / javascript · linux (push) Successful in 4m19s
wai-quantum OpenQASM reader / reader and corpus · linux (push) Successful in 6m2s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 12m42s
wai-quantum service / service · linux (push) Failing after 6m41s
wai-quantum views in agent hosts / views · a scripted host (push) Successful in 10m12s
WAI Studio / Studio in WebKit · linux (push) Successful in 12m36s
wai-quantum resource estimation / estimation and calibration · linux, release (push) Successful in 12m48s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 10m15s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 3m45s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 4m21s
wai-quantum command line / command line · macos (push) Successful in 3m3s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 10m0s
wai-quantum command line / command line · linux (push) Failing after 52m54s
wai-fleet service / service · macos (push) Successful in 57s
wai-ledger service / service · macos (push) Successful in 2m37s
wai-quantum editors / editors · macos (push) Successful in 2m11s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Successful in 45m7s
wai-quantum qudit jobs / the same bits · macos (push) Successful in 3m43s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Failing after 2m15s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 5m55s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 7m55s
wai-quantum pulse and dynamics / the same bits · macos (push) Successful in 3m9s
wai-quantum wasmQ / the reference modules rebuild to their modules of record · linux (push) Successful in 46s
wai-quantum for Python / python · macos (push) Successful in 3m28s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 16m57s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 9m9s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · linux (push) Successful in 4m15s
wai-quantum wasmQ / interpreter and vectors under wasm32-wasip2 (wasmtime) (push) Successful in 4m10s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 8m51s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 9m44s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 11m9s
wai-quantum service / service · macos (push) Successful in 8m15s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 17m35s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 20m53s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 7m25s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · macos (push) Successful in 2m12s
quantum-ops: the encoding in the text, four more records registered, and an unmetered form that never reads zero joules
quantum-ops named its records' fields and deferred everything else to the reference, so no
verifier could be written from the text, and it allowed `0` as the unmetered marker, which
quantum-landscape and wasmQ/2 forbid.

- extensions/quantum-ops.md §3, written from quantum_ops.rs and quantum_energy.rs: the
  primitives and their framing (§3.1), reading a receipt's JSON (§3.2), each kind's payload
  and Merkle leaves (§3.3), the identity (§3.4), the energy forms (§3.5), the reasons a
  verifier gives (§3.6), and the links and content hashes (§3.7). What is read and decides
  nothing is named: the written receipt_hash, a decode/compile/rearrange receipt's written
  merkle_root, an evidence summary (not sealed), members no text names.
- Registered: wai.quantum.mitigate, .decode, .compile, .rearrange (SPEC §5, quantum-ops §1.3
  to §1.6; registry.rs, the export regenerated). wai.quantum.qbom and .fabric are stated not
  to be part of the standard (quantum-ops §8) and stay unregistered with that reason. §5 of
  the text no longer names third-party tools.
- The unmetered form (quantum-ops §3.5, energy-measurement §2.8): quantum_energy::Unmetered,
  for every Labellable family (calibration, job, mitigation, decode, compile, rearrange,
  circuit, phasor, sparse-Pauli, resource). Under the 0x02 domain the figure 0 is followed by
  tag 0 and the reason (u32 BE length, UTF-8); its JSON writes joules_micro null beside
  energy_unmetered. MaybeLabelled gains the variant and unmetered()/joules_micro(), the
  latter never Some(0); an unlabelled 0 still verifies and reads as unmetered (legacy).
  wai_quantum_meter and wai-quantum-serve seal unmetered runs in the new form, and serve's
  POST /verify verdict says why. quantum-sim's receipt text says so.
- Reading tightened where the JSON showed what the seal does not say: a member named twice
  (sig::unique_members), a kind of another family, rounds/swaps/atoms_moved past u32 (read
  before as their low 32 bits), a funds_ceiling that is no count and an optional hash that is
  no string (each read before as none) no longer read; a str()-framed string holding U+0000
  no longer verifies (two receipts could sign the same bytes).

Vectors (wai/quantum-ops-conformance): 12 receipts the reference made, every kind and every
energy form (the three earlier ones byte-identical), and 49 crafted by generate.py, each one
defect away or one change that decides nothing, with hand-written reasons. ops_verify.py,
written from §3 alone and sharing no code with the engine, gives the 12 their identities and
the 49 their exact reasons; wai_quantum_ops_vectors verify gives all 61 their verdicts and
stages. CI: the corpus's verify in cargo-classes as before; ops_verify.py and
generate.py --check as a new independent verifier (verifiers/quantum-ops.sh).

Failing first: the crafted receipts given to the reader before this change (origin/main
1f5bc7225, a scratch test over MaybeLabelled::from_json and verify) verified nine of the
defects this change refuses: a member named twice (plain and escaped), a calibration whose
kind is a job's, one with no kind, rounds of 2^32 + 1 sealed as 1, a funds_ceiling "50"
sealed as none, a parent_receipt_hash of 0 sealed as none, and a device_id and a grant
capability holding U+0000. The six crafted receipts of the unmetered form did not read
there, since the form did not exist.

Tested on the build host: wai-quantum --features full --lib --tests (lib 1560 passed, 26
ignored; every integration test passed, landscape_conformance's 54 among them); default
features (127), quantum_ops alone (51), quantum_receipt alone (50); wai-rs with the
energy-receipts workflow's feature set, --lib --bins --test video_receipt (906, 4, 15, 130);
wai-rs codecs::registry (15) and `wai registry export --check`; wai-quantum-serve (12);
wai-quantum-cli's test build; wai-web cargo check; wai_quantum_ops_vectors verify and
ops_verify.py on the corpus; clippy: no finding on a changed file of wai-quantum, serve or
the two wai-rs bins. Locally: check-wai-section-refs, check-spec-refs,
check-wai-quantum-names, check-public-names --maintainer-products-only,
changelog-assemble --check, check-tests-in-ci, check-wai-core-freeze,
wai-conformance-lists check, check-wai-corpus-licences: clean. wai breaking against main:
the two breaks the changelog entry acknowledges.

quantum_ops.rs is one of the sources the wasmQ modules of record pin
(quantum-conformance/wasmq/modules/modules.json): its digest is updated, and on x86_64
Linux (build.sh --check) both modules still build byte for byte as committed.

Rebased on 15b7f810d: the registry export is up to date, and the registry, ops, energy,
pins and sig tests, serve's tests and wai_quantum_ops_vectors verify pass again.

Changelog entry: wai/changes/2026-11-10-quantum-ops-encoding-and-unmetered-form.md

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-10 15:30:53 -05:00

24 KiB
Raw Permalink Blame History

WAI Extension: Quantum-Operations Attestation (wai.quantum.calibration · wai.quantum.job · wai.quantum.mitigate · wai.quantum.decode · wai.quantum.compile · wai.quantum.rearrange)

Status: Draft. Engine: wai-quantum/src/quantum_ops.rs (feature quantum_ops, which wai-rs forwards under the same name and re-exports as wai::quantum_ops), with the energy forms of wai-quantum/src/quantum_energy.rs. The verify-half of WAI (wai.asset.provenance's lineage, specialized) applied to the operations around a quantum processor.

0. What this extension adds

A calibration run or a job on a quantum processor leaves a dataset, a state snapshot and a log; so does each classical step around it: the mitigation of its counts, the decoding of a syndrome, the compilation of a circuit, the rearrangement of a neutral-atom register. This extension adds a receipt over each operation with two properties:

  1. cryptographic signature + portability: a record a third party verifies from the bytes alone, by the rules of §3, which are complete: a verifier written from them alone agrees with the reference on every vector of the corpus (§4);
  2. joules, or a statement that nobody measured them: the energy of the operation with its acquisition class, or the unmetered form with its reason (§3.5), and never a figure of zero joules for a run nobody read.

Version capture of the software that ran, bills of materials and hash-chained audit traces exist elsewhere; the receipt here is signed, content-addressed and grant-bounded. It is not a control system and runs no hardware: the operation is performed by the sink's control stack, exactly as WAI dispatches a decode to a sink's codec. WAI owns the receipt.

1. The records

Six records, one per operation, each sealed the same way (§3): a payload of fixed binary framing, signed with Ed25519, whose content hashes are bound by a BLAKE3 Merkle root. Each carries a grant (§2), an optional parent_receipt_hash (the identity, §3.4, of the receipt this one follows: a signed lineage), its signer's key and label, and its energy (§3.5).

1.1 Calibration (wai.quantum.calibration)

A signed record of one bring-up or tune-up run (CalibrationReceipt; the calibration engines of quantum_cal, quantum_control and quantum_noise produce what it binds):

  • device_id, target ("q3", "cz(q3,q4)", "readout:q3");
  • config_hash: the content hash of the applied pulse or gate configuration;
  • evidence[]: each {kind, blob_hash, summary}, a benchmark outcome (randomized benchmarking, T1 and T2, Rabi, a readout fit) content-addressed to its raw dataset bytes, so a fidelity claim binds to the exact bytes that produced it (evidence_matches()). summary is a human sentence and is not sealed (§3.2): only kind and blob_hash are;
  • merkle_root, over [config_hash] ++ evidence leaves (§3.3);
  • joules_micro, the run's energy (§3.5); grant; parent_receipt_hash, the prior device state this one supersedes.

1.2 Jobs (wai.quantum.job)

A signed record of one dispatched circuit (JobReceipt):

  • backend_id: what ran it ("example:qpu-a", "wai.quantum.circuit");
  • circuit_hash, result_hash (the counts histogram or the state), shots (requested);
  • calibration_ref: the identity (§3.4) of the calibration receipt of the device state the job ran under, or none for a simulator. A verifier given that calibration confirms the job names that calibration and both verify (§3.7): the property that the calibration claimed was the one in effect, signed;
  • merkle_root, over [circuit_hash, result_hash], and calibration_ref after them when there is one; joules_micro, grant, parent_receipt_hash.

1.3 Mitigation (wai.quantum.mitigate)

A signed record of one classical error-mitigation step (MitigationReceipt): the raw data and the optional noise model that went in, the estimate that came out.

  • backend_id; method ("zne.richardson", "readout.tensored", "shadow.pauli"); observable, a label of the estimated observable (sealed, but informational);
  • input_hash (the raw counts or expectation table), noise_model_hash (the model the method consumed, or none: the model's provenance pinned, not re-derived);
  • raw_estimate_fx, mitigated_estimate_fx, error_bar_fx: signed fixed point at scale 2^20 (1.0 is 1048576); shots;
  • merkle_root, over [input_hash], noise_model_hash when there is one, and the result leaf (§3.3); joules_micro, grant, parent_receipt_hash.

1.4 Decoding (wai.quantum.decode)

A signed record of one error-correction decode (DecodeReceipt): code_id, decoder, check_matrix_hash, syndrome_hash, correction_hash, converged (the correction reproduces the syndrome), rounds (a u32), work_messages (the messages passed), and joules_micro, grant, parent_receipt_hash. Whether a correction leaves a logical error is not a member: a decoder that sees only a syndrome cannot know it.

1.5 Compilation (wai.quantum.compile)

A signed record that a compiled circuit is equivalent to its source (CompileReceipt): source_hash, target_hash (the routed circuit and its final map), coupling_hash, method ("clifford-tableau"), equivalent, swaps (a u32), work, and joules_micro, grant, parent_receipt_hash.

1.6 Register preparation (wai.quantum.rearrange)

A signed record of a neutral-atom rearrangement plan (RearrangeReceipt): initial_hash (the loaded occupancy), target_hash (the target sites), plan_hash (the moves), method ("hungarian-lsap"), success (every target site filled), atoms_moved (a u32), total_distance, and joules_micro, grant, parent_receipt_hash.

2. The grant

GrantRef = capability ⊗ joule ceiling (⊗ an optional funds ceiling, JCP §4.8 dual ceiling). The full grant lives in the JCP layer; the receipt binds its content hash (grant_hash), its capability, joule_ceiling_micro and funds_ceiling.

The joule ceiling is checked inside verification (§3.6): a receipt whose joules_micro exceeds its grant's ceiling is not valid, so an operation that blew its energy grant cannot produce a passing receipt. A ceiling of 2^64 − 1 is no ceiling. An unmetered run (§3.5) has no figure to hold to the ceiling: the check passes, since its sealed figure is 0, and a verifier states that the ceiling was not checked, because the run was not metered.

3. Encoding and verification

This section is complete: it is what the reference does, and a verifier written from it alone gives every receipt of the corpus its verdict (§4). The reference's own words are seal, to_json, from_json, verify and receipt_hash of each type, and quantum_energy::MaybeLabelled for a receipt in any form.

3.1 Primitives

  • H(x) is BLAKE3 in its hash mode, 32 bytes.
  • u8(n), u32(n), u64(n) are unsigned integers and i64(n) a two's-complement integer, each big-endian, of 1, 4, 8 and 8 bytes.
  • str(s) is the UTF-8 bytes of s followed by one byte 0x00. A string framed so must hold no U+0000 (§3.6).
  • opt(h) is 0x01 ‖ h for a hash h (32 bytes), and 0x00 for none.
  • grant(g) is grant_hash ‖ str(capability) ‖ u64(joule_ceiling_micro) ‖ f, f being 0x01 ‖ u64(funds_ceiling), or 0x00 for no funds ceiling.
  • tail(r) is grant(r.grant) ‖ opt(parent_receipt_hash) ‖ signer_pubkey ‖ signer_id: the 32 key bytes, then the signer's label in UTF-8 with no terminator (it ends the payload).
  • A domain is ASCII followed by the version byte 0x01. D' is D itself in the legacy form, and D with its last byte 0x01 replaced by 0x02 in the labelled and unmetered forms (§3.5). E is what follows the figure: nothing in the legacy form, the class's signed encoding in the labelled form, and the unmetered form's tag and reason (§3.5).
  • The signature is Ed25519 over the payload bytes themselves (not a digest of them), verified strictly, by the provider protocol's rule §8.2 The signature, strictly: SPEC §7 Signatures with the key held to the prime-order subgroup, S < ℓ, R canonical and not of small order, and no cofactor.

3.2 Reading a receipt

A receipt is JSON (RFC 8259), its text UTF-8, its value an object. The reference writes its members in the order of the table below, with no space, but the order and the spacing are not read. The receipt does not read when any of these holds; the reason is §3.6's:

  1. the text is not UTF-8, not JSON, or its value is not an object; or a string in it has an escape that is no Unicode scalar value (a lone surrogate); or an object in it names a member twice, two names being the same when their escapes read as the same characters ("a" and "a") (unreadable);
  2. kind is absent, or is not the kind's string below (kind);
  3. a member the kind requires is absent, or not of its form (member):
    • a digest is a string of exactly 64 lower-case hex digits (0–9, a–f); sig is one of 128, and signer_pubkey one of 64;
    • a count is a JSON number written as an integer: digits only, with no sign, fraction or exponent, of value 0 to 2^64 − 1 (1.0, 1e0, -0 and +1 are not counts); a u32 count (rounds, swaps, atoms_moved) is a count of at most 2^32 − 1, and one past it does not read (it is never read as its low bits);
    • a signed integer (raw_estimate_fx, mitigated_estimate_fx, error_bar_fx) is a JSON number written as an integer, an optional - then digits, of value −2^63 to 2^63 − 1, and not -0;
    • a string is a JSON string; a boolean is true or false;
    • an optional digest (parent_receipt_hash, calibration_ref, noise_model_hash) is absent or null for none, or a digest; any other value does not read;
    • grant is an object with grant_hash (a digest), capability (a string), joule_ceiling_micro (a count) and funds_ceiling, absent or null for none or a count, any other value not reading;
    • evidence is an array, each entry an object with kind (a string), blob_hash (a digest) and summary (a string);
  4. the energy members break §3.5's reading (energy_form).
kind record members it requires, beside kind, grant, joules_micro, parent_receipt_hash, sig, signer_id, signer_pubkey
quantum-calibration §1.1 config_hash, device_id, evidence, merkle_root, target
quantum-job §1.2 backend_id, calibration_ref (optional), circuit_hash, merkle_root, result_hash, shots
quantum-mitigate §1.3 backend_id, error_bar_fx, input_hash, merkle_root, method, mitigated_estimate_fx, noise_model_hash (optional), observable, raw_estimate_fx, shots
quantum-decode §1.4 check_matrix_hash, code_id, converged, correction_hash, decoder, rounds, syndrome_hash, work_messages
quantum-compile §1.5 coupling_hash, equivalent, method, source_hash, swaps, target_hash, work
quantum-rearrange §1.6 atoms_moved, initial_hash, method, plan_hash, success, target_hash, total_distance

What is read and decides nothing. These are not sealed, and a verifier does not read them:

  • receipt_hash, which every form writes: the identity, for a reader's convenience. A verifier computes the identity itself (§3.4), and an application that keys receipts by identity MUST compute it, never take the written one;
  • merkle_root of a decode, compile or rearrange receipt: written for a reader, and computed by a verifier (§3.3) where the payload holds it;
  • each evidence entry's summary, a human sentence: change it and the receipt still verifies, so a reader MUST NOT present it as attested;
  • any member the table and §3.5 do not name.

3.3 The payloads

Each kind's payload, in its form (§3.5). M(l) is the Merkle root of the list of hashes l: each hash h becomes the leaf H("moq-jwp:merkle-leaf" ‖ 0x01 ‖ h); while a level holds more than one node, an odd level repeats its last node, and each pair a, b becomes H("moq-jwp:merkle-node" ‖ 0x01 ‖ a ‖ b); one node is the root. (The lists here are never empty.)

kind domain D payload
calibration wai:quantum-calibration D' ‖ str(device_id) ‖ str(target) ‖ config_hash ‖ merkle_root ‖ u64(number of evidence entries) ‖ u64(joules_micro) ‖ E ‖ tail
job wai:quantum-job D' ‖ str(backend_id) ‖ circuit_hash ‖ result_hash ‖ opt(calibration_ref) ‖ u64(shots) ‖ merkle_root ‖ u64(joules_micro) ‖ E ‖ tail
mitigate wai:quantum-mitigate D' ‖ str(backend_id) ‖ str(method) ‖ str(observable) ‖ input_hash ‖ opt(noise_model_hash) ‖ i64(raw_estimate_fx) ‖ i64(mitigated_estimate_fx) ‖ i64(error_bar_fx) ‖ u64(shots) ‖ merkle_root ‖ u64(joules_micro) ‖ E ‖ tail
decode wai:quantum-decode D' ‖ str(code_id) ‖ str(decoder) ‖ check_matrix_hash ‖ syndrome_hash ‖ correction_hash ‖ u8(converged) ‖ u32(rounds) ‖ u64(work_messages) ‖ M([check_matrix_hash, syndrome_hash, correction_hash]) ‖ u64(joules_micro) ‖ E ‖ tail
compile wai:quantum-compile D' ‖ source_hash ‖ target_hash ‖ coupling_hash ‖ str(method) ‖ u8(equivalent) ‖ u32(swaps) ‖ u64(work) ‖ M([source_hash, target_hash, coupling_hash]) ‖ u64(joules_micro) ‖ E ‖ tail
rearrange wai:quantum-rearrange D' ‖ initial_hash ‖ target_hash ‖ plan_hash ‖ str(method) ‖ u8(success) ‖ u32(atoms_moved) ‖ u64(total_distance) ‖ M([initial_hash, target_hash, plan_hash]) ‖ u64(joules_micro) ‖ E ‖ tail

A boolean is u8 1 for true and 0 for false. The merkle_root a calibration, job or mitigation receipt writes is the one its payload holds, and it must be the root of its leaves:

  • calibration: [config_hash] followed by, for each evidence entry in order, H("wai:qcal-evidence" ‖ 0x01 ‖ str(kind) ‖ blob_hash);
  • job: [circuit_hash, result_hash], followed by calibration_ref when there is one;
  • mitigation: [input_hash], then noise_model_hash when there is one, then the result leaf H("wai:quantum-mitigate-result" ‖ 0x01 ‖ str(method) ‖ i64(raw_estimate_fx) ‖ i64(mitigated_estimate_fx) ‖ i64(error_bar_fx)).

3.4 The identity

A receipt's identity, its receipt_hash, is H(I ‖ payload ‖ sig), with I the kind's identity domain (wai:quantum-calibration-id, wai:quantum-job-id, wai:quantum-mitigate-id, wai:quantum-decode-id, wai:quantum-compile-id, wai:quantum-rearrange-id, each followed by 0x01 in every form) and payload the payload of the form it is in (§3.5). Another receipt names this one by its identity: a parent_receipt_hash, or a job's calibration_ref.

3.5 Energy: a figure, or unmetered, never zero for a run nobody read

A receipt is in one of three forms, which its JSON decides:

form its JSON E (§3.1) and D'
a figure, unlabelled (the legacy form) joules_micro a count; no energy_ member nothing; D
a figure, labelled (energy-measurement §2.8) joules_micro a count of at least 1; energy_provenance and its evidence (energy-measurement §2.7) the class's signed encoding (energy-measurement §2.7); D with 0x02
unmetered joules_micro null; energy_unmetered, the reason, a string u8(0) ‖ u32(byte length of the reason) ‖ the reason in UTF-8; D with 0x02

The labelled form's class is ModelBased (tag 2), Estimator (3), OnChipCounter (4, then u32(relative_ppm) ‖ u64(window_us) ‖ u8(filtering), filtering 0 Unknown, 1 Off, 2 On) or CalibratedInstrument (5, then u32(relative_ppm) ‖ u64(window_us) ‖ u32(byte length of the reference) ‖ the reference in UTF-8). The unmetered form seals its figure as 0 and its tag as energy-measurement §2.7's tag 0, no class, followed by the reason.

Reading the energy members (§3.2, energy_form). Of energy_provenance, energy_uncertainty, energy_counter_filtering and energy_calibration_ref, one whose value is null is read as absent.

  • With energy_unmetered present, whatever its value: it is a string; joules_micro is present and null; and none of the four class members is present. The figure is read as 0.
  • Otherwise, with energy_provenance: it is one of the four names above (HwShunt, the legacy label, never labels these receipts, and any other name does not read); energy_uncertainty, when present, is an object whose relative_ppm is a u32 count and whose window_us is a count; energy_counter_filtering, when present, is Unknown, Off or On; energy_calibration_ref, when present, is a string. ModelBased and Estimator have none of the three; OnChipCounter has energy_uncertainty, may have energy_counter_filtering (Unknown when absent) and has no reference; CalibratedInstrument has energy_uncertainty and energy_calibration_ref and no filtering. A declared relative_ppm and window_us are each at least 1, and a reference is not empty once the characters of Unicode's White_Space property are taken from both its ends.
  • Otherwise, any of the three evidence members without energy_provenance does not read; with none, the receipt is in the legacy form.

What each form says, and how a 0 is read.

  • A run nobody measured is sealed in the unmetered form, saying why. Its JSON holds no zero: joules_micro is null. A producer MUST NOT seal a new unmetered run as an unlabelled 0.
  • An unlabelled receipt whose joules_micro is 0 is the legacy form of the same statement: unmetered, legacy, sealed before the unmetered form existed. It verifies as it always did, and a reader MUST present it as unmetered (legacy), never as a figure of zero joules, and MUST NOT total, average or compare it as 0 J (energy-measurement §2).
  • An unlabelled receipt with a figure of at least 1 is a figure with no class; a labelled one is a figure with its class. No form states a measured zero: a meter that read nothing produced no reading, and the receipt is unmetered.

The reference reads either unmetered form through MaybeLabelled::unmetered() (the reason, or that the receipt is of the legacy form) and gives a figure only through MaybeLabelled::joules_micro(), which is never Some(0).

3.6 What a verifier checks

A verifier reads the receipt (§3.2, §3.5) and then checks, in its form:

reason when
unreadable, kind, member, energy_form the receipt does not read (§3.2). Reported alone: nothing else is checked
string_nul a string str() frames (§3.1) holds U+0000: device_id, target, an evidence entry's kind, backend_id, method, observable, code_id, decoder, or the grant's capability. Such a string could be read as two, so that two receipts would sign the same bytes
merkle_root a calibration, job or mitigation receipt's merkle_root is not the root of its leaves (§3.3)
ceiling joules_micro is more than the grant's joule_ceiling_micro (§2)
energy the labelled form's figure is 0 (a class beside no figure), or its declared uncertainty is below the resolution floor, joules_micro × relative_ppm < 288 676 (energy-measurement §2.3); or the unmetered form's reason is empty or more than 4096 bytes
bad_key signer_pubkey is refused by the strict rule's checks of the key (§3.1). The signature is then not checked
bad_signature the signature over the payload of the receipt's form does not hold, strictly

The receipt is valid exactly when there is no reason. The reference's verify() (of each type, of Labelled, of Unmetered, and of MaybeLabelled) is true exactly then, and its from_json gives None exactly when the receipt does not read. A receipt whose label or reason was added, stripped or restated after it was sealed fails bad_signature: the form is inside the signature through D' and E.

Beside a receipt's own validity, a verifier given more checks more:

  • content: given the bytes a hash binds (a configuration, a dataset, a circuit, a result, a plan), H(bytes) equals that hash (evidence_matches, result_matches, input_matches, noise_model_matches, code_matches, correction_matches, source_matches, target_matches, plan_matches);
  • lineage: given the receipt a parent_receipt_hash names, it is that receipt's identity (§3.4) in the form it was sealed in;
  • the calibration a job ran under: given a calibration receipt, the job's calibration_ref is its identity and both are valid (verify_against_calibration, which MaybeLabelled gives for every form of each).

4. Conformance

  • A conforming producer (a control stack, or an adapter over one, §6) MUST seal a receipt per operation it attests, with every hash the real content hash; joules_micro a figure it read, with its class where it has one, and never fabricated; and a run it did not read in the unmetered form, saying why (§3.5), never as 0.
  • A conforming verifier MUST read a receipt by §3.2 and §3.5, MUST give it exactly §3.6's reasons, MUST read an unlabelled 0 as unmetered (legacy) and present no unmetered run as zero joules, and, for a job that claims a calibration state it is given, MUST check §3.7's link.
  • Receipts are portable: JSON, verifiable with the public key and the bytes they bind.
  • The corpus, ../quantum-ops-conformance/: receipts of every kind and every energy form made by the reference (vectors/, pinned in expected_hashes.json with the artifacts each binds and its links), and receipts derived from them each one defect away, with the reason §3.6 gives it, or one change §3.2 says decides nothing (crafted/). The reference (wai_quantum_ops_vectors verify) gives every one its verdict; ops_verify.py, written from this section alone and sharing no code with the engine, gives every one its verdict and its exact reasons.

5. What this is NOT

  • Not a control system, not a simulator, not a calibration learner. It attests operations others perform. The control electronics and the tuning models are the dispatched backend: WAI's "don't reinvent, dispatch" (SPEC Appendix B), applied to quantum control.
  • Not a reconstruction. joules_micro and the results are attested (only the signer can vouch for its own silicon's draw); the hashes, the Merkle root, the grant ceiling and the links are verifiable by anyone. The receipt states plainly which half is which.

6. Integration (where it attaches)

The natural attach point is the control-system → cloud boundary: the moment a calibration node or a job completes, the control system already holds everything a receipt needs (configuration, evidence datasets, result, backend identity), and its power rails are already instrumented, so adding a signature and a joule figure is incremental. In an open calibration framework, three points do it: the one place a node writes its dataset, which covers every node; the per-node boundary where the framework records the versions of the packages that ran; and, in a lab's task and database layer, the point where a production test records its pass or fail.

7. The metric

This extension carries joules per verified calibration, per job, per mitigation, per decode, per compile and per rearrangement as signed, portable, content-addressed, grant-bounded records, and says so where nobody measured them.

8. What is not part of this extension

Two more records the reference seals are not part of the standard: their labels are not registered, no text specifies their encoding, and no verifier other than the reference's is held to them.

  • wai.quantum.qbom, the reference's bill of materials (quantum_qbom): a manifest restating the stage receipts of one computation, each entry's figure with its optional class (energy-measurement §2.8). Its entries name the receipts of §1 by their identities (§3.4), and those receipts are what this extension attests.
  • wai.quantum.fabric, the reference's statement of where a result ran (quantum_fabric): the fabric member, its kernel, the parity its certificate earned against the CPU reference, and the joules.

A later revision may register either with a text and vectors of its own.