open-standards/wai/wai-wasmq/tests/vectors.rs
Transaction Science 7d0c795f63
Some checks failed
wai-quantum clippy / does this change touch it (push) Successful in 14s
wai-audit collector and player integration / does this change touch it (push) Successful in 32s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 35s
wai-quantum command line / does this change touch it (push) Successful in 22s
wai-quantum pulse and dynamics / does this change touch it (push) Successful in 16s
wai-quantum for Python / does this change touch it (push) Successful in 14s
wai-quantum qudit jobs / does this change touch it (push) Successful in 26s
wai-quantum error correction and mitigation / does this change touch it (push) Successful in 29s
WAI operation catalogue / does this change touch it (push) Successful in 1m18s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 59s
wai-quantum extension points / does this change touch it (push) Successful in 24s
wai-quantum service / does this change touch it (push) Successful in 19s
wai-quantum for JavaScript / does this change touch it (push) Successful in 58s
wai-quantum studio and desktop / does this change touch it (push) Successful in 16s
wai-quantum editors / does this change touch it (push) Successful in 1m1s
wai-quantum OpenQASM reader / does this change touch it (push) Successful in 1m0s
wai-quantum other formats / does this change touch it (push) Successful in 1m1s
wai-quantum contract / does this change touch it (push) Successful in 1m3s
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 15s
wai-quantum resource estimation / does this change touch it (push) Successful in 1m1s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 13s
WAI Studio / does this change touch it (push) Successful in 18s
wai-sink-android native sink library / does this change touch it (push) Successful in 44s
wai-quantum verdicts and repairs / does this change touch it (push) Successful in 1m34s
wai-sink-swift native sink package / does this change touch it (push) Successful in 1m32s
wai-quantum pulse and dynamics / the same bits · linux-arm64 (push) Successful in 4m11s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux-arm64, release (push) Successful in 3m59s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 5m57s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 5m24s
wai-quantum extension points / the registry and the example · linux-arm64 (push) Successful in 6m36s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 7m27s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 19s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 14s
wai-quantum wasmQ / does this change touch it (push) Successful in 16s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime) (push) Successful in 1m2s
wai-quantum qudit jobs / the module and the conformance set under wasm32-wasip2 (wasmtime) (push) Successful in 1m15s
wai-audit collector and player integration / collector · linux (push) Successful in 3m41s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs · linux, release (push) Successful in 3m59s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Successful in 16s
wai-quantum error correction and mitigation / codes, decoders, texts and mitigation · linux, release (push) Successful in 3m0s
wai-quantum for Python / python · linux (push) Successful in 4m41s
wai-quantum clippy / clippy, warnings denied, every feature set · linux (push) Successful in 6m12s
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Successful in 3m2s
wai-quantum extension points / the registry under wasm32-wasip2 (wasmtime) (push) Successful in 2m2s
wai-quantum OpenQASM reader / corpus under wasm32-wasip2 (wasmtime) (push) Successful in 1m13s
wai-quantum extension points / the registry and the example · linux (push) Successful in 4m12s
wai-quantum OpenQASM reader / reader and corpus · linux (push) Successful in 2m19s
wai-quantum studio and desktop / studio · browser (push) Successful in 3m45s
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Successful in 11s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 8m8s
wai-quantum other formats / the set under wasm32-wasip2 (wasmtime) (push) Successful in 2m45s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 12m19s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux, release (push) Successful in 2m7s
wai-quantum qudit jobs / the module, the job, the conformance set, the referee and the verb · linux (push) Successful in 11m22s
wai-quantum for JavaScript / javascript · linux (push) Successful in 7m5s
wai-quantum other formats / readers, writers and the set · linux (push) Successful in 6m10s
wai-quantum contract / API compatibility · linux (push) Successful in 4m53s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m18s
wai-quantum editors / editors · linux (push) Successful in 6m14s
wai-quantum verdicts and repairs / the intent set and the verdict under wasm32-wasip2 (wasmtime) (push) Successful in 1m19s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 11m24s
wai-quantum resource estimation / estimation and calibration · linux, release (push) Successful in 6m20s
wai-quantum contract / schemas and the committed tool lists · linux (push) Successful in 9m3s
wai-quantum views in agent hosts / views · the page and its engine (push) Successful in 7m45s
wai-quantum service / service · linux (push) Successful in 15m16s
wai-quantum verdicts and repairs / verdicts, repairs and the intent set · linux (push) Successful in 4m2s
wai-quantum views in agent hosts / views · a scripted host (push) Successful in 9m32s
wai-quantum command line / command line · linux (push) Successful in 29m20s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Failing after 2m13s
wai-quantum wasmQ / the reference modules rebuild to their modules of record · linux (push) Failing after 41s
WAI Studio / Studio in WebKit · linux (push) Successful in 20m52s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 4m54s
wai-quantum wasmQ / interpreter and vectors under wasm32-wasip2 (wasmtime) (push) Successful in 4m25s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · linux (push) Successful in 7m31s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Failing after 36m28s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 10m13s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 11m40s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 13m17s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m2s
wai-quantum command line / command line · macos (push) Successful in 2m41s
wai-quantum for Python / python · macos (push) Successful in 2m59s
wai-quantum qudit jobs / the same bits · macos (push) Successful in 2m4s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 10m36s
wai-quantum editors / editors · macos (push) Successful in 1m39s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 4m44s
wai-quantum pulse and dynamics / the same bits · macos (push) Failing after 10m28s
wai-quantum service / service · macos (push) Successful in 7m32s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 10m17s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 6m48s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · macos (push) Successful in 2m9s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 7m13s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 14m44s
WAI Quantum: wasmQ envelopes and qudit jobs on the job service and both MCP servers
Until now a wasmQ envelope ran only from the command line and a qudit job only from the
engine and the command line; the service and the MCP servers could verify a wasmQ job and
run neither.

- The job service runs both as jobs (src/hybrid.rs): POST /v1/wasmq (the envelope's bytes,
  {"envelope_base64"} or {"example"}; GET /v1/wasmq/examples) and POST /v1/qudit, each
  admitted in the order of what each step costs, opened or read and planned in a reading
  child (a refusal keeps its code, W001-W017 or J090-J092), queued within the client's and
  the service's limits, run in a worker (wasmQ on the native engine), kept in the store
  across a restart (the envelope under the digest its receipt binds) and sealed with the
  service's key; each waits as POST /v1/run does. The job's request is what the receipt
  binds: the contract and the envelope's digest, or the qudit request. The service's
  limits refuse, never truncate, and say so: an envelope past 786,432 bytes or whose run
  asks more than 2^38 of the profile's operations (quantum-wasmq §4.8) is refused J031
  before it is queued, naming `wai-quantum run`; one past a job's memory is refused as any
  job is; a worker past its memory or the job's time is stopped and the job fails saying
  which, nothing sealed. A fault the envelope's own budgets cause is sealed. A wasmQ/2 run's
  energy.run is the worker's figure, read as every job's (the process's CPU energy on
  macOS, the packages' over its window on Linux), or the unmetered form with the reason.
- MCP: run_wasmq (wai_wasmq::tool) and run_qudit (engine::qudit::tools) on both servers.
  The command line's runs a wasmQ/2 envelope in a process of its own and reads its energy
  as `wai-quantum run` does; the service's runs each as a job, output schema
  service-tools.v1.json#/$defs/hybrid_job, and get_quantum_job states such a job's verdict
  from what it holds. docs/local-mcp.json, docs/service-mcp.json, llms.txt, llms-full.txt
  and the skill's tools.md regenerated (WAI_QUANTUM_BLESS=1).
- wai-wasmq: examples (seven conformance envelopes, byte for byte, a repo test holds them
  to the set), asks (a run's work and memory from the bundle alone), tool, and
  run::seal_for (sealing from the request a receipt binds).
- Schemas: wasmq.v1.json; job.v1.json's request and result take a wasmQ run's and a qudit
  job's. Specs: quantum-wasmq §7 and §11.9, quantum-sim §9.10.

Tested on the build hosts (Linux x86_64 Framework; the service's hybrid tests also on macOS
arm64): wai-wasmq all tests and clippy -D warnings; wai-quantum --features full
engine::schema:: engine::qudit:: quantum_qudit:: (36 passed) and the qudit workflow's pin
(26 passed, unchanged); the service's mcp::, hybrid::, discovery::, offload:: unit tests and
tests/hybrid.rs (4: both kinds over HTTP and MCP, each verified and reproduced, the four
limits, the energy) and clippy -D warnings; wai-quantum-cli's whole suite, its MCP stdio
test of both kinds among it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-10 18:55:11 -05:00

555 lines
37 KiB
Rust

//! The conformance vectors (`wai/quantum-conformance/wasmq/`) hold on every engine of this
//! build, and are what this file makes: every committed vector is compared with the bytes
//! made here, and every refusal is made beside the same module or bundle without its one
//! defect, which is accepted. `WASMQ_BLESS=1` writes the files; without it the tests only
//! read them.
use serde_json::{Value, json};
use std::path::{Path, PathBuf};
use wai_quantum::quantum_qec::CssCode;
use wai_wasmq::envelope::{Bundle, Callout, EXACT, EXACT_MAX_QUBITS, MAGIC, Module, Run, from_parts, pack, parts, write_unchecked};
use wai_wasmq::reference;
use wai_wasmq::run::EngineKind;
fn dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../quantum-conformance/wasmq")
}
fn wasm(wat: &str) -> Vec<u8> {
wat::parse_str(wat).unwrap()
}
const PROGRAM: &str = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[8]) -> bit[8];\nqubit[8] q;\nbit[8] b;\nbit[8] r;\nh q;\nb = measure q;\nr = f(b);\n";
const LIST: &str = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[72]) -> bit[72];\nqubit[72] q;\nbit[72] b;\nbit[72] r;\nh q;\nb = measure q;\nr = f(b);\n";
const TWO: &str = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[8]) -> bit[8];\nextern g(bit[8]) -> bit[8];\nqubit[8] q;\nbit[8] b;\nbit[8] r;\nh q;\nb = measure q;\nr = f(b);\nr = g(r);\n";
/// A reset whose outcome is random, then resets of qubits still in |0>, then measurements
/// (§6.1): which of them take a value from the shot's stream.
const RESETS: &str = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[8]) -> bit[8];\nqubit[8] q;\nqubit a;\nbit[8] b;\nbit[8] r;\nh a;\nreset a;\nreset q;\nh q;\nb = measure q;\nr = f(b);\n";
const IDENTITY: &str = r#"(module (func (export "f") (param i64) (result i64) local.get 0))"#;
const BOTH: &str = r#"(module (func (export "f") (param i64) (result i64) local.get 0) (func (export "g") (param i64) (result i64) local.get 0))"#;
/// A list-form identity: the result is the argument's bytes where the host wrote them.
const ECHO: &str = r#"(module (memory (export "memory") 1 1)
(func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) i32.const 1024)
(func (export "f") (param i32 i32) (result i32)
i32.const 2048 local.get 0 i32.store i32.const 2052 local.get 1 i32.store i32.const 2048))"#;
fn one(program: &str, module: Vec<u8>, run: Run) -> Bundle {
Bundle { program: program.into(), inputs: Default::default(), modules: vec![Module { name: "m".into(), bytes: module, priors: vec![] }], callouts: vec![Callout { name: "f".into(), module: 0, export: "f".into() }], run }
}
fn runs() -> Vec<(&'static str, Bundle)> {
let d = std::fs::read(dir().join("modules/qldpc_decoder.wasm")).unwrap();
let p = std::fs::read(dir().join("modules/atom_planner.wasm")).unwrap();
let s3 = CssCode::surface(3);
let s5 = CssCode::surface(5);
let g = CssCode::gross();
let mut job = Run::new(16, 77);
job.state = "job".into();
let mut tight = Run::new(32, 9);
tight.per_call = 400;
let spin = r#"(module (func (export "f") (param i64) (result i64) (local i64)
block loop local.get 0 i64.eqz br_if 1 local.get 0 i64.const 1 i64.sub local.set 0 br 0 end end local.get 1))"#;
let deep = r#"(module (func $r (param i64) (result i64) local.get 0 i64.const 1 i64.add call $r) (func (export "f") (param i64) (result i64) local.get 0 call $r))"#;
let nan = r#"(module (func (export "f") (param i64) (result i64) f64.const nan:0x4000000000abc local.get 0 f64.convert_i64_u f64.add i64.reinterpret_f64 i64.const 255 i64.and))"#;
let grow = r#"(module (memory 1 3) (func (export "f") (param i64) (result i64) local.get 0 i32.wrap_i64 i32.const 7 i32.and memory.grow i64.extend_i32_s i64.const 255 i64.and))"#;
let divide = r#"(module (func (export "f") (param i64) (result i64) i64.const 1 local.get 0 i64.const 1 i64.and i64.div_u))"#;
let wide = r#"(module (func (export "f") (param i64) (result i64) local.get 0 i64.const 256 i64.or))"#;
vec![
("surface3-decode64.wai", reference::qec_bundle(&d, s3.n, &s3.checks, 1, Run::new(32, 1234))),
("surface5-decode64-job.wai", reference::qec_bundle(&d, s5.n, &s5.checks, 2, job)),
("gross-decode.wai", reference::qec_bundle(&d, g.n, &g.checks, 3, Run::new(4, 5))),
("atoms4x4-plan64.wai", reference::atom_bundle(&p, 4, 4, 2, 2, Run::new(32, 99))),
("atoms9x9-plan.wai", reference::atom_bundle(&p, 9, 9, 3, 3, Run::new(6, 99))),
("list-echo.wai", one(LIST, wasm(ECHO), Run::new(8, 3))),
("reset-draws.wai", one(RESETS, wasm(IDENTITY), Run::new(64, 11))),
("nan-canonical.wai", one(PROGRAM, wasm(nan), Run::new(8, 2))),
("grow-past-maximum.wai", one(PROGRAM, wasm(grow), Run::new(16, 5))),
("fault-fuel.wai", one(PROGRAM, wasm(spin), tight)),
("fault-stack.wai", one(PROGRAM, wasm(deep), Run::new(2, 1))),
("fault-trap.wai", one(PROGRAM, wasm(divide), Run::new(64, 4))),
("fault-bad-result.wai", one(PROGRAM, wasm(wide), Run::new(2, 1))),
]
.into_iter()
.chain(more_runs())
.chain(second_runs())
.collect()
}
/// The profile's second version (§11): a T gate and a Toffoli by the `exact` method; a
/// rotation a module computes, applied as its bits' phases; angle arguments, one known on
/// reading and one from measured bits; the tableau under the second version's names; the
/// state vector given a Clifford program, whose draws are the tableau's; and a reset by the
/// state vector, which pins its stream.
fn second_runs() -> Vec<(&'static str, Bundle)> {
let exact = |shots: u64, seed: u64| {
let mut r = Run::second(shots, seed);
r.method = EXACT.into();
r
};
let t_toffoli = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[3]) -> bit[3];\nqubit[3] q;\nbit[3] b;\nbit[3] r;\nh q[0];\nt q[0];\nh q[0];\nx q[1];\nccx q[0], q[1], q[2];\nb = measure q;\nr = f(b);\n";
let feedback = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[1]) -> bit[3];\nqubit[2] q;\nbit[1] m;\nbit[3] th;\nbit[1] out;\nh q[0];\nm[0] = measure q[0];\nth = f(m);\nh q[1];\nif (th[0]) p(pi / 4) q[1];\nif (th[1]) p(pi / 2) q[1];\nif (th[2]) p(pi) q[1];\nh q[1];\nout[0] = measure q[1];\n";
let thrice = wasm(r#"(module (func (export "f") (param i64) (result i64) local.get 0 i64.const 3 i64.mul))"#);
let angles = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(angle[8], uint[8]) -> bit[16];\nextern g(angle[4]) -> bit[4];\nqubit[4] q;\nbit[4] m;\nbit[16] r;\nbit[4] s;\nh q;\nm = measure q;\nr = f(pi / 4, 3);\ns = g(m);\n";
let mut angle = one(angles, wasm(r#"(module (func (export "f") (param i64 i64) (result i64) local.get 0 i64.const 8 i64.shl local.get 1 i64.or) (func (export "g") (param i64) (result i64) local.get 0))"#), Run::second(16, 3));
angle.callouts.push(Callout { name: "g".into(), module: 0, export: "g".into() });
// A reset whose outcome is random, at an angle the state vector reads at three sixteenths
// of a turn from the stream, then rotations of every kind the method takes.
let rotations = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[4]) -> bit[4];\nqubit[4] q;\nbit[4] b;\nbit[4] r;\nrx(3 * pi / 8) q[0];\nreset q[0];\nry(pi / 8) q[0];\nrz(pi / 16) q[0];\nh q[1];\ncp(pi / 2) q[1], q[2];\ncrz(pi / 4) q[1], q[3];\nrzz(pi / 8) q[2], q[3];\nch q[0], q[3];\ncswap q[1], q[2], q[3];\nccz q[0], q[1], q[2];\ntdg q[2];\nsx q[3];\nb = measure q;\nr = f(b);\n";
vec![
("v2-t-toffoli.wai", one(t_toffoli, wasm(IDENTITY), Run::second(64, 5))),
("v2-feedback-rotation.wai", one(feedback, thrice, Run::second(64, 9))),
("v2-angle-arguments.wai", angle),
("v2-stabilizer.wai", one(PROGRAM, wasm(IDENTITY), Run::second(8, 2))),
("v2-exact-of-a-clifford-program.wai", one(PROGRAM, wasm(IDENTITY), exact(8, 2))),
("v2-rotations-and-a-reset.wai", one(rotations, wasm(IDENTITY), Run::second(64, 13))),
]
}
/// A module of one export `f` of `(i64) -> i64`, its body `body`, with `extra` beside it.
fn scalar(extra: &str, body: &str) -> Vec<u8> {
wasm(&format!(r#"(module {extra} (func (export "f") (param i64) (result i64) {body}))"#))
}
/// The list-form identity of `LIST` with its result changed: `ret` the address it returns,
/// and `after` what it does to the result's bytes before it returns.
fn echo_with(ret: u32, after: &str) -> Vec<u8> {
wasm(&format!(
r#"(module (memory (export "memory") 1 1)
(func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) i32.const 1024)
(func (export "f") (param i32 i32) (result i32)
i32.const 2048 local.get 0 i32.store i32.const 2052 local.get 1 i32.store {after} i32.const {ret}))"#
))
}
/// Runs that show what the rest of the text says a run does (§5, §6): every reason a fault
/// has, every phase and every budget it stops in, the calls a host makes into a module, the
/// lowering of a signed argument, the order modules are made in, and a program that
/// measures nothing.
fn more_runs() -> Vec<(&'static str, Bundle)> {
let mut out = Vec::new();
// Each trap, as a fault of its own reason.
let ty = "(type $t (func (param i64) (result i64)))";
for (name, extra, body) in [
("fault-unreachable.wai", "", "unreachable"),
("fault-memory-out-of-bounds.wai", "(memory 1 1)", "i32.const 70000 i64.load"),
("fault-table-out-of-bounds.wai", &*format!("{ty} (table 1 1 funcref)"), "local.get 0 i32.const 5 call_indirect (type $t)"),
("fault-indirect-call-null.wai", &*format!("{ty} (table 1 1 funcref)"), "local.get 0 i32.const 0 call_indirect (type $t)"),
("fault-indirect-call-type.wai", &*format!("{ty} (table 1 1 funcref) (func $g) (elem (i32.const 0) func $g)"), "local.get 0 i32.const 0 call_indirect (type $t)"),
("fault-integer-overflow.wai", "", "i64.const 0x8000000000000000 i64.const -1 i64.div_s"),
("fault-invalid-conversion.wai", "", "f64.const nan i64.trunc_f64_s"),
] {
out.push((name, one(PROGRAM, scalar(extra, body), Run::new(4, 1))));
}
// A fault in each phase of making an instance (§5.3).
out.push(("fault-in-seed.wai", one(PROGRAM, scalar(r#"(func (export "wasmq-seed") (param i64) unreachable)"#, "local.get 0"), Run::new(4, 1))));
out.push(("fault-in-init.wai", one(PROGRAM, scalar(r#"(func (export "init") unreachable)"#, "local.get 0"), Run::new(4, 1))));
let mut prior = one(
PROGRAM,
scalar(r#"(memory (export "memory") 1 1) (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) i32.const 1024) (func (export "wasmq-prior") (param i32 i32 i32) unreachable)"#, "local.get 0"),
Run::new(4, 1),
);
prior.modules[0].priors.push(("weights".into(), vec![1, 2, 3, 4, 5]));
out.push(("fault-in-prior.wai", prior));
// Each budget a fuel fault can be of (§4.2): an instance's, and what is left of the run's.
let mut instance = Run::new(4, 1);
instance.per_init = 300;
out.push(("fault-fuel-instance.wai", one(PROGRAM, scalar(r#"(func (export "init") loop br 0 end)"#, "local.get 0"), instance)));
let mut run = Run::new(8, 1);
run.per_job = 50;
let sum = "local.get 0 ".to_string() + &"local.get 0 i64.add ".repeat(10) + "drop local.get 0";
out.push(("fault-fuel-run.wai", one(PROGRAM, scalar("", &sum), run)));
// The calls a host makes into a module around a list (§5.2): `cabi_post_f` after the
// result is read, which uses fuel of the call's.
let post = wasm(
r#"(module (memory (export "memory") 1 1)
(func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) i32.const 1024)
(func (export "f") (param i32 i32) (result i32) i32.const 2048 local.get 0 i32.store i32.const 2052 local.get 1 i32.store i32.const 2048)
(func (export "cabi_post_f") (param i32) (local i32) loop local.get 1 i32.const 1 i32.add local.tee 1 i32.const 5 i32.lt_u br_if 0 end))"#,
);
out.push(("list-post.wai", one(LIST, post, Run::new(8, 3))));
// Each way a list result is not one (§5.2).
for (name, m) in [
// The pointer and length written at 2050, so that only the address's alignment is wrong.
("fault-list-misaligned.wai", echo_with(2050, "i32.const 2050 local.get 0 i32.store i32.const 2054 local.get 1 i32.store")),
("fault-list-outside.wai", echo_with(70000, "")),
("fault-list-length.wai", echo_with(2048, "i32.const 2052 i32.const 5 i32.store")),
] {
out.push((name, one(LIST, m, Run::new(4, 3))));
}
// Seventy bits take nine bytes, the last two bits of the last byte zero.
let seventy = LIST.replace("72", "70");
out.push(("fault-list-past-its-bits.wai", one(&seventy, echo_with(2048, "i32.const 1032 i32.const 255 i32.store8"), Run::new(4, 3))));
// A signed argument, sign-extended (§5.2): `f(-3, 200)` gives back its two arguments.
let signed = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(int[8], uint[8]) -> bit[64];\nqubit[1] q;\nbit[64] r;\nr = f(-3, 200);\n";
out.push(("signed-argument.wai", one(signed, wasm(r#"(module (func (export "f") (param i64 i64) (result i64) local.get 0 i64.const 8 i64.shl local.get 1 i64.or))"#), Run::new(2, 1))));
// A program that measures nothing: its outcome is its bits, which its call writes, and
// no qubit is read for it (§6.1).
let unmeasured = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[1]) -> bit[1];\nqubit[3] q;\nbit[1] d;\nd = f(d);\nh q;\n";
out.push(("measures-nothing.wai", one(unmeasured, wasm(IDENTITY), Run::new(16, 7))));
// Bits nothing writes are in the outcome all the same, as 0 (§6.1): `a`'s three, then
// the call's two, so every outcome is `11000`.
let unwritten = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(uint[8]) -> bit[2];\nqubit[1] q;\nbit[3] a;\nbit[2] r;\nr = f(3);\n";
out.push(("bits-nothing-writes.wai", one(unwritten, wasm(IDENTITY), Run::new(2, 7))));
// A block's own bit is no bit of the outcome (§6.1, Q322): the loop's `t` is measured and
// read, and the outcome is `a` and `b` alone, `11`.
let block = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[1]) -> bit[1];\nqubit[1] q;\nbit[1] a;\nx q[0];\nfor uint i in [0:0] {\n bit t;\n t = measure q[0];\n if (t) { a = measure q[0]; }\n}\nbit[1] b;\nb = f(a);\n";
out.push(("block-bit-not-in-outcome.wai", one(block, wasm(IDENTITY), Run::new(2, 7))));
// Two modules, each failing in its init: they are made in the contract's order (§5.3).
let fails = |m: &str| wasm(&format!(r#"(module (func (export "init") unreachable) (func (export "{m}") (param i64) (result i64) local.get 0))"#));
let mut two = one(TWO, fails("f"), Run::new(4, 1));
two.modules[0].name = "first".into();
two.modules.push(Module { name: "second".into(), bytes: fails("g"), priors: vec![] });
two.callouts = vec![Callout { name: "f".into(), module: 0, export: "f".into() }, Callout { name: "g".into(), module: 1, export: "g".into() }];
out.push(("two-modules-in-order.wai", two));
// A program that declares no qubit and names physical ones: its qubits are one more than
// the highest index it names (§2.2), here 3; and its bits are numbered in the order it
// declares them (§6.1), so the measured `b[1]` is bit 2 and every outcome is `100`.
let physical = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(bit[1]) -> bit[1];\nbit[1] a;\nbit[2] b;\nx $2;\nb[1] = measure $2;\na = f(a);\n";
out.push(("physical-qubits.wai", one(physical, wasm(IDENTITY), Run::new(4, 7))));
out
}
fn leb(mut v: u64) -> Vec<u8> {
let mut out = Vec::new();
loop {
let b = (v & 0x7f) as u8;
v >>= 7;
if v == 0 {
out.push(b);
return out;
}
out.push(b | 0x80);
}
}
fn raw(sections: &[(u8, Vec<u8>)]) -> Vec<u8> {
let mut m = b"\0asm\x01\0\0\0".to_vec();
for (id, body) in sections {
m.push(*id);
m.extend(leb(body.len() as u64));
m.extend_from_slice(body);
}
m
}
/// A module a runner refuses: its name, its code, the module, the same module without
/// the defect, and its text when it has one.
struct Refused {
name: &'static str,
code: &'static str,
module: Vec<u8>,
repaired: Vec<u8>,
wat: Option<String>,
}
fn module_refusals() -> Vec<Refused> {
let f = r#"(func (export "f") (param i64) (result i64) local.get 0)"#;
let text = |name: &'static str, code: &'static str, defect: String, repaired: String| Refused { name, code, module: wasm(&defect), repaired: wasm(&repaired), wat: Some(defect) };
let with = |name: &'static str, code: &'static str, defect: &str, repaired: &str| text(name, code, format!("(module {defect} {f})"), format!("(module {repaired} {f})"));
let body = |name: &'static str, code: &'static str, defect: &str, repaired: &str| {
text(name, code, format!(r#"(module (memory 1 1) (table 1 funcref) (func (export "f") (param i64) (result i64) {defect}))"#), format!(r#"(module (memory 1 1) (table 1 funcref) (func (export "f") (param i64) (result i64) {repaired}))"#))
};
let exports = |n: u32| format!("(module (func) {})", (0..n).map(|k| format!("(export \"e{k}\" (func 0)) ")).collect::<String>());
let locals = |n: usize| format!("(module (func (local {})))", "i64 ".repeat(n));
// One type `() -> ()`, one function of it, and a body: `i32.const 0`, `drop`, and an `end` or none.
let unfinished = |end: bool| {
let mut code = vec![0x01, if end { 0x05 } else { 0x04 }, 0x00, 0x41, 0x00, 0x1a];
if end {
code.push(0x0b);
}
raw(&[(1, vec![0x01, 0x60, 0x00, 0x00]), (3, vec![0x01, 0x00]), (10, code)])
};
// One type, and one function of type `index`.
let typed = |index: u8| raw(&[(1, vec![0x01, 0x60, 0x00, 0x00]), (3, vec![0x01, index]), (10, vec![0x01, 0x02, 0x00, 0x0b])]);
vec![
Refused { name: "body-without-end", code: "W001", module: unfinished(false), repaired: unfinished(true), wat: None },
Refused { name: "function-of-no-type", code: "W001", module: typed(5), repaired: typed(0), wat: None },
with("import-clock", "W002", r#"(import "wasi:clocks/monotonic-clock" "now" (func (result i64)))"#, ""),
with("import-random", "W002", r#"(import "wasi_snapshot_preview1" "random_get" (func (param i32 i32) (result i32)))"#, ""),
with("memory-unbounded", "W003", "(memory 1)", "(memory 1 1)"),
with("memory-too-large", "W003", "(memory 1 4097)", "(memory 1 4096)"),
with("start-function", "W004", "(func $s) (start $s)", "(func $s)"),
with("shared-memory", "W005", "(memory 1 1 shared)", "(memory 1 1)"),
body("atomic", "W005", "i32.const 0 local.get 0 i64.atomic.rmw.add", "i32.const 0 i64.load local.get 0 i64.add"),
body("simd", "W006", "local.get 0 i64x2.splat i64x2.extract_lane 0", "local.get 0"),
body("relaxed-simd", "W006", "local.get 0 i64x2.splat local.get 0 i64x2.splat local.get 0 i64x2.splat f32x4.relaxed_madd i64x2.extract_lane 0", "local.get 0"),
with("tail-call", "W007", "(func $g (param i64) (result i64) local.get 0) (func (param i64) (result i64) local.get 0 return_call $g)", "(func $g (param i64) (result i64) local.get 0) (func (param i64) (result i64) local.get 0 call $g)"),
body("ref-null", "W007", "ref.null func ref.is_null i64.extend_i32_u", "i32.const 1 i64.extend_i32_u"),
with("reference-type", "W007", "(func (param externref))", "(func (param i64))"),
body("table-grow", "W008", "unreachable table.grow 0 i64.extend_i32_u", "unreachable i64.extend_i32_u"),
body("table-size", "W008", "table.size 0 i64.extend_i32_u", "memory.size i64.extend_i32_u"),
text("frame-too-large", "W009", locals(4097), locals(4096)),
text("too-many-exports", "W010", exports(1025), exports(1024)),
with("data-past-memory", "W011", r#"(memory 1 1) (data (i32.const 65530) "0123456789")"#, r#"(memory 1 1) (data (i32.const 65526) "0123456789")"#),
with("reserved-export", "W012", r#"(global (export "__wasmq_fuel") (mut i64) (i64.const 0))"#, r#"(global (export "fuel") (mut i64) (i64.const 0))"#),
with("seed-of-another-type", "W012", r#"(func (export "wasmq-seed") (param i32))"#, r#"(func (export "wasmq-seed") (param i64))"#),
]
}
/// A bundle that is well formed and breaks a rule: its name, its code, the bundle, and
/// the same bundle without the defect.
fn bundle_refusals() -> Vec<(&'static str, &'static str, Bundle, Bundle)> {
let good = || one(PROGRAM, wasm(IDENTITY), Run::new(4, 1));
let two = || {
let mut b = one(TWO, wasm(BOTH), Run::new(4, 1));
b.callouts.push(Callout { name: "g".into(), module: 0, export: "g".into() });
b
};
let mut out = Vec::new();
let mut add = |name: &'static str, code: &'static str, defect: Bundle, repaired: Bundle| out.push((name, code, defect, repaired));
let mut swapped = two();
swapped.callouts.reverse();
add("callouts-out-of-order", "W015", swapped, two());
let mut twice = good();
twice.callouts.push(Callout { name: "f".into(), module: 0, export: "f".into() });
add("two-callouts-for-one-extern", "W015", twice, good());
add("callout-of-another-type", "W015", one(PROGRAM, wasm(r#"(module (func (export "f") (param i32) (result i32) local.get 0))"#), Run::new(4, 1)), good());
add("memory-not-exported", "W015", one(LIST, wasm(&ECHO.replace("(memory (export \"memory\") 1 1)", "(memory 1 1)")), Run::new(4, 1)), one(LIST, wasm(ECHO), Run::new(4, 1)));
add("gate-outside-the-clifford-gates", "W016", one(&PROGRAM.replace("h q;", "h q;\nt q[0];"), wasm(IDENTITY), Run::new(4, 1)), good());
add("program-calls-nothing", "W016", one(&PROGRAM.replace("r = f(b);", "r = measure q;"), wasm(IDENTITY), Run::new(4, 1)), good());
// A measurement that names no bit, in a program that calls externs (§6.1, Q324): its
// outcome is the bits it declares, and this one declares none for it.
let bare = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(uint[8]);\nqubit[4] q;\nf(1);\nx q[3];\nmeasure q[3];\n";
let named = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(uint[8]);\nqubit[4] q;\nbit[4] c;\nf(1);\nx q[3];\nc[3] = measure q[3];\n";
let sink = || wasm(r#"(module (func (export "f") (param i64)))"#);
add("program-measure-with-no-bit", "W016", one(bare, sink(), Run::new(2, 7)), one(named, sink(), Run::new(2, 7)));
add("no-shots", "W017", one(PROGRAM, wasm(IDENTITY), Run::new(0, 1)), good());
let mut state = good();
state.run.state = "forever".into();
add("instances-of-no-kind", "W017", state, good());
let mut seed = good();
seed.run.seed = 1 << 53;
add("seed-a-double-cannot-hold", "W017", seed, good());
// What a host must hold and do that fuel does not count (§4.7, §4.8).
let of_memory = |pages: u32| {
let m = format!(r#"(module (memory (export "memory") {pages} {pages}) (func (export "f") (param i64) (result i64) local.get 0) (func (export "g") (param i64) (result i64) local.get 0))"#);
let mut b = one(TWO, wasm(&m), Run::new(4, 1));
b.modules.push(Module { name: "n".into(), bytes: wasm(&m), priors: vec![] });
b.callouts = vec![Callout { name: "f".into(), module: 0, export: "f".into() }, Callout { name: "g".into(), module: 1, export: "g".into() }];
b
};
add("memory-past-a-run-s-among-its-modules", "W003", of_memory(2049), of_memory(2048));
// The most bits a program holds, a shot more than results may hold.
let wide = PROGRAM.replace("bit[8] r;", &format!("bit[8] r;\nbit[{}] pad;", (1 << 20) - 16));
add("results-past-what-a-host-holds", "W017", one(&wide, wasm(IDENTITY), Run::new((1 << 8) + 1, 1)), one(&wide, wasm(IDENTITY), Run::new(1 << 8, 1)));
let measures = PROGRAM.replace("qubit[8] q;", "qubit[32768] q;").replace("h q;\nb = measure q;", "b[0] = measure q[0];");
// Eight gates, eight measurements and a call, and resets up to the steps a program takes.
let resets = |n: u64| PROGRAM.replace("r = f(b);", &format!("r = f(b);\nfor uint i in [0:{}] {{ reset q[0]; }}", n - 1));
add("program-past-its-steps", "W016", one(&resets((1 << 21) - 16), wasm(IDENTITY), Run::new(1, 1)), one(&resets((1 << 21) - 17), wasm(IDENTITY), Run::new(1, 1)));
add("work-past-what-a-run-may-ask", "W017", one(&measures, wasm(IDENTITY), Run::new(1 << 20, 1)), one(&measures, wasm(IDENTITY), Run::new(4, 1)));
// The second version (§11): what the `exact` method does not take, and angle arguments
// the first version does not take or that are not whole numbers of their turns.
let exact = |p: &str, shots: u64| {
let mut r = Run::second(shots, 1);
r.method = EXACT.into();
one(p, wasm(IDENTITY), r)
};
let with = |gate: &str| PROGRAM.replace("h q;", &format!("h q;\n{gate}"));
add("v2-angle-not-dyadic", "W016", exact(&with("rz(0.1) q[0];"), 4), exact(&with("rz(pi / 8) q[0];"), 4));
add("v2-angle-off-the-double-s-rounding", "W016", exact(&with("rz(pi / 4 + 2e-14) q[0];"), 4), exact(&with("rz(pi / 4) q[0];"), 4));
add("v2-gate-outside-the-exact-gates", "W016", exact(&with("u(pi / 2, 0, pi) q[0];"), 4), exact(&with("ry(pi / 2) q[0];"), 4));
add("v2-t-gate-by-the-stabilizer-method", "W016", one(&with("t q[0];"), wasm(IDENTITY), Run { method: "stabilizer".into(), ..Run::second(4, 1) }), exact(&with("t q[0];"), 4));
let wide = |n: u32| PROGRAM.replace("qubit[8] q;", &format!("qubit[{n}] q;")).replace("h q;", "t q[0];").replace("b = measure q;", "b = measure q[0:7];");
add("v2-past-the-exact-method-s-qubits", "W016", exact(&wide(EXACT_MAX_QUBITS + 1), 4), exact(&wide(EXACT_MAX_QUBITS), 4));
// 2^20 shots of a 20-qubit state: 2^41 operations for its fresh states alone, and
// thirty-seven times that with its gate and its eight measurements, past 2^42 (§11.7).
add("v2-state-vector-work-past-what-a-run-may-ask", "W017", exact(&wide(20), 1 << 20), exact(&wide(20), 1 << 10));
let angled = |arg: &str| format!("OPENQASM 3.0;\ninclude \"stdgates.inc\";\nextern f(angle[2]) -> bit[2];\nqubit[1] q;\nbit[2] r;\nr = f({arg});\n");
add("v2-angle-argument-off-its-turns", "W016", one(&angled("pi / 4"), wasm(IDENTITY), Run::second(4, 1)), one(&angled("pi / 2"), wasm(IDENTITY), Run::second(4, 1)));
add("v1-angle-argument", "W016", one(&angled("pi / 2"), wasm(IDENTITY), Run::new(4, 1)), one(&angled("pi / 2"), wasm(IDENTITY), Run::second(4, 1)));
out
}
/// Envelopes one edit away from one that opens: each name, its code, and its bytes.
fn edited(base: &[u8]) -> Vec<(&'static str, &'static str, Vec<u8>)> {
let (manifest, contract, frames) = parts(base).unwrap();
let text = String::from_utf8(contract.clone()).unwrap();
let with = |manifest: &[u8], magic: &[u8; 4], contract: &[u8], frames: &[u8]| from_parts(manifest, magic, contract, frames).unwrap();
let flip = |find: &[u8], with: &[u8]| {
let at = base.windows(find.len()).position(|w| w == find).unwrap();
let mut e = base.to_vec();
e[at..at + with.len()].copy_from_slice(with);
e
};
let prior_at = base.windows(15).position(|w| w == b"wai:qec-checks\x01").unwrap();
let mut wrong_prior = base.to_vec();
wrong_prior[prior_at + 15 + 8 + 4] ^= 1;
let module_at = base.windows(8).position(|w| w == b"\0asm\x01\0\0\0").unwrap();
let mut wrong_module = base.to_vec();
wrong_module[module_at + 200] ^= 0x40;
let mut trailing = base.to_vec();
trailing.push(0);
let mut more = frames.clone();
more.push(0);
let shots = text.replacen("\"shots\":32", "\"shots\":33", 1);
let extra = text.replacen(",\"modules\":", ",\"extra\":0,\"modules\":", 1);
assert!(shots != text && extra != text);
let m = String::from_utf8(manifest.clone()).unwrap();
vec![
("prior-hash-mismatch", "W014", wrong_prior),
("module-hash-mismatch", "W014", wrong_module),
("program-hash-mismatch", "W014", flip(b"h c0;", b"x c0;")),
("contract-run-changed", "W013", with(&manifest, MAGIC, shots.as_bytes(), &frames)),
("contract-extra-member", "W013", with(&manifest, MAGIC, extra.as_bytes(), &frames)),
("contract-not-canonical", "W013", with(&manifest, MAGIC, text.replacen('{', "{ ", 1).as_bytes(), &frames)),
("payload-of-another-kind", "W013", with(&manifest, b"WQM2", &contract, &frames)),
("byte-after-the-frames", "W013", with(&manifest, MAGIC, &contract, &more)),
("manifest-changed", "W013", with(m.replace("\"shots\":32", "\"shots\":33").as_bytes(), MAGIC, &contract, &frames)),
("other-capability", "W013", with(m.replace("wai.quantum.wasmq", "wai.quantum.wasmx").as_bytes(), MAGIC, &contract, &frames)),
("trailing-byte", "W013", trailing),
("truncated", "W013", base[..base.len() - 1].to_vec()),
]
}
/// Every vector file this test makes, by its path under the vectors' directory, and the
/// index that lists them.
fn made() -> (Vec<(String, Vec<u8>)>, Value) {
let key = wai_wasmq::vectors::key();
let mut files = Vec::new();
let mut index_runs = Vec::new();
let mut base = Vec::new();
for (name, b) in runs() {
let env = pack(&b).unwrap_or_else(|e| panic!("{name}: {e}"));
let o = wai_wasmq::open(&env).unwrap();
let (body, _) = wai_wasmq::run(&o, EngineKind::Interpreter, &key, false).unwrap();
index_runs.push(json!({ "file": format!("envelopes/{name}"), "envelope_blake3": wai_wasmq::envelope::blake3_hex(&env), "expect": wai_wasmq::vectors::pins(&body) }));
if name == "surface3-decode64.wai" {
files.push(("envelopes/surface3-decode64.job.json".to_string(), (serde_json::to_string_pretty(&body).unwrap() + "\n").into_bytes()));
files.push(("envelopes/surface3-decode64.qasm".to_string(), b.program.clone().into_bytes()));
files.push(("envelopes/surface3-decode64.checks.bin".to_string(), b.modules[0].priors[0].1.clone()));
base = env.clone();
}
files.push((format!("envelopes/{name}"), env));
}
let mut index_refuse = Vec::new();
for r in module_refusals() {
if let Some(wat) = &r.wat {
files.push((format!("refuse/{}.wat", r.name), format!("{wat}\n").into_bytes()));
}
files.push((format!("refuse/{}.wasm", r.name), r.module));
index_refuse.push(json!({ "file": format!("refuse/{}.wasm", r.name), "code": r.code }));
}
for (name, code, defect, _) in bundle_refusals() {
let qubits = wai_quantum::qasm::read_callouts(&defect.program, &defect.inputs).map(|h| h.reading.program.n_qubits).unwrap_or(8);
files.push((format!("refuse/{name}.wai"), write_unchecked(&defect, method_of(&defect), qubits).unwrap()));
index_refuse.push(json!({ "file": format!("refuse/{name}.wai"), "code": code }));
}
for (name, code, bytes) in edited(&base) {
files.push((format!("refuse/{name}.wai"), bytes));
index_refuse.push(json!({ "file": format!("refuse/{name}.wai"), "code": code }));
}
let index = json!({
"profiles": [wai_wasmq::profile::PROFILE, wai_wasmq::envelope::PROFILE2],
"note": "every run vector gives exactly `expect` on every engine and every host; every refusal is refused with its code (extensions/quantum-wasmq.md §9)",
"runs": index_runs,
"refuse": index_refuse,
});
(files, index)
}
/// The method a refused bundle's envelope is written with: the one its run asks, or the
/// first version's.
fn method_of(b: &Bundle) -> &str {
if b.run.method.is_empty() { wai_wasmq::envelope::METHOD } else { &b.run.method }
}
fn kinds() -> Vec<EngineKind> {
wai_wasmq::engine::available().iter().map(|s| EngineKind::parse(s).unwrap()).collect()
}
#[test]
fn the_vectors_are_the_ones_made_here_and_hold_on_every_engine_of_this_build() {
let d = dir();
let (files, index) = made();
let index_text = serde_json::to_string_pretty(&index).unwrap() + "\n";
if std::env::var("WASMQ_BLESS").is_ok() {
for sub in ["envelopes", "refuse"] {
let _ = std::fs::remove_dir_all(d.join(sub));
std::fs::create_dir_all(d.join(sub)).unwrap();
}
for (path, bytes) in &files {
std::fs::write(d.join(path), bytes).unwrap();
}
std::fs::write(d.join("vectors.json"), &index_text).unwrap();
}
// The committed files are these, and there are no others.
for (path, bytes) in &files {
assert!(std::fs::read(d.join(path)).is_ok_and(|have| &have == bytes), "{path} is not the file this test makes: run it with WASMQ_BLESS=1");
}
assert_eq!(std::fs::read_to_string(d.join("vectors.json")).unwrap(), index_text, "vectors.json is not the index this test makes");
for sub in ["envelopes", "refuse"] {
for entry in std::fs::read_dir(d.join(sub)).unwrap() {
let name = format!("{sub}/{}", entry.unwrap().file_name().to_string_lossy());
assert!(files.iter().any(|(p, _)| *p == name), "{name} is a file this test does not make");
}
}
let (lines, problems) = wai_wasmq::vectors::verify(&d, &kinds()).unwrap();
assert!(problems.is_empty(), "{problems:#?}");
assert_eq!(lines.len(), index["runs"].as_array().unwrap().len() + index["refuse"].as_array().unwrap().len());
// Every code of §3.3 has a vector.
let codes: std::collections::BTreeSet<&str> = index["refuse"].as_array().unwrap().iter().filter_map(|r| r["code"].as_str()).collect();
let all: std::collections::BTreeSet<&str> = wai_wasmq::profile::CODES.iter().map(|c| c.0).collect();
assert_eq!(codes, all, "the codes with a refusal vector");
// And every reason a fault has, every phase and every budget it stops in, is shown.
let shown = |member: &str| -> std::collections::BTreeSet<String> { index["runs"].as_array().unwrap().iter().filter_map(|r| r["expect"]["fault"][member].as_str().map(str::to_string)).collect() };
let want = |v: &[&str]| -> std::collections::BTreeSet<String> { v.iter().map(|s| s.to_string()).collect() };
assert_eq!(shown("reason"), want(&wai_wasmq::run::REASONS), "the reasons a run vector ends in");
assert_eq!(shown("phase"), want(&["seed", "prior", "init", "call"]), "the phases a run vector stops in");
assert_eq!(shown("budget"), want(&["call", "instance", "run"]), "the budgets a fuel fault of a run vector is of");
}
#[test]
fn each_refusal_is_refused_for_its_one_defect() {
// A module vector: the module has its code, and the same module without the defect passes.
for r in module_refusals() {
assert_eq!(wai_wasmq::profile::check(&r.module).err().map(|e| e.code), Some(r.code), "{}", r.name);
if let Err(e) = wai_wasmq::profile::check(&r.repaired) {
panic!("{}: without its defect the module is still refused: {e}", r.name);
}
}
// A bundle vector: the bundle has its code, and the same bundle without the defect packs.
for (name, code, defect, repaired) in bundle_refusals() {
let qubits = wai_quantum::qasm::read_callouts(&defect.program, &defect.inputs).map(|h| h.reading.program.n_qubits).unwrap_or(8);
let env = write_unchecked(&defect, method_of(&defect), qubits).unwrap();
assert_eq!(wai_wasmq::open(&env).err().map(|e| e.code), Some(code), "{name}");
if let Err(e) = pack(&repaired) {
panic!("{name}: without its defect the bundle is still refused: {e}");
}
}
// An edited envelope: one edit away from an envelope that opens.
let base = pack(&runs().remove(0).1).unwrap();
assert!(wai_wasmq::open(&base).is_ok());
for (name, code, bytes) in edited(&base) {
assert_eq!(wai_wasmq::open(&bytes).err().map(|e| e.code), Some(code), "{name}");
}
}
/// What a receipt shows of its envelope and its transcript is what the writer wrote: each run
/// vector's envelope is as long as its job says (rule 31), and where no call returned, its
/// transcript is the one rule 35 reads.
#[test]
fn a_job_shows_its_envelope_s_length_and_a_transcript_of_no_call() {
let key = wai_wasmq::vectors::key();
let mut bare = 0;
for (name, b) in runs() {
let env = pack(&b).unwrap_or_else(|e| panic!("{name}: {e}"));
let (body, _) = wai_wasmq::run(&wai_wasmq::open(&env).unwrap(), EngineKind::Interpreter, &key, false).unwrap();
let (c, r) = (&body["request"]["wasmq"], &body["result"]);
assert_eq!(wai_quantum::engine::wasmq::envelope_bytes(Some(c), r).0, env.len() as u128, "{name}");
if let Some(t) = wai_quantum::engine::wasmq::bare_transcript(r) {
assert_eq!(r["transcript_blake3"].as_str(), Some(t.as_str()), "{name}");
bare += 1;
}
}
assert!(bare >= 4, "the run vectors with no call that returned: {bare}");
}
/// The envelopes the crate carries to start from (`wai_wasmq::examples`) are the conformance
/// set's own, byte for byte: what a surface runs from them is what `vectors.json` pins.
#[test]
fn the_crate_s_examples_are_the_conformance_set_s_envelopes() {
for e in &wai_wasmq::examples::ALL {
let committed = std::fs::read(dir().join("envelopes").join(format!("{}.wai", e.name))).unwrap_or_else(|err| panic!("{}: {err}", e.name));
assert!(committed == e.bytes, "wai-wasmq/envelopes/{}.wai is not quantum-conformance/wasmq/envelopes/{}.wai: copy it again", e.name, e.name);
}
}