Re-landed from PR #676 (branch wai/quantum-parse-depth, merged with mainf6e302665at 0cf954bfc) as one commit on main, under the land-it model. Six review rounds; round 6's 16 findings are fixed, each with a test that fails ond5564748e. The public, anonymous job service is hardened on every route: - The reader: QEC indices refused past 2^24 and decodes capped; operator runs, else-if ladders and switches read flat at any length; real nesting bounded (Q006: 64 levels in the text, 256 through calls); arrays at most 7 dimensions. - Every read of a client's program is counted first and runs in a child capped on memory, time and answer size, covering admission, dry runs, checks, engine calls, set receipts, MCP verdicts and /v1/verify. - A result-size bound that is a true upper bound for every job kind (sampled intents' fits, trajectories, diagnostics, RFC 8785 numbers), held by a property test over random jobs, and tight where the method knows better (the stabilizer method's outcomes, a loop's verdict). - Dry runs apply exactly the run's checks, MCP's verdict included. - Turns: reading and check shares per client, a lent turn given back when others wait, at most eight waiting, J032 past them; long polls past a client's holds answer 429/503 with Retry-After and the job's status. - JSON-RPC ids echoed as sent; header and body time limits; large bodies read on one of four large-body turns, one per client. - wasmQ's /v1/verify and MCP verify go through the same admission, turns and reading child; wasmQ's profile states this reader's nesting bound. Passed on the merged tree (Framework, linux; M3, macOS): the service suite under ulimit -Sn 256 (118/119), the wai-quantum library (1,458), the CLI, wai-wasmq (67) and its 83 vectors on three engines, the engine with and without receipts, clippy -D warnings, wai breaking against main (5 acknowledged changes), and every repository check. Co-Authored-By: Claude Opus 5.5 <[email protected]>
20 KiB
OpenQASM reader: diagnostic codes
Every refusal and warning the reader gives (wai_quantum::qasm), and every
construct it lowers, carries or keeps verbatim, has a code. A refusal or a
warning reads, on every surface:
line 3: unknown gate foo [Q103]
and, as data (wai-quantum lint --json, the MCP servers' lint_qasm, the
job service, the Studio), carries its code, its outcome, its message
and where it stands: line, column and length, in characters.
Stability. A code never changes meaning once released. A construct that comes to be supported gets a new code for what now happens to it; the old code keeps its row, marked retired, so a code in an old log or receipt still means what it meant then. New codes are only ever added.
Outcomes.
refused: the program is not read, and nothing runs.lowered: read and lowered exactly to the engine's gates and steps.carried: kept in the program as written (its timing, its outputs), changing nothing a method computes unless the method says it uses it.preserved: kept verbatim for export, never executed.warned: read, with something the person should know; the job's result lists it underdiagnostics.
What is asked of a program (the request, the method, an intent, a repair,
the host) has codes of its own, J…: job-refusals.md.
The verdict (verdicts.md) carries a refusal's codes, and the
repair (wai-quantum repair, repair_qasm) makes the fixes that are
mechanical on the lines a diagnostic flags.
The table is also served as data: wai_quantum::qasm::diag::codes() in Rust,
wai-quantum diagnostics [--json] on the command line, the qasm_diagnostics
tool of both MCP servers, and engine_diagnostic_codes() in the browser
engine. A test holds this page to the code's table.
| Code | Outcome | Meaning |
|---|---|---|
Q001 |
refused | A character that is not part of the language. |
Q002 |
refused | A number that does not read: a malformed literal, or one too large to hold. |
Q003 |
refused | A string, a block comment, a bracket or a calibration block that is not closed. |
Q004 |
refused | Something else was expected here: a ;, a name, an expression or a statement (the message says which). |
Q005 |
refused | A statement in a place the language does not allow it: else with no if, case outside switch, a declaration inside a gate. |
Q006 |
refused | A program nested deeper than the reader takes: statements, parentheses, operators, brackets and types more than 64 levels deep in its text (a run of one precedence, a + b + c, and an else if chain each count one, however long), an array of more than 7 dimensions, or more than 256 levels in all through the gates and subroutines it calls; refused, never read by a recursion that could run out of stack. |
Q010 |
warned | An OPENQASM version other than 2.x or 3.x: the program is read as OpenQASM 3. |
Q011 |
warned | An include of a file other than the standard libraries (stdgates.inc, qelib1.inc): its definitions are not read, so a gate it defines is unknown. |
Q012 |
lowered | include "stdgates.inc" or "qelib1.inc": the standard gates, U, gphase and OpenQASM 2's names are built in. |
Q013 |
warned | A pragma or annotation the reader does not act on: kept, not applied. |
Q100 |
refused | The program declares no qubits. |
Q101 |
refused | A name declared twice in one scope, or given to two kinds of thing (a register and an integer). |
Q102 |
refused | A name that is not declared: a register, a variable, an alias or a subroutine. |
Q103 |
refused | A gate that is neither in the standard library nor defined in the program. |
Q104 |
refused | A gate or subroutine given the wrong number of parameters, qubits or arguments. |
Q105 |
refused | A declaration only the top level may make (qubits, a gate, a subroutine, an extern) inside a block. |
Q106 |
refused | A word of the language, or a built-in constant (pi, tau, euler), used as a name. |
Q107 |
refused | An index or slice outside its register or array. |
Q108 |
refused | Registers of different lengths in one statement that applies to whole registers. |
Q109 |
refused | One qubit named twice in one gate. |
Q110 |
refused | A value of the wrong type here: a float where an integer is needed, a complex gate parameter, a qubit where a value is needed. |
Q111 |
refused | More qubits than the reader takes (65 536). |
Q112 |
refused | An integer outside its type's range (a negative uint, a value too wide for int[n]), or integer arithmetic that overflows. |
Q113 |
refused | Division, or a remainder, by zero. |
Q114 |
refused | An input given no value, or a value given for an input the program does not declare. |
Q115 |
refused | An input of a type the reader takes no value for: only int and uint inputs are given values. |
Q116 |
refused | A value that depends on a measurement used where the reader needs it on reading: a gate parameter, an index, a size, a loop's range. |
Q117 |
refused | A gate parameter that is not a finite number. |
Q118 |
refused | Integers divided with a remainder where a real number is wanted: OpenQASM 3 truncates 1/2 to 0 and OpenQASM 2 reads it as 0.5, so write 1.0/2. |
Q119 |
refused | ^ between integers in a program that does not say OPENQASM 3: OpenQASM 3 reads it as exclusive or, OpenQASM 2 as a power; write ** for a power. |
Q120 |
warned | ^ between real numbers, read as a power as OpenQASM 2 reads it; OpenQASM 3 writes **. |
Q121 |
warned | A value rounded to its declared width, as the language defines (angle[n] to n bits of a turn, float[32] and float[16] to single and half precision); the message gives the amount. |
Q122 |
refused | A type width the reader does not hold: a float other than float[16], float[32] and float[64], an integer or an angle wider than 64 bits. |
Q123 |
refused | A cast the language does not allow, or one whose value does not fit. |
Q124 |
refused | Physical qubits ($0) in a program that also declares qubits. |
Q125 |
refused | A call of an extern function, whose body is outside the program. |
Q126 |
refused | A call of an opaque gate, or of a gate with only a calibration: its matrix is not known. |
Q127 |
refused | An assignment to a constant, an input or a loop variable. |
Q128 |
refused | A measurement where a value is needed that is not a bit (measurement gives bits, into a bit register). |
Q129 |
refused | A parameter (input float, input angle) a gradient cannot follow to the gates: under a modifier, in a classical variable, a condition, an index, a size, a loop's range, a subroutine or gphase, or one whose type rounds it (angle[n], float[32]); a gradient follows a parameter through arithmetic, the built-in functions and gate definitions into a gate's arguments. |
Q130 |
refused | A program whose reading would hold more memory than the reader takes: a classical value (an array, a bit register) of more than 64 MiB, each element counted at its width, or more than 512 MiB in all of its values, gates, steps, measurements and timing; refused before it is made. |
Q200 |
lowered | A gate the program defines, inlined at each call with its parameters bound. |
Q201 |
lowered | ctrl @ and negctrl @ on any gate, lowered exactly to standard gates (a negative control is a control between two x). |
Q202 |
lowered | inv @ on any gate, user gates included: each gate's exact inverse, in reverse order. |
Q203 |
lowered | pow(k) @ with an integer k: angles scaled, or the gate repeated; a negative k repeats the inverse. |
Q204 |
lowered | pow(r) @ with a fractional r where an exact gate exists: the principal power (pow(1/2) @ x is sx, pow(r) @ rz(θ) is rz(rθ) for |θ| < 2π). |
Q205 |
refused | pow(r) @ with a fractional r where no exact gate exists here: a user gate, u, cu, or a rotation by 2π or more. |
Q206 |
lowered | gphase(θ): a global phase, which no measurement sees, dropped; under controls it is a phase on the controls. |
Q207 |
refused | A control modifier that adds no control: ctrl(0) @. |
Q208 |
refused | Modifiers that add more controls than the reader lowers (16 written in standard gates, 255 on a gate a method holds whole). |
Q209 |
refused | Gate definitions or subroutine calls nested deeper than 32. |
Q210 |
refused | A program that expands to more gates than the reader holds (2 000 000), or that holds gates whole on more qubits than that in all. |
Q211 |
refused | A modifier on something that is not a gate. |
Q212 |
refused | A statement a gate's body may not hold: a gate holds gate calls, gphase, barrier, loops and conditions known on reading. |
Q300 |
lowered | An if, while or switch whose condition is known on reading: decided then. |
Q301 |
lowered | A condition on measured bits (c[0], c == 3, c >= 2, &&, ||, !), compiled to steps that branch on them. |
Q302 |
refused | A condition that reads neither measured bits nor values known on reading. |
Q303 |
refused | A bit register of more than one bit used as a condition: compare it with a number, as c == 3. |
Q304 |
refused | A comparison with a number that does not fit in the bits compared. |
Q305 |
refused | A negated operand compared with == or != (!c == 1): write c != 1. |
Q306 |
refused | Classical arithmetic on measured bits at run time, beyond a condition, or a comparison between two measured values: the program's steps branch on bits and hold no other run-time values. |
Q307 |
refused | A condition that reads more than 64 bits. |
Q308 |
lowered | for over a range, a set or an array: unrolled, once per value. |
Q309 |
lowered | while whose condition is known on reading: unrolled until it fails. |
Q310 |
refused | A while whose condition reads measured bits and that declares no bound: add @wai.max_iterations N before it. |
Q311 |
warned | A while on measured bits run at most its declared bound (@wai.max_iterations N): a run that still meets its condition after N iterations stops looping there. |
Q312 |
refused | A program that does not finish unrolling within the reader's bound (20 000 000 statements and loop iterations), or that runs out a caller's budget of reading (qasm::within_steps: statements, gates and a generator's loop passes, shared by every program read under it). |
Q313 |
refused | A range with a zero step, or that does not read as [start:end] or [start:step:end]. |
Q314 |
refused | break or continue outside a loop, or return outside a subroutine. |
Q315 |
refused | A return with a value under a condition on measured bits. |
Q316 |
lowered | break, continue, return and end: under a condition on measured bits, a jump forward in the steps. |
Q317 |
lowered | switch: decided on reading, or a chain of conditions on measured bits. |
Q318 |
lowered | A def subroutine, inlined at each call: classical arguments by value, qubits by reference, its return value given back. |
Q319 |
refused | A bit given anything but a measurement at run time: bits are written by measurement (a declaration may give them 0). |
Q320 |
refused | A measurement whose result goes nowhere: measure q; while bit registers are declared (write c = measure q;). |
Q321 |
refused | Qubits measured into a different number of bits. |
Q322 |
lowered | A bit declared inside a block or a subroutine: a bit of its own, which the steps read and the results do not show. |
Q323 |
refused | A program past a bound its reader holds it to as it reads it: qubits, bits, steps, the bits its calls of externs take and give, or the work of reading it (a reader of programs from others, as the hybrid profile reads them). |
Q324 |
refused | A measurement with no target bit (measure q;) in a program that calls externs: its outcome is the bits it declares, so each measurement names the bit it writes (write c = measure q;). |
Q400 |
warned | The method applies no durations: the program's delays, boxes and stretches change nothing it computes, and the result says so. |
Q401 |
carried | delay[d] on qubits, carried in the program's timing. |
Q402 |
carried | box (with or without a duration), carried in the timing around the gates it holds. |
Q403 |
carried | stretch: a duration a scheduler would solve, carried by name. |
Q404 |
carried | barrier, carried in the timing; it changes no gate. |
Q405 |
refused | durationof(…): it needs gate durations, which the program does not give the reader. |
Q406 |
refused | A duration that does not read: no unit, negative, or not known on reading. |
Q407 |
carried | A gate's duration (x[20ns] q;), carried in the timing, not applied. |
Q450 |
preserved | defcal: kept verbatim for export, never executed; the gate's matrix comes from its gate definition or the standard library. |
Q451 |
preserved | cal { … }: kept verbatim for export, never executed. |
Q452 |
preserved | defcalgrammar: kept verbatim for export. |
Q453 |
lowered | In a pulse run, a cal or defcal body read as OpenPulse and lowered to the schedule on frames (plays, delays, phase and frequency changes, captures and barriers) that the pulse simulator integrates. |
Q454 |
refused | In a pulse run, a defcalgrammar other than "openpulse": the pulse reader reads OpenPulse alone. |
Q455 |
refused | A statement in a calibration that the pulse reader does not take: classical control, a frame's attributes or get_phase, an extern function, a frame made inside a defcal, a nested calibration, or a defcal over qubit arguments (the message names it and what to write instead). |
Q456 |
refused | A waveform that does not read: a template the reader does not know, arguments of the wrong number or kind, a length or a width that is not positive, a sample that is not a number, or more samples than it holds. |
Q457 |
refused | A frame or a port that does not read: a play, a delay or a phase or frequency change on a name that is not a frame, newframe on a name that is not a port, a frequency that is not a number, or a port that reaches no qubit. |
Q458 |
refused | A duration in a calibration that is not a whole, non-negative number of samples at the sample period (dt), or a schedule longer than the reader holds. |
Q459 |
refused | In a pulse run, a gate or a measurement on physical qubits that no defcal calibrates for those qubits and those parameters. |
Q460 |
refused | In a pulse run, a statement outside the calibrations that the pulse reader does not take: declared qubits (a pulse program names physical qubits, $0), a modifier, reset, classical control, a subroutine, or a measurement into something other than a bit. |
Q461 |
refused | A capture that does not read: not on a frame of an acquisition port, without a duration or a waveform, or its result put somewhere other than a bit. |
Q462 |
warned | A play on a measurement port: scheduled and timed, its effect on the readout not simulated (a capture reads the qubit's state). |
Q500 |
refused | An angle that is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32): the bit-exact method refuses it, never rounds it; the methods in double precision take it. |
Q501 |
refused | More than 255 qubits for the bit-exact circuit. |
Q502 |
refused | A program that measures a qubit and then acts on it, resets one after its first gate, or acts on measured bits: the bit-exact circuit takes programs whose measurements all come at the end. |
Q600 |
carried | An output declaration, carried into the result: its bits (their places in each outcome) or its value. |
Q601 |
refused | An output that is not a bit and whose value depends on a measurement at the end. |
Q700 |
refused | A file that does not read in the format named: QIR that is not LLVM text with one entry point, or jeff that is not a Cap'n Proto message of the jeff schema (a pointer outside the message, a struct or list of the wrong shape, more than the reader takes); the message says what and where. |
Q701 |
refused | A format version the reader does not take: QIR whose qir_major_version is not 1 or 2, or jeff other than 0.2 and 0.3. |
Q702 |
warned | A QIR module that leaves out what its profile requires (the qir_profiles attribute, the version flags, required_num_qubits, required_num_results, the entry_point attribute of its only function): read from what it holds, and said so. |
Q703 |
refused | A QIR profile the reader does not take: qir_profiles names neither base_profile nor adaptive_profile. |
Q704 |
refused | What the module's own QIR profile forbids: under the base profile a branch, a classical instruction, reading a result, or a gate or reset on a qubit after its measurement; under the adaptive profile an optional capability its module flags do not declare (computation on integers or floats of a type, IR-defined functions, loops, switch, several returns, dynamic qubits or results, arrays). |
Q705 |
refused | A QIR capability the module may use that this reader does not take: loops, switch, phi, IR-defined functions, dynamic allocation of qubits or results, arrays, controlled forms that take their controls in an array, or a classical value computed from a measurement anywhere but a branch's condition. |
Q706 |
refused | An instruction or function the reader does not know: a quantum intrinsic outside the gates it reads (docs/formats.md lists them), a runtime function it does not take, an LLVM instruction no profile lists, or a function a module declares and does not define. |
Q707 |
refused | A QIR operand that does not read: a qubit or result that is not a constant index, an index past required_num_qubits or required_num_results, or an angle that is not a finite number known on reading. |
Q708 |
refused | A value whose meaning the program's text cannot keep: in QIR a result read, measured again and only then branched on; in jeff a qubit the two sides of a branch on a measurement leave in different places. |
Q709 |
warned | Rotations at angles that are not dyadic multiples of 2π, read at their exact doubles: the double-precision methods take them; the bit-exact method refuses them (Q500). |
Q710 |
refused | A jeff custom gate the reader does not know: its name is not a gate of the standard library (in any case), or its qubits or parameters are not that gate's. |
Q711 |
warned | A jeff custom gate named as a gate of the standard library (H, CX, Rx, in any case) with that gate's qubits and parameters: read as that gate, by its name alone. |
Q712 |
lowered | A jeff Pauli-product rotation, exp(iθP) as its schema defines it, lowered exactly to basis changes, a parity ladder and one rz. |
Q713 |
refused | A jeff value used where it cannot be: a qubit or register used twice, a value used before it is defined or never defined, a cycle, or a value of the wrong type or count for its operation. |
Q714 |
refused | A jeff value the reader needs on reading and cannot know: a gate angle, a loop's bounds or a while condition from a measurement, a register's size or index, a switch on a value that is neither known nor a measured bit, or integer arithmetic on a measured bit beyond not, and, or, xor, eq and select. |
Q715 |
lowered | jeff's structured control flow: a for or while decided on reading unrolled, a switch on a known value decided, a switch on a measured bit written as if … else, and a call of a function the module defines inlined. |
Q716 |
warned | A jeff entry point that takes qubits: they are the program's first qubits, starting in |0⟩, and the qubits it returns are not measured. |
Q720 |
refused | A program the format written cannot hold as it is: under QIR's base profile a measurement in the middle, a reset after a gate or a condition (write the adaptive profile), a loop in QIR, or in jeff a branch on a measured bit. |
Q721 |
warned | What the format read or written has no place for, left out and said so: delays, boxes, barriers and gate durations, calibrations, output declarations, and classical values recorded as output. |
See qasm-feature-matrix.md for each construct of OpenQASM 3.1 and its code. The codes from Q700 are those of the readers and writers of other formats (QIR and jeff, formats.md).