open-standards/wai/wai-quantum/ci/check_schemas.py
Transaction Science 56b47afae1 wai-quantum engine::registry: methods, passes, noise channels and formats behind traits, the built-ins registered through them
Method, Pass, Channel and FrontEnd, and one registry the planner, the run,
the compile, the conversions and the verdict go through. Every built-in
registers through the same trait a host's own implements: the twelve
methods and the pulse simulator, the eight passes, the five channels and
the three formats. Registry::with_builtins() and register(...) are
explicit and stay in the process.

The engine checks what a registered component gives: a method's class and
the members the engine writes, a pass's output against its input on the
whole circuit by the ladder or a distance bound, a channel's Kraus
operators completely positive and trace preserving at each job's values,
a format's program reading. A result a registered component took part in
carries `components`, each identity (name, version, descriptor digest)
marked registered and certified false, sealed by its receipt; a result of
built-ins alone gives the bytes it gave, the eight pinned job digests
holding through any registry. Refusal codes J060 to J065. The example
examples/extension_points.rs, docs/extension-points.md, and the CI leg
wai-quantum-registry.yml.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 23:30:48 -04:00

243 lines
14 KiB
Python

"""The committed schemas, read by a second implementation of JSON Schema.
python -I wai/wai-quantum/ci/check_schemas.py WAI_DIR [WAI_QUANTUM_BINARY]
The engine's tests hold what the code writes to its schemas with the engine's
own checker, which reads the subset of JSON Schema the files use. This reads
them with a full implementation of the 2020-12 dialect (the `jsonschema`
package, pinned in wai-quantum-py/tests/requirements.lock), sharing no code
with the engine:
- every schema file (each `*.json` under the packages' `schemas/`) is a valid
2020-12 schema, named by its `$id`, and every `$ref` in it resolves among
the files;
- every tool of both MCP servers, in the committed tool lists, has an
`inputSchema` and an `outputSchema` that are valid schemas of objects, and
each `outputSchema` stands alone (no `$ref` out of it);
- the job bodies sealed before results named their engine and schema follow
the job schema;
- with the command line given: a run's job, a set's, the versions it reports, and the
answer of each of its MCP server's tools that needs no file (the verdict,
the repair, the compile, the estimate and its check, the debugger, the
device targets, error correction, mitigation and pulse runs, gradients,
optimisation and the algorithm builders among them), called over
standard input and output, each follow their schema.
Exit status 0 when everything holds; 1 with the first failure otherwise.
"""
from __future__ import annotations
import json
import subprocess
import sys
from pathlib import Path
from jsonschema import Draft202012Validator
from referencing import Registry, Resource
# Every schema file is read, so a new one is checked without being listed here;
# these must be among them.
PACKAGES = ["wai-quantum", "wai-quantum-cli", "wai-quantum-service", "wai-quantum-qpu"]
REQUIRED = [
"wai-quantum/schemas/job-request.v1.json",
"wai-quantum/schemas/job-result.v1.json",
"wai-quantum/schemas/job.v1.json",
"wai-quantum/schemas/receipt.v2.json",
"wai-quantum/schemas/plan.v1.json",
"wai-quantum/schemas/tools.v1.json",
"wai-quantum/schemas/versions.v1.json",
"wai-quantum/schemas/compile-result.v1.json",
"wai-quantum/schemas/verdict.v1.json",
"wai-quantum/schemas/target.v1.json",
"wai-quantum/schemas/estimate.v1.json",
"wai-quantum/schemas/set.v1.json",
"wai-quantum/schemas/provenance.v1.json",
"wai-quantum-cli/schemas/lease.v1.json",
"wai-quantum-cli/schemas/eval-report.v1.json",
"wai-quantum-cli/schemas/eval-answers.v1.json",
"wai-quantum-cli/schemas/token-cost.v1.json",
"wai-quantum/schemas/qec.v1.json",
"wai-quantum/schemas/distance.v1.json",
"wai-quantum/schemas/mitigation.v1.json",
"wai-quantum/schemas/answer.v1.json",
"wai-quantum/schemas/telemetry.v1.json",
"wai-quantum/schemas/views-bundle.v1.json",
"wai-quantum/schemas/algorithms.v1.json",
"wai-quantum-service/schemas/receipt-keys.v1.json",
"wai-quantum-cli/schemas/local-tools.v1.json",
"wai-quantum-service/schemas/service-tools.v1.json",
"wai-quantum-qpu/schemas/provider.v1.json",
]
BASE = "https://git.transaction.science/Transaction-Science/open-standards/raw/branch/main/wai/"
def refs(v, out):
if isinstance(v, dict):
if isinstance(v.get("$ref"), str):
out.append(v["$ref"])
for x in v.values():
refs(x, out)
elif isinstance(v, list):
for x in v:
refs(x, out)
return out
def main() -> int:
wai = Path(sys.argv[1])
binary = sys.argv[2] if len(sys.argv) > 2 else None
schemas = {}
files = sorted(str(p.relative_to(wai)) for d in PACKAGES for p in (wai / d / "schemas").glob("*.json"))
missing = [f for f in REQUIRED if f not in files]
assert not missing, f"schema files not found: {missing}"
for f in files:
s = json.loads((wai / f).read_text(encoding="utf-8"))
Draft202012Validator.check_schema(s)
assert s["$id"] == BASE + f, f"{f}: its $id is {s['$id']}"
schemas[s["$id"]] = s
registry = Registry().with_resources((i, Resource.from_contents(s)) for i, s in schemas.items())
for i, s in schemas.items():
for r in refs(s, []):
# Resolved as a validator resolves it: against the file's own $id.
registry.resolver(base_uri=i).lookup(r)
print(f"{len(schemas)} schema files: valid 2020-12 schemas, every reference resolving")
def holds(at: str, doc, what: str) -> None:
v = Draft202012Validator({"$ref": at}, registry=registry)
errs = sorted(v.iter_errors(doc), key=lambda e: list(e.path))
assert not errs, f"{what}: " + "; ".join(f"{'/'.join(map(str, e.path))}: {e.message[:200]}" for e in errs[:5])
lists = {}
for f in ["wai-quantum-cli/docs/local-mcp.json", "wai-quantum-cli/docs/service-mcp.json"]:
tools = json.loads((wai / f).read_text(encoding="utf-8"))["tools"]
for t in tools:
for k in ("inputSchema", "outputSchema"):
Draft202012Validator.check_schema(t[k])
assert t[k].get("type") == "object", f"{f}: {t['name']}: its {k} is an object's"
assert not refs(t["outputSchema"], []), f"{f}: {t['name']}: its outputSchema refers out of itself"
lists[f] = {t["name"]: t for t in tools}
print(f"{f}: {len(tools)} tools, each with valid input and output schemas, each output standing alone")
job = BASE + "wai-quantum/schemas/job.v1.json"
for f in ["wai-quantum/src/engine/testdata/job-legacy.json", "wai-quantum/src/engine/testdata/provider-job-legacy.json"]:
holds(job, json.loads((wai / f).read_text(encoding="utf-8")), f)
print("the job bodies sealed before results named their engine and schema follow the job schema")
for doc, at in [
("quantum-conformance/eval/answers.json", "wai-quantum-cli/schemas/eval-answers.v1.json"),
("quantum-conformance/eval/token-cost.json", "wai-quantum-cli/schemas/token-cost.v1.json"),
("wai-quantum/views/manifest.json", "wai-quantum/schemas/views-bundle.v1.json"),
]:
holds(BASE + at, json.loads((wai / doc).read_text(encoding="utf-8")), doc)
print("the committed eval corpus, its token counts and the views page's manifest follow their schemas")
if binary:
bell = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"
run = json.loads(subprocess.run([binary, "run", "--demo-key", "--json", "--shots", "50", "-o", "Z0 Z1", "-"], input=bell, capture_output=True, text=True, check=True).stdout)
holds(job, run, "run --json")
assert run["result"]["schema"] == "wai.quantum.job-result/1" and run["result"]["engine"]["name"] == "wai-quantum", run["result"]
# A set, run here: the set's result, each item sealed alone.
import tempfile
with tempfile.TemporaryDirectory() as d:
prog = Path(d) / "bell.qasm"
prog.write_text(bell, encoding="utf-8")
sset = json.loads(subprocess.run([binary, "run", "--demo-key", "--json", "--shots", "20", str(prog), "--program", str(prog)], capture_output=True, text=True, check=True).stdout)
holds(job, sset, "run --program --json")
holds(BASE + "wai-quantum/schemas/set.v1.json", sset["result"], "a set's result")
assert sset["result"]["schema"] == "wai.quantum.set/1" and sset["result"]["engine"]["name"] == "wai-quantum", sset["result"]
versions = json.loads(subprocess.run([binary, "version", "--json"], capture_output=True, text=True, check=True).stdout)
holds(BASE + "wai-quantum/schemas/versions.v1.json", versions, "version --json")
assert versions["engine"] == run["result"]["engine"], (versions["engine"], run["result"]["engine"])
tele = ("OPENQASM 3.0;\nqubit[3] q;\nbit[3] c;\nh q[0];\ns q[0];\nh q[1];\ncx q[1], q[2];\ncx q[0], q[1];\nh q[0];\n"
"c[0] = measure q[0];\nc[1] = measure q[1];\nif (c[1]) x q[2];\nif (c[0]) z q[2];\nc[2] = measure q[2];\n")
pair = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"
rot = "OPENQASM 3.0;\nqubit[3] q;\nh q;\nccx q[0], q[1], q[2];\nrz(0.3) q[0];\n"
pulse = ("OPENQASM 3.0;\ndefcalgrammar \"openpulse\";\ncal {\n extern port d0;\n extern port a0;\n"
" frame q0 = newframe(d0, 5.0e9, 0);\n frame c0 = newframe(a0, 5.0e9, 0);\n}\n"
"defcal x $0 { play(q0, gaussian(0.4, 64dt, 16dt)); }\ndefcal measure $0 -> bit { return capture_v2(c0, 100dt); }\n"
"bit c;\nx $0;\nc = measure $0;\n")
calls = [
("run_quantum_circuit", {"qasm": bell, "shots": 20}),
("run_quantum_circuit", {"qasm": pair, "shots": 64, "repair": True, "intent": [
{"distribution": {"00": 0.5, "11": 0.5}},
{"sampled": {"00": 0.5, "11": 0.5}, "test": "chi_squared", "alpha": 0.01, "shots": 2000}]}),
("run_quantum_circuit", {"qasm": pair, "shots": 32, "intent": {"equivalent": pair}}),
("run_quantum_circuit", {"qasm": bell, "shots": 20, "compile": {"basis": "standard"}}),
("plan_quantum_circuit", {"qasm": bell}),
("lint_qasm", {"qasm": bell}),
("lint_qasm", {"qasm": "qubit[1] q;\nfoo q[0];"}),
("critique_qasm", {"qasm": bell}),
("check_equivalent", {"a": bell, "b": "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\ncx q[0], q[1];\nc = measure q;\n"}),
("improve_qasm", {"qasm": bell}),
("classical_shortcuts", {"qasm": bell}),
("draw_circuit", {"qasm": bell}),
("verify_quantum_result", {"job": run}),
("list_methods", {}),
("list_components", {}),
("novelty_qasm", {"qasm": bell}),
("rewrite_qasm", {"qasm": bell, "op": "options"}),
("rewrite_qasm", {"qasm": bell, "op": "simplify"}),
("converge_cohort", {"programs": [{"name": "a", "qasm": bell}, {"name": "b", "qasm": "OPENQASM 3.0;\nqubit[1] q;\nt q[0];\n"}]}),
("repair_qasm", {"qasm": "OPENQASM 3.0;\nqubit[2] q\nh q[0];\n"}),
("compile_qasm", {"qasm": "OPENQASM 3.0;\nqubit[2] q;\nh q[0];\nrz(0.3) q[0];\ncx q[0], q[1];\n", "epsilon": 1e-3}),
("compile_qasm", {"qasm": bell, "basis": "standard", "level": 2, "stages": True}),
("qasm_diagnostics", {}),
("qasm_diagnostics", {"code": "Q103"}),
("qasm_diagnostics", {"code": "J021"}),
("estimate_resources", {"qasm": rot, "qubit": "us-e4", "budget": 1e-3, "export": "counts"}),
("debug_branches", {"qasm": tele}),
("debug_step", {"qasm": tele, "line": 14, "outcomes": [1, 1], "probe": {"qubits": [2]}}),
("list_targets", {}),
("show_target", {"target": "synthetic-line-5", "view": True, "document": True}),
("run_on_target", {"qasm": bell, "target": "synthetic-line-5", "shots": 100}),
("plan_quantum_circuit", {"qasm": bell, "target": "synthetic-line-5"}),
("qec_code", {"code": "color:5"}),
("qec_decode", {"code": "surface:3", "error": [4]}),
("qec_decode", {"memory": {"distance": 3, "rounds": 3, "p": 0.002}, "decoder": "correlated", "detectors": [0, 1]}),
("qec_threshold", {"family": "color", "distances": [3, 5], "p": [0.03], "shots": 200}),
("run_quantum_circuit", {"qasm": rot, "observables": ["Z0 Z1"], "noise": {"depolarizing_2q": 0.02}, "mitigate": "zne"}),
("compile_qasm", {"qasm": bell, "basis": "standard", "twirl": {"seed": 3}, "dd": "xy4"}),
("pulse_schedule", {"qasm": pulse}),
("run_quantum_circuit", {"qasm": pulse, "method": "pulse", "shots": 50}),
("plan_quantum_circuit", {"qasm": pulse, "method": "pulse"}),
("gradient_qasm", {"qasm": "OPENQASM 3.0;\ninput float t;\nqubit[2] q;\nh q[0];\ncrx(t) q[0], q[1];\n", "params": {"t": 0.4}, "hamiltonian": ["Z1", "0.5 X0"]}),
("optimize_qasm", {"qasm": "OPENQASM 3.0;\ninput float t;\nqubit q;\nrx(t) q;\n", "params": {"t": 0.4}, "hamiltonian": ["Z0"], "optimizer": "spsa", "steps": 5}),
("vqe_ground_state", {"hamiltonian": ["Z0 Z1", "0.5 X0"], "ansatz": {"layers": 1}, "steps": 5}),
("qaoa_maxcut", {"graph": {"nodes": 3, "edges": [[0, 1], [1, 2]]}, "steps": 5}),
("build_algorithm", {"algorithm": "qpe", "counting": 3, "phase": 0.375}),
]
local = lists["wai-quantum-cli/docs/local-mcp.json"]
def session(calls):
lines = [{"jsonrpc": "2.0", "id": 0, "method": "initialize", "params": {"protocolVersion": "2025-06-18"}}]
lines += [{"jsonrpc": "2.0", "id": i + 1, "method": "tools/call", "params": {"name": n, "arguments": a}} for i, (n, a) in enumerate(calls)]
out = subprocess.run([binary, "mcp", "--demo-key"], input="".join(json.dumps(m) + "\n" for m in lines), capture_output=True, text=True, check=True).stdout
answers = {m["id"]: m for m in map(json.loads, out.splitlines())}
holds(BASE + "wai-quantum/schemas/versions.v1.json", answers[0]["result"]["_meta"]["science.transaction.wai/versions"], "initialize")
got = []
for i, (name, _) in enumerate(calls):
r = answers[i + 1]["result"]
assert r["isError"] is False, f"{name}: {r}"
errs = list(Draft202012Validator(local[name]["outputSchema"]).iter_errors(r["structuredContent"]))
assert not errs, f"{name}: " + "; ".join(e.message[:200] for e in errs[:5])
got.append(r["structuredContent"])
return got
got = session(calls)
# An estimate's check takes the estimate this server wrote.
est = got[[n for n, _ in calls].index("estimate_resources")]
session([("verify_quantum_result", {"job": est})])
# A pulse job's check takes the pulse job this server ran.
ran = got[[i for i, (n, a) in enumerate(calls) if a.get("method") == "pulse" and n == "run_quantum_circuit"][0]]
checked = session([("pulse_check", {"request": ran["request"], "result": ran["result"]})])[0]
assert checked["result"]["verified"] is True, checked
print(f"{binary}: run --json, version --json, initialize and {len(calls) + 2} tool answers follow their schemas")
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except AssertionError as e:
print(f"check_schemas: {e}", file=sys.stderr)
sys.exit(1)