### wai-quantum 0.4.1: the fabric's WebGPU member

Additive. The default features, `full`, and every existing pin and digest are unchanged.

- **Certification one case at a time.** `quantum_fabric::Certification` (`new`, `add`,
  `cases`, `finish`) folds a member's outputs into a certificate as they arrive, for a
  member that produces them asynchronously. `certify` is now a loop over it and gives the
  same certificates.
- **Corpora.** `Corpus::Random { seed, cases }` is the existing random corpus
  (`random-v1`). `Corpus::Fabric { seed, cases, wide }` (`fabric-v1`) continues the same
  stream after it with circuits of 11 to 17 qubits (`lanes::random_wide_circuit`), so that
  every dispatch shape a 32-bit-lane member uses is exercised. `FABRIC_DEFAULT` is seed 7,
  200 + 24 circuits; `GENERATOR_FABRIC`, `GENERATOR_FABRIC2` and `fabric_generator` name
  it per gateset, and `Corpus::{generator, name, circuits}` describe any corpus. The
  fabric-v1 lanes32 digests are pinned: `41c726a0…3df7` (circuit/1) and `9a84b55a…7809`
  (circuit2). `lanes::certify_corpus` certifies the lane core on any corpus;
  `certify_lanes` is it on the random corpus, with the same generator string.
- **The lane core, word by word.** `lanes::GateWords` and `gate_words` (a gate as the
  eight 32-bit matrix words and the target and control masks a kernel reads),
  `fxmul_wide` (the exact 64-bit `fx`), `PROBE_EDGES`, `apply_words` and `run_words` (the
  general 2×2 path computed from exact 64-bit values, flagging a gate exactly when the
  reference's result leaves 32 bits, and refusing malformed words), `simulate_checked`,
  `output` and `reference_output`. `lanes::horizon(n, gs)` is the gate count below which a
  valid circuit provably cannot leave 32 bits, computed in integers from the gateset's
  table: 46,340 (circuit/1) and 46,339 (circuit2) at 26 qubits. The module documentation
  and `fxmul` no longer claim that every result of a valid circuit fits in 32 bits; it
  holds within the horizon.
- **`quantum_fabric::plan`**: `Program` (one step per op, the start reduced modulo 2^n),
  `PlannedGate`, `Step`, `compile`, `LaneRun` and `execute`, the CPU executor a member's
  output is held to; `PLAN_REVISION` is 1.
- **`quantum_fabric::wgsl`**: `SHADER`, the lane core transcribed into WGSL
  (`src/quantum_fabric/lanes32.wgsl`: unsigned 32-bit values only, an exact 64-bit copy
  of every result, literal shift amounts, no float, division, conversion, workgroup
  memory or barrier); `implementation_id()` (`wgsl-lanes32/dc8e19f61e0e87ab`, a BLAKE3
  over the shader text and `HOST_LAYOUT`, so any edit is a new implementation that earns
  its certificates again); `gate_record`, `Grid`, `grid` and `gate_grid` (the 64-byte gate
  record and the dispatch grid; `WORKGROUP` and `X_GROUPS_MAX` are 64); `AdapterIdentity`
  with `member_id` (`local/gpu-…` or `local/swgpu-…`, sorting after every
  `local/cpu-<arch>`), `key` and `class`; and `MUTANTS`, `mutate` and `Detector`, the
  shader mutants every device must catch. The module documentation carries the argument
  that the kernel is bit-exact. `wai/tools/quantum-wgsl-check` (unpublished) holds the
  shader to that argument's rules on naga's IR and translates it to MSL, SPIR-V and HLSL.
- **The WebGPU member, feature `quantum_fabric_webgpu`** (opt-in, not in `full`). The
  kernel through the platform's GPU interface natively (Metal, Vulkan, DX12) and through
  a browser's WebGPU on `wasm32-unknown-unknown`; wgpu 30.0.1 enters only those two target
  tables, and on every other target, `wasm32-wasip2` included, the module is compiled
  out. `discover()` opens each adapter at the WebGPU downlevel limits with only the buffer
  limits raised, pins the DX12 shader compiler (translator `naga+dxbc`), probes the
  device's arithmetic against the lane core, and lists each adapter it cannot use with
  the reason (`Discovery`, `Refusal`). `WebGpuMember` runs lanes, programs and circuits,
  certifies a gateset on a corpus, and builds a fabric `Member`; a bit-exact member
  reproduces the pinned random-v1 and fabric-v1 digests. A result that would leave 32
  bits is refused (`WebGpuError::OutOfRange`), never returned. Every entry point is async
  with no executor; natively `blocking` resolves each call in one poll, and a future still
  pending is an error. Natively each submission is waited on before the next, so
  `POLL_TIMEOUT` bounds one chunk of gates, not a run; a failed wait, which the GPU
  interface reports by panicking, is caught and returned as `WebGpuError::Device`, and
  the member treats its device as lost from then on (a `panic = "abort"` build still
  aborts). With no energy figures, placement keeps the CPU reference, and a receipt over
  a member's run is unmetered.
- **wai-rs.** The feature `quantum_fabric_webgpu` forwards to it and re-exports the
  module. `wai_quantum_vectors verify <dir> --webgpu` runs the corpus check once per
  WebGPU member, each state computed by the member; each accept file must also run on the
  member as it does natively, so the 255-qubit files are refused as `too-many-qubits`.
  Without the feature `--webgpu` is an error; with no member it exits 2.
- **CI.** `wai-quantum-webgpu.yml` checks the shader under naga and a SPIR-V validator,
  the browser build, the feature's absence from the `wasm32-wasip2` dependency tree, the
  shader file in the package, and the MSRV; and runs the member's tests
  (`scripts/wai-quantum-webgpu-member.sh`) on software Vulkan, Metal, and a discrete GPU
  through Vulkan. Each member job declares the adapters its runner must have, and fails
  if the adapters found differ, if any test did not run, if a declared adapter lacks a
  bit-exact certificate for each pinned digest, or if a shader mutant survives. The
  `wasm32-wasip2` job requires the fabric's new unit tests by name.

