Skip to main content

memra_engine/
qwen4exp_gpu.rs

1//! qwen4_exp (Qwen3.8-Flash-Next) GPU EAGER forward — onboarding-ladder phase 7, eager arm.
2//!
3//! Lane: research/qwen4exp-bringup-20260829 (SEMANTICS.md is the math, ARCH.md the census
4//! geometry). Scope = text-only single-request prefill + incremental decode, correctness-
5//! gated against the memra-reference oracle (`qwen4exp-gpu-gate`). DELIBERATELY DEFERRED
6//! (each resumes in a named perf/serving lane): CUDA graphs, batching > 1, speculative /
7//! MTP execution, vision, a gather/compact QSA kernel (the eager arm runs dense attention
8//! under the causal∧selection mask per SEMANTICS.md §QSA), and ngram-table async prefetch
9//! (the eager gather is synchronous host math).
10//!
11//! Execution doctrine (the dsv4_gpu precedent): every tensor-scale op runs on the device
12//! (cuBLASLt f32 GEMMs + the engine's f32 elementwise/norm/rope kernels + the three
13//! qwen4_exp eager kernels in cu/kernels.cu); CONTROL decisions and per-token scalars run
14//! as host twins of the exact reference code (MoE routing top-k, the QSA micro-block
15//! selection, PLE n-gram hashing, the PLE signed-sqrt gate scalars). Host twins are pinned
16//! to their reference functions by name in comments; the gate catches drift loudly because
17//! a selection/routing mismatch blows the logit tolerance.
18//!
19//! Weight residency: everything device-resident f32 (bf16 checkpoints dequantize exactly),
20//! EXCEPT (a) the n-gram embedding table — HOST-resident (it is a pure gather source; the
21//! 51B-row table never fits device, SEMANTICS.md §Loading notes / HF `_no_placement_params`)
22//! — and (b) modelopt-NVFP4 stacked expert banks, which stay AS-STORED on device and
23//! dequantize per routed expert through the existing `memra_dsv4_nvfp4_deq_bf16` kernel
24//! (macro applied post-upcast in f32 — exact for any finite macro; the real mint's
25//! `weight_scale_2` values are amax-derived non-pow2, see `dequant_nvfp4_expert_f32`).
26//!
27//! Norm-weight convention: this module binds EFFECTIVE norm weights (the reference crate's
28//! convention). `from_reference_weights` takes them as-is; `load_from_dir` folds the
29//! checkpoint's zero-centered (1+w) values at load for every RMSNorm EXCEPT
30//! `linear_attn.norm` (the qwen35 receipt: hf_mapping.rs qwen.py:302-303 exempts exactly
31//! that row; SEMANTICS.md §GDN says the GDN program is qwen3_5's except the sigmoid gate).
32
33// Shape lints allowed module-wide (lane/clippy-zero-restore-20260901): this is the qwen4exp
34// bring-up lane's kernel-adjacent host code — host twins pinned line-for-line to their
35// reference functions — and its just-gated shape is load-bearing, so index loops, control
36// flow, and `% == 0` idioms are not reshaped here (is_multiple_of also changes zero-divisor
37// semantics from panic to defined). The last four rows (unwrap/question-mark/as_deref/drain)
38// are allowed for the same reason, not because they are harmless: their fixes rewrite
39// control flow and expression order in the pinned twins. Truly mechanical lints (unused
40// imports/mut, no-op casts, needless borrows, doc shape) stay live. NOTE: a module-wide
41// allow exempts FUTURE code in this file too, not just the banked sites — when the bring-up
42// lanes close, narrowing these to per-site allows is fair game.
43#![allow(
44    clippy::manual_is_multiple_of,
45    clippy::collapsible_if,
46    clippy::needless_range_loop,
47    clippy::too_many_arguments,
48    clippy::unnecessary_unwrap,
49    clippy::needless_question_mark,
50    clippy::needless_option_as_deref,
51    clippy::extend_with_drain,
52    clippy::type_complexity,
53    clippy::large_enum_variant
54)]
55
56use std::os::raw::c_void;
57
58use cudarc::driver::{CudaSlice, CudaView, DevicePtr, DevicePtrMut, LaunchConfig, PushKernelArg};
59use memra_gguf::model_plan::{
60    AttentionPlan, FullAttentionPlan, GatedDeltaNetPlan, GdnGateActivation, MicroBlockIndexPlan,
61    MlpPlan, ModelPlan, MoeMlpPlan, PleEmbeddingPlan, ResidualTopology, RopeFactors, RopePlan,
62    RouterPlan, TensorPresence, yarn_attention_factor, yarn_frequency_divisors,
63};
64use memra_gguf::tensor_contract::{LayerTensor, TensorId};
65use memra_reference::{ReferenceTensor, ReferenceWeights};
66
67use crate::Engine;
68
69type Res<T> = Result<T, Box<dyn std::error::Error>>;
70
71// ---------------------------------------------------------------- weights
72
73/// One gated-residual read/write gate set (attn_/mlp_hyper_connection.*) or the exit
74/// mixer (`inject == None`, use_combine=false). Stream-major slicing happens at load so
75/// the forward composes from existing per-plane ops (see `gate_read`).
76struct GateW {
77    /// Per-stream [hidden] slices of hc_norm [wide].
78    norm: Vec<CudaSlice<f32>>,
79    /// The same norm weights stacked [streams, hidden] — the batched-norm kernel
80    /// (`hc_norm_planes_f32`, hcmicro seam) indexes them by stream in one launch.
81    norm_stack: CudaSlice<f32>,
82    /// Per-stream [rank, hidden] column-slices of input_mix_weight_down [rank, wide].
83    down: Vec<CudaSlice<f32>>,
84    /// Per-stream [hidden, rank] row-slices of input_mix_weight_up [wide, rank].
85    up: Vec<CudaSlice<f32>>,
86    /// block_inject_weight [streams, streams*hidden] whole, for the fused inject-gate
87    /// kernel (`hc_inject_gates_f32`); `None` for the exit mixer (census carries no
88    /// block_inject there).
89    inject: Option<CudaSlice<f32>>,
90    /// bf16 trunk-residency twins (see `TRUNK_BF16`): the down/up twins are STACKED
91    /// across streams ([S, rank, hidden] / [S, hidden, rank]) so the fused read gate
92    /// runs each projection as ONE batched `qmatvec_bf16w_f32` launch over the
93    /// stream-major slab instead of `streams` cuBLASLt GEMVs.
94    down_b16: Option<CudaSlice<u8>>,
95    up_b16: Option<CudaSlice<u8>>,
96    inject_b16: Option<CudaSlice<u8>>,
97}
98
99/// Low-rank width of a gate — from the f32 slices, or from the bf16 stacked twin when
100/// `trunk_f32_diet` dropped them (the twin is [S, rank, hidden] bf16).
101fn gate_rank(gate: &GateW, hidden: usize, streams: usize) -> Res<usize> {
102    if gate.down[0].len() >= hidden {
103        return Ok(gate.down[0].len() / hidden);
104    }
105    match gate.down_b16.as_ref() {
106        Some(w) => Ok(w.len() / (2 * streams * hidden)),
107        None => Err("qwen4exp_gpu: gate rank underivable (f32 dropped and no bf16 twin)".into()),
108    }
109}
110
111struct QsaW {
112    attn: FullAttentionPlan,
113    overlay: MicroBlockIndexPlan,
114    wq: CudaSlice<f32>, // [2*nh*hd, H] fused [q|gate] per head
115    wk: CudaSlice<f32>, // [nkv*hd, H]
116    wv: CudaSlice<f32>, // [nkv*hd, H]
117    wo: CudaSlice<f32>, // [H, nh*hd]
118    q_norm: Option<CudaSlice<f32>>,
119    k_norm: Option<CudaSlice<f32>>,
120    idx_proj: CudaSlice<f32>, // [(ih+ikv)*id, H]
121    /// Indexer norms live host-side: the selection is a host twin of
122    /// `memra_reference::micro_block_selection_mask`.
123    idx_q_norm: Vec<f32>,
124    idx_k_norm: Vec<f32>,
125    /// bf16 trunk-residency twins (`TRUNK_BF16` guards + receipts). wq/wk/wv live in
126    /// ONE row-stacked twin (proj-stack residency — see `GdnW::proj_b16`).
127    proj_b16: Option<CudaSlice<u8>>,
128    wo_b16: Option<CudaSlice<u8>>,
129    /// YaRN rope tables (long-context lane) — `None` on the shipped config.
130    yarn: Option<YarnRopeW>,
131}
132
133/// YaRN rope consumption (qwen4_exp long-context lane): the per-pair frequency divisors
134/// (device copy for `rope_neox_ffm`, host copy for the indexer twin) plus the derived
135/// attention factor on cos/sin. Built once at load from `RopeFactors::Yarn` through the
136/// memra-gguf transformers-twin helpers (pinned against the banked receipt). The QSA q/k
137/// rope, the indexer q/pooled-k rope, and the MTP draft all consume ONE table — the
138/// indexer shares the main rotary (SEMANTICS.md §Rope), enforced at build by the
139/// overlay-vs-attention rope-width check.
140struct YarnRopeW {
141    ff: CudaSlice<f32>,
142    ff_host: Vec<f32>,
143    mscale: f32,
144}
145
146/// Resolve a QSA rope plan into the yarn tables (or `None` for the plain-rope shipped
147/// config). PartialRotary/Checkpoint stay refused — this family's plan never emits them.
148/// `overlay` = `Some` at single-card load (the shared-table width check); the TP2 half
149/// builder passes `None` because the same plan already passed the check on card 0.
150fn build_yarn(
151    e: &Engine,
152    rope: &RopePlan,
153    overlay: Option<&MicroBlockIndexPlan>,
154    layer: u32,
155) -> Res<Option<YarnRopeW>> {
156    match rope.factors {
157        RopeFactors::None => Ok(None),
158        RopeFactors::Yarn {
159            factor,
160            original_context,
161            beta_fast,
162            beta_slow,
163        } => {
164            if let Some(overlay) = overlay
165                && overlay.rope_dimensions != rope.dimensions
166            {
167                return Err(format!(
168                    "qwen4exp_gpu: layer {layer} indexer rope width {} != attention rope \
169                     width {} — the shared yarn table would be wrong",
170                    overlay.rope_dimensions, rope.dimensions
171                )
172                .into());
173            }
174            let ff_host = yarn_frequency_divisors(
175                rope.dimensions,
176                rope.base,
177                factor,
178                original_context,
179                beta_fast,
180                beta_slow,
181            );
182            Ok(Some(YarnRopeW {
183                ff: e.htod(&ff_host)?,
184                ff_host,
185                mscale: yarn_attention_factor(factor),
186            }))
187        }
188        _ => Err(format!(
189            "qwen4exp_gpu: layer {layer}: only plain or yarn rope factors are supported"
190        )
191        .into()),
192    }
193}
194
195struct GdnW {
196    plan: GatedDeltaNetPlan,
197    qkv: CudaSlice<f32>,    // [conv_dim, H]
198    z: CudaSlice<f32>,      // [nv*hv, H]
199    beta: CudaSlice<f32>,   // [nv, H]
200    alpha: CudaSlice<f32>,  // [nv, H]
201    conv_w: CudaSlice<f32>, // [conv_dim, K]
202    a: CudaSlice<f32>,      // [nv] — the reference's `a` multiplier, used as-is by gdn_glog
203    dt: CudaSlice<f32>,     // [nv]
204    norm: CudaSlice<f32>,   // [hv]
205    out: CudaSlice<f32>,    // [H, nv*hv]
206    /// bf16 trunk-residency twins (`TRUNK_BF16` guards + receipts). The same-activation
207    /// projections live in ONE row-stacked twin [qkv; z; beta; alpha] (proj-stack
208    /// residency, VRAM-neutral): the per-mat arm launches against row-offset views, the
209    /// proj-stack seam launches the whole stack in one `qmatvec_bf16w_multi4_f32`.
210    proj_b16: Option<CudaSlice<u8>>,
211    out_b16: Option<CudaSlice<u8>>,
212}
213
214enum MixerW {
215    Qsa(QsaW),
216    Gdn(GdnW),
217}
218
219/// One resident half of a routed expert bank (fused gate_up [E, 2ff, H] with gate rows
220/// first per expert — SplitExpertGateUp orientation — or down [E, H, ff]).
221/// F32 = fixture / bf16 checkpoints (dequantized exactly at load). Nvfp4 = modelopt
222/// stacked as-stored (codes [E, out, in/2] u8 + e4m3 scales [E, out, in/16] + finite
223/// macros); per routed expert the eager path dequants through the existing dsv4 kernel
224/// then upcasts, macro post-upcast in f32 (`dequant_nvfp4_expert_f32`). Halves mix
225/// freely — NVFP4 needs in_f % 16 == 0, which geometry (not policy) decides per
226/// projection.
227enum BankHalf {
228    F32(CudaSlice<f32>),
229    Nvfp4 {
230        codes: CudaSlice<u8>,
231        scales: CudaSlice<u8>,
232        macros: Vec<f32>,
233        /// Device twin of `macros` for the grouped decode path
234        /// (`qmatvec_nvfp4_modelopt_sel_f32` folds the macro in its epilogue).
235        macros_dev: CudaSlice<f32>,
236    },
237    /// HOST-resident raw bf16 bank (logical [E, out, in]) — the real-checkpoint gate
238    /// residency for BF16 artifacts whose f32 banks exceed device memory (the 360 GB
239    /// export: f32 banks ≈ 483 GB). Each routed expert's rows are uploaded and upcast
240    /// per forward call (`LoadOptions::host_bf16_banks`); bf16→f32 is exact, so the
241    /// value chain equals the device-resident F32 arm. Gate-mode residency only —
242    /// never a serving configuration.
243    HostBf16(Vec<u8>),
244    /// DEVICE-resident raw bf16 bank (logical [E, out, in], row-major bf16 bytes) — the
245    /// MTP draft bank residency (mtp-spec lane): the graft ships the 512-expert bank
246    /// BF16 (~5 GB device) and the decode path runs per-selected-expert
247    /// `qmatvec_bf16w_f32` row-offset launches straight off the resident bytes
248    /// (exact-widening products, the trunk-bf16 accumulation class). Half the bytes of
249    /// an f32 residency; no dequant materialization.
250    DeviceBf16(CudaSlice<u8>),
251}
252
253struct ExpertBank {
254    gate: BankHalf, // logical [E, ff, H]
255    up: BankHalf,   // logical [E, ff, H]
256    down: BankHalf, // logical [E, H, ff]
257}
258
259struct MoeW {
260    plan: MoeMlpPlan,
261    router: CudaSlice<f32>, // [E, H]
262    /// bf16 residency twin of the router (set_router_bf16 seam; same guards as trunk).
263    router_b16: Option<CudaSlice<u8>>,
264    bank: ExpertBank,
265    shared_gate: CudaSlice<f32>,
266    shared_up: CudaSlice<f32>,
267    shared_down: CudaSlice<f32>,
268    shared_input_gate: Option<CudaSlice<f32>>, // [H]
269    /// bf16 residency twins for the shared-expert mats (hcmicro seam; same
270    /// representability/geometry guards as the trunk twins). gate/up live in ONE
271    /// row-stacked twin (proj-stack residency — see `GdnW::proj_b16`).
272    shared_gu_b16: Option<CudaSlice<u8>>,
273    shared_down_b16: Option<CudaSlice<u8>>,
274}
275
276/// The n-gram embedding table stays HOST-resident (pure gather source).
277enum NgramTable {
278    F32(Vec<f32>),
279    Bf16(Vec<u8>),
280}
281
282impl NgramTable {
283    fn rows(&self, head_dim: usize) -> usize {
284        match self {
285            Self::F32(data) => data.len() / head_dim,
286            Self::Bf16(bytes) => bytes.len() / 2 / head_dim,
287        }
288    }
289
290    fn gather_into(&self, row: usize, head_dim: usize, dst: &mut [f32]) {
291        match self {
292            Self::F32(data) => {
293                dst.copy_from_slice(&data[row * head_dim..(row + 1) * head_dim]);
294            }
295            Self::Bf16(bytes) => {
296                let start = row * head_dim * 2;
297                for (i, out) in dst.iter_mut().enumerate() {
298                    let b = u16::from_le_bytes([bytes[start + 2 * i], bytes[start + 2 * i + 1]]);
299                    *out = f32::from_bits(u32::from(b) << 16);
300                }
301            }
302        }
303    }
304}
305
306struct PleW {
307    plan: PleEmbeddingPlan,
308    key_proj: Vec<CudaSlice<f32>>, // per-stream [H, embed] row slices of [wide, embed]
309    value_proj: CudaSlice<f32>,    // [H, embed]
310    norm_key: Vec<CudaSlice<f32>>, // per-stream [H]
311    norm_query: Vec<CudaSlice<f32>>,
312    norm_conv: Vec<CudaSlice<f32>>,
313    conv_w: Vec<CudaSlice<f32>>, // per-stream [H, K] row slices of [wide, K]
314    multipliers: Vec<i64>,
315    sizes: Vec<i64>,
316    offsets: Vec<i64>,
317    table: NgramTable,
318}
319
320struct LayerW {
321    index: u32,
322    eps_attn: f32,
323    eps_mlp: f32,
324    attn_gate: GateW,
325    mlp_gate: GateW,
326    mixer: MixerW,
327    moe: MoeW,
328    ple: Option<PleW>,
329}
330
331/// The MTP/NextN draft block (SEMANTICS.md §MTP, mtp-spec lane): input fusion =
332/// `fc_embedding(zero-centered-RMSNorm(embed(tok)))` broadcast over streams +
333/// per-stream `fc_hidden(FLAT GemmaRMSNorm_wide(trunk wide hidden))`; ONE decoder layer
334/// (QSA + MoE, own indexer, no PLE) at global index n_trunk; exit through the draft's
335/// OWN hyper_connection_mixer into the SHARED trunk lm_head. The post-layer wide state
336/// is the K>1 multi-step carrier. Norm rows arrive (1+w)-FOLDED from the loader (the
337/// family GemmaRMSNorm convention).
338struct MtpW {
339    /// Fusion-norm epsilons from the plan (`MtpInputPlan`).
340    eps_embed: f32,
341    eps_hidden: f32,
342    /// mtp.pre_fc_norm_embedding [hidden], folded.
343    pre_norm_embed: CudaSlice<f32>,
344    /// mtp.pre_fc_norm_hidden [wide] — FLAT over the whole wide vector, folded.
345    pre_norm_hidden: CudaSlice<f32>,
346    fc_embed: CudaSlice<f32>, // mtp.fc_embedding [hidden, hidden]
347    fc_embed_b16: Option<CudaSlice<u8>>,
348    fc_hidden: CudaSlice<f32>, // mtp.fc_hidden [hidden, hidden]
349    fc_hidden_b16: Option<CudaSlice<u8>>,
350    /// The draft decoder layer (index n_trunk; QSA mixer + MoE, bank DeviceBf16 on the
351    /// real graft).
352    layer: LayerW,
353    /// mtp.hyper_connection_mixer (read-only exit gate, no inject).
354    mixer: GateW,
355}
356
357/// Card-1 draft placement (mtp10): the MTP block's device tensors (weights + the ~5 GB
358/// DeviceBf16 expert bank), the draft state, and the draft workspace all live on a SECOND
359/// card, with a private full copy of the shared lm head beside them so the draft's head
360/// matvec never crosses the bus. What crosses per round is SMALL: the trunk's captured
361/// wide rows for the draft replay ((a+1) x wide f32, P2P) and the drafted token ids
362/// (4-byte dtoh each). Exactness is untouched by construction — the draft only proposes;
363/// the card-0 verify chunk arbitrates. Why this exists (measured, mtp9): the co-resident
364/// placement leaves ~2.6 GiB on card 0, which OOMs any spec run on a prompt past ~400
365/// tokens — the two-card placement is a PREREQUISITE for agentic-length prompts, not an
366/// optimization.
367struct MtpDev1 {
368    /// Engine ordinal the draft was built on (every draft call must present it).
369    dev: usize,
370    /// [vocab, H] f32 copy of the shared lm head (the cuBLASLt fallback arm).
371    output: CudaSlice<f32>,
372    /// bf16 twin of the head copy (the arm `linear_trunk_into` takes at the default
373    /// trunk_bf16 seam) — same bytes as card 0's twin, so a draft logit is bit-identical
374    /// to its single-card twin at the same row.
375    output_b16: Option<CudaSlice<u8>>,
376}
377
378/// FR-Spec draft-head trim (DRAFT-REGIME.md law 1, mtp9 lane): the DRAFT scores only
379/// the top-N own-gen rank subset, the TARGET verify stays full-vocab — so the spec
380/// byte-identity contract is untouched BY CONSTRUCTION and only ACCEPTANCE can move
381/// (a token outside the trim set is unproposable, i.e. a guaranteed one-round miss).
382/// Rows are gathered D2D from the shared lm head, so the trimmed head is the SAME
383/// bytes the full head would have read — a trimmed draft logit is bit-identical to its
384/// full-vocab twin at the same row.
385struct DraftTrim {
386    /// Rows in the trimmed head.
387    n: usize,
388    /// `d2t[i]` = the TARGET vocab id of trimmed row i (rank order, most frequent first).
389    d2t: Vec<u32>,
390    /// [n, hidden] gathered bf16 rows (the `qmatvec_bf16w_f32` arm — what the trunk seam
391    /// runs by default, and the ONLY residency built when the full head has a bf16 twin:
392    /// an f32 twin would cost 2x the bytes for a path the default never takes, and this
393    /// artifact's post-load headroom is ~2.5 GiB).
394    head_b16: Option<CudaSlice<u8>>,
395    /// [n, hidden] gathered f32 rows — built ONLY when there is no bf16 twin to gather
396    /// from (the cuBLASLt fallback arm). At least one of the two is always present.
397    head: Option<CudaSlice<f32>>,
398}
399
400/// The draft head's linear when the trim is armed — `linear_trunk_into`'s arm chain over
401/// the trimmed residency (bf16 twin first, f32 fallback), so a trimmed row's value chain
402/// is the full head's VERBATIM at the same row.
403fn linear_trim_into(
404    e: &Engine,
405    trim: &DraftTrim,
406    x: &CudaSlice<f32>,
407    y: &mut CudaSlice<f32>,
408    t: usize,
409    in_f: usize,
410) -> Res<()> {
411    if trunk_bf16_on() {
412        if let Some(w) = trim.head_b16.as_ref() {
413            if (2..=12).contains(&t) && verify_mt_on() {
414                return launch_qmatvec_bf16w_mt(e, w, 0, x, y, in_f, trim.n, t);
415            }
416            return launch_qmatvec_bf16w(e, w, x, y, in_f, trim.n, t, 1, 0, 0, in_f, 0);
417        }
418    }
419    let w = trim.head.as_ref().ok_or(
420        "qwen4exp_gpu: the draft trim was gathered bf16-only — the f32 head arm needs \
421         trunk_bf16 on (or a checkpoint without a bf16 lm-head twin)",
422    )?;
423    e.linear_device_into(x, w, y, t, in_f, trim.n)
424}
425
426pub struct Qwen4ExpGpu {
427    pub plan: ModelPlan,
428    hidden: usize,
429    streams: usize,
430    vocab: usize,
431    embed_host: Vec<f32>, // [vocab, H] — host row-gather source (reference embed twin)
432    output: CudaSlice<f32>, // [vocab, H] lm head (tied to embed when absent)
433    /// bf16 trunk-residency twin of the lm head (`TRUNK_BF16` guards + receipts).
434    output_b16: Option<CudaSlice<u8>>,
435    layers: Vec<LayerW>,
436    exit_mixer: GateW,
437    exit_eps: f32,
438    /// The MTP draft block — present when the checkpoint's mtp.* rows were materialized
439    /// (`LoadOptions::load_mtp`, or a fixture whose weights carry them).
440    mtp: Option<MtpW>,
441    /// Card-1 draft placement (mtp10): when present, `mtp`'s device tensors live on the
442    /// SECOND card and this holds that card's private lm-head copy. Every draft call
443    /// (mtp_state / mtp_draft_forward / spec_generate's draft engine) must then present
444    /// an engine on `mtp_dev1.dev` — enforced, not assumed.
445    mtp_dev1: Option<MtpDev1>,
446    /// FR-Spec draft-head trim — `None` (full-vocab draft head) unless a caller armed it
447    /// with `build_draft_trim`. Default OFF: a trim is a per-model, per-requant rank
448    /// artifact (law 1), never an inferred default.
449    draft_trim: Option<DraftTrim>,
450    /// A built trim PARKED by `set_draft_trim(false)` — the A/B's OFF arm keeps the
451    /// gathered head allocated (no per-rep realloc churn) while the draft runs full-vocab.
452    draft_trim_parked: Option<DraftTrim>,
453    /// Deferred-chain device embed table (mtp11, `SpecOpts::defer`) — `None` until a
454    /// caller armed it with `arm_spec_devchain`. Default OFF (flags law): the host
455    /// chain is the shipped mtp10 program until the deferred round carries its own
456    /// interleaved receipts.
457    chain_embed: Option<ChainEmbed>,
458}
459
460/// The deferred chain's embed rows, resident on the DRAFT engine (mtp11): the chain's
461/// device argmax feeds the next step's embed gather without a host round trip. Rows are
462/// raw bf16 when every source value is bf16-clean (this artifact's embed is a bf16
463/// export, so `f32 -> bits>>16 -> bits<<16` is the identity and the device gather's
464/// QT_BF16 deq reproduces the host `embed_host` row BITWISE — checked value-by-value at
465/// arm time, never assumed), else raw f32 (always exact, 2x bytes). With the FR-Spec
466/// trim armed the rows are gathered in TRIM-RANK order (row i = embed[d2t[i]]), so the
467/// RAW trim-space argmax index gathers its own next-step row and no d2t table crosses
468/// to the device; the round's drain maps raw -> target ids through `draft_token`.
469struct ChainEmbed {
470    table: CudaSlice<u8>,
471    qt: i32,
472    row_bytes: usize,
473    /// Rows in the table == `draft_logits_width()` at arm time (trim.n or vocab).
474    rows: usize,
475    /// Armed against a live trim (the table is trim-rank-gathered)?
476    for_trim: bool,
477    /// Device ordinal the table lives on (must be the draft engine's).
478    dev: usize,
479}
480
481// ---------------------------------------------------------------- state
482
483struct PleState {
484    /// Per-stream [pad_ple, H] device history of the NORMED gated value rows
485    /// (pad_ple = (K-1)*dilation = 9 on the artifact). Zeros = fresh context.
486    conv_hist: Vec<CudaSlice<f32>>,
487    /// INCREMENTAL n-gram id cache (`plecache` seam, 262k perf lane). `host_ngram_ids` is a
488    /// `ngram_ids` twin over the FULL token history and the caller then slices the last `t`
489    /// rows — so a decode step at a 150,000-token fill rebuilds 150,000 rows of hashes to
490    /// use ONE. Measured: `ple.host_ngram_gather` is **7.3 ms, 19.5% of a deep decode
491    /// token** (PROFILE-11 §5), second only to `qsa.sdpa`, and it is O(context) per token.
492    ///
493    /// Cacheable EXACTLY, and the proof is local: `shift_right_ignore_eos` at position p
494    /// reads `history[p - shift]` and an eos scan that only ever moves left-to-right, so
495    /// `ids[token]` is a pure function of `token_ids[..=token]` and NEVER changes when a
496    /// token is appended. The cache therefore appends; it never recomputes a row.
497    ///
498    /// `history` carries the `max_ngram - 1` eos prefix exactly as the twin builds it, and
499    /// `last_eos` is the twin's running `last_eos_inclusive` at the end of `history`. On a
500    /// rewind (spec reject) both truncate, which is the same discipline the `idxcache` seam
501    /// needed for its device mirror.
502    ngram_ids: Vec<i64>,
503    ngram_history: Vec<i64>,
504    ngram_last_eos: i64,
505}
506
507// ---- Quantized-cache storage (kvq/idxq lanes) --------------------------------------
508
509/// q8_0 row bytes for a `dim`-wide f32 row (34 B per 32-elem block, zero-padded tail).
510fn q8_row_bytes(dim: usize) -> usize {
511    dim.div_ceil(32) * 34
512}
513/// q5_1 row bytes (24 B per 32-elem block).
514fn q5_row_bytes(dim: usize) -> usize {
515    dim.div_ceil(32) * 24
516}
517
518/// QSA KV cache storage. `F32` is the historical exactness arm (every banked receipt);
519/// `Q8Q5` stores K rows as q8_0 and V rows as q5_1 byte caches (the owner's asymmetric
520/// K=q8/V=q5 default), token-slot-addressed exactly like the f32 rows — rewind stays a
521/// position rewrite, replay overwrites slots in place.
522enum QsaKvStore {
523    F32 {
524        k: CudaSlice<f32>, // [cap, nkv*hd] post-norm+rope keys
525        v: CudaSlice<f32>, // [cap, nkv*hd]
526    },
527    Q8Q5 {
528        k: CudaSlice<u8>, // [cap * q8_row_bytes(nkv*hd)]
529        v: CudaSlice<u8>, // [cap * q5_row_bytes(nkv*hd)]
530    },
531}
532
533impl QsaKvStore {
534    fn is_quant(&self) -> bool {
535        matches!(self, QsaKvStore::Q8Q5 { .. })
536    }
537    fn capacity_rows(&self, kv_dim: usize) -> usize {
538        match self {
539            QsaKvStore::F32 { k, .. } => k.len() / kv_dim,
540            QsaKvStore::Q8Q5 { k, .. } => k.len() / q8_row_bytes(kv_dim),
541        }
542    }
543}
544
545/// Host twin of the device q8_0 quantize warp program (`q4e_quant_q8_block`) — must stay
546/// BIT-IDENTICAL to it (the idxcache seam's contract: host- and device-quantized rows
547/// interleave in one cache), pinned by the tiny gate's quant-twin arm. `lrintf` under the
548/// default rounding mode == `round_ties_even`; the amax fold is order-free (fmaxf over
549/// |x| is associative + commutative); the f16 scale conversion is RNE on both sides.
550fn host_quant_q8_row(row: &[f32], dim: usize, out: &mut Vec<u8>) {
551    for b in 0..dim.div_ceil(32) {
552        let mut amax = 0.0f32;
553        for l in 0..32 {
554            let e = b * 32 + l;
555            let x = if e < dim { row[e] } else { 0.0 };
556            amax = amax.max(x.abs());
557        }
558        let d = amax / 127.0f32;
559        let mut id = if d != 0.0 { 1.0f32 / d } else { 0.0 };
560        // Subnormal-amax guard — mirrors the device kernel (contract totality).
561        if !id.is_finite() {
562            id = 0.0;
563        }
564        out.extend_from_slice(&memra_gguf::nvfp4_repack::f32_to_f16_bits(d).to_le_bytes());
565        for l in 0..32 {
566            let e = b * 32 + l;
567            let x = if e < dim { row[e] } else { 0.0 };
568            let q = ((x * id).round_ties_even() as i32).clamp(-127, 127);
569            out.push(q as i8 as u8);
570        }
571    }
572}
573
574/// Host twin of `q4e_deq_q8` (d single-mul q — one f32 multiply, same bits as the
575/// device `__fmul_rn`).
576fn host_deq_q8_rows(bytes: &[u8], row0: usize, rows: usize, dim: usize, out: &mut Vec<f32>) {
577    let rb = q8_row_bytes(dim);
578    for r in row0..row0 + rows {
579        let row = &bytes[r * rb..(r + 1) * rb];
580        for e in 0..dim {
581            let blk = &row[(e >> 5) * 34..];
582            let d = memra_gguf::dequant::fp16_to_f32(u16::from_le_bytes([blk[0], blk[1]]));
583            let q = blk[2 + (e & 31)] as i8 as f32;
584            out.push(d * q);
585        }
586    }
587}
588
589/// Host twin of the device q5_1 quantize warp program (`q4e_quant_q5_block`); min/max
590/// folds are order-free (fminf/fmaxf associative + commutative), the rest is per-lane.
591fn host_quant_q5_row(row: &[f32], dim: usize, out: &mut Vec<u8>) {
592    for b in 0..dim.div_ceil(32) {
593        let lane = |l: usize| -> f32 {
594            let e = b * 32 + l;
595            if e < dim { row[e] } else { 0.0 }
596        };
597        let mut mn = f32::INFINITY;
598        let mut mx = f32::NEG_INFINITY;
599        for l in 0..32 {
600            mn = mn.min(lane(l));
601            mx = mx.max(lane(l));
602        }
603        let d = (mx - mn) / 31.0f32;
604        let mut id = if d != 0.0 { 1.0f32 / d } else { 0.0 };
605        // Subnormal-amax guard — mirrors the device kernel (contract totality).
606        if !id.is_finite() {
607            id = 0.0;
608        }
609        let q5 = |l: usize| -> u32 {
610            (((lane(l) - mn) * id).round_ties_even() as i32).clamp(0, 31) as u32
611        };
612        let mut qh = 0u32;
613        for l in 0..32 {
614            qh |= ((q5(l) >> 4) & 1) << l;
615        }
616        out.extend_from_slice(&memra_gguf::nvfp4_repack::f32_to_f16_bits(d).to_le_bytes());
617        out.extend_from_slice(&memra_gguf::nvfp4_repack::f32_to_f16_bits(mn).to_le_bytes());
618        out.extend_from_slice(&qh.to_le_bytes());
619        for l in 0..16 {
620            out.push(((q5(l) & 0x0F) | ((q5(l + 16) & 0x0F) << 4)) as u8);
621        }
622    }
623}
624
625/// Host twin of `q4e_deq_q5` (`__fmaf_rn(d, q5, m)` == `f32::mul_add`).
626fn host_deq_q5_rows(bytes: &[u8], row0: usize, rows: usize, dim: usize, out: &mut Vec<f32>) {
627    let rb = q5_row_bytes(dim);
628    for r in row0..row0 + rows {
629        let row = &bytes[r * rb..(r + 1) * rb];
630        for e in 0..dim {
631            let blk = &row[(e >> 5) * 24..];
632            let d = memra_gguf::dequant::fp16_to_f32(u16::from_le_bytes([blk[0], blk[1]]));
633            let m = memra_gguf::dequant::fp16_to_f32(u16::from_le_bytes([blk[2], blk[3]]));
634            let qh = u32::from_le_bytes([blk[4], blk[5], blk[6], blk[7]]);
635            let lane = e & 31;
636            let lo = if lane < 16 {
637                blk[8 + lane] & 0x0F
638            } else {
639                blk[8 + lane - 16] >> 4
640            };
641            let q5 = (lo as u32) | (((qh >> lane) & 1) << 4);
642            out.push(d.mul_add(q5 as f32, m));
643        }
644    }
645}
646
647/// Host twin of the device `__float2bfloat16` RNE conversion (finite domain; the raw
648/// keys are finite projection outputs — NaN handling is not part of the pin).
649fn f32_to_bf16_rne(x: f32) -> u16 {
650    let bits = x.to_bits();
651    let rounding_bias = 0x7fff + ((bits >> 16) & 1);
652    (bits.wrapping_add(rounding_bias) >> 16) as u16
653}
654
655/// Indexer raw-key HOST cache (idxq lane): rows of `idx_dim` keys, stored f32
656/// (historical), q8_0 blocks, or bf16. Consumed ONLY through `rows_f32` into the fp32
657/// mean-pooling — quantize the cache, dequant at read, pooling math identical.
658enum IdxRawCache {
659    F32(Vec<f32>),
660    Q8(Vec<u8>),
661    Bf16(Vec<u16>),
662}
663
664impl IdxRawCache {
665    fn new(mode: IdxQMode) -> Self {
666        match mode {
667            IdxQMode::F32 => IdxRawCache::F32(Vec::new()),
668            IdxQMode::Q8 => IdxRawCache::Q8(Vec::new()),
669            IdxQMode::Bf16 => IdxRawCache::Bf16(Vec::new()),
670        }
671    }
672    fn rows(&self, idx_dim: usize) -> usize {
673        match self {
674            IdxRawCache::F32(v) => v.len() / idx_dim,
675            IdxRawCache::Q8(v) => v.len() / q8_row_bytes(idx_dim),
676            IdxRawCache::Bf16(v) => v.len() / idx_dim,
677        }
678    }
679    fn truncate_rows(&mut self, rows: usize, idx_dim: usize) {
680        match self {
681            IdxRawCache::F32(v) => v.truncate(rows * idx_dim),
682            IdxRawCache::Q8(v) => v.truncate(rows * q8_row_bytes(idx_dim)),
683            IdxRawCache::Bf16(v) => v.truncate(rows * idx_dim),
684        }
685    }
686    /// Append `n` rows given as f32 (host-side quantize twin — bit-identical to the
687    /// device append kernels, so host/device-quantized rows interleave freely).
688    fn append_rows_f32(&mut self, rows: &[f32], n: usize, idx_dim: usize) {
689        match self {
690            IdxRawCache::F32(v) => v.extend_from_slice(&rows[..n * idx_dim]),
691            IdxRawCache::Q8(v) => {
692                for r in 0..n {
693                    host_quant_q8_row(&rows[r * idx_dim..(r + 1) * idx_dim], idx_dim, v);
694                }
695            }
696            IdxRawCache::Bf16(v) => {
697                v.extend(rows[..n * idx_dim].iter().map(|&x| f32_to_bf16_rne(x)));
698            }
699        }
700    }
701    /// Dequant rows [row0, row0+n) to f32 (the pooling read).
702    fn rows_f32(&self, row0: usize, n: usize, idx_dim: usize, out: &mut Vec<f32>) {
703        out.clear();
704        match self {
705            IdxRawCache::F32(v) => out.extend_from_slice(&v[row0 * idx_dim..(row0 + n) * idx_dim]),
706            IdxRawCache::Q8(v) => host_deq_q8_rows(v, row0, n, idx_dim, out),
707            IdxRawCache::Bf16(v) => out.extend(
708                v[row0 * idx_dim..(row0 + n) * idx_dim]
709                    .iter()
710                    .map(|&b| memra_gguf::dequant::bf16_to_f32(b)),
711            ),
712        }
713    }
714}
715
716/// Indexer raw-key DEVICE cache (idxcache seam), format-matched to the host cache.
717/// Bf16 rows live as u16; Q8 rows as q8_0 bytes. The host cache materializes from these
718/// by dtoh VERBATIM (no re-quant), so lazy materialization stays bit-identical.
719enum IdxRawDev {
720    F32(CudaSlice<f32>),
721    Q8(CudaSlice<u8>),
722    Bf16(CudaSlice<u16>),
723}
724
725/// Pay the idxcache lazy-materialization debt: dtoh device rows [host_rows, dev_rows)
726/// into the host cache VERBATIM — format-matched bytes, no re-quant, so the seam's
727/// bit-identity contract holds per format.
728fn idx_materialize_host(
729    e: &Engine,
730    raw_keys: &mut IdxRawCache,
731    raw_dev: &Option<IdxRawDev>,
732    raw_dev_rows: usize,
733    idx_dim: usize,
734) -> Res<()> {
735    let host_rows = raw_keys.rows(idx_dim);
736    if raw_dev_rows <= host_rows {
737        return Ok(());
738    }
739    let m = raw_dev
740        .as_ref()
741        .ok_or("idxcache: rows counted without a cache")?;
742    match (m, raw_keys) {
743        (IdxRawDev::F32(d), IdxRawCache::F32(h)) => {
744            let delta = e.dtoh_view(&d.slice(host_rows * idx_dim..raw_dev_rows * idx_dim))?;
745            h.extend_from_slice(&delta);
746        }
747        (IdxRawDev::Q8(d), IdxRawCache::Q8(h)) => {
748            let rb = q8_row_bytes(idx_dim);
749            let delta = e.dtoh_u8_view(&d.slice(host_rows * rb..raw_dev_rows * rb))?;
750            h.extend_from_slice(&delta);
751        }
752        (IdxRawDev::Bf16(d), IdxRawCache::Bf16(h)) => {
753            let delta = e
754                .gpu
755                .stream()
756                .clone_dtoh(&d.slice(host_rows * idx_dim..raw_dev_rows * idx_dim))?;
757            e.gpu.stream().synchronize()?;
758            h.extend_from_slice(&delta);
759        }
760        _ => return Err("idxcache: device/host raw-key formats disagree".into()),
761    }
762    Ok(())
763}
764
765/// The idxq selection-identity audit twin (instrument): parallel f32 raw/pooled caches
766/// fed from the per-chunk idx_proj dtoh, selection recomputed on host per scored row.
767struct IdxAudit {
768    raw_f32: IdxRawCache, // always the F32 variant
769    pooled_f32: Vec<f32>,
770}
771
772enum MixerState {
773    Qsa {
774        kv: QsaKvStore,
775        /// Indexer RAW key cache — pre-norm, pre-rope, host-resident
776        /// (`update_indexer`, SEMANTICS.md §QSA: 128 dims/token/QSA-layer). Precision
777        /// per the idxq lane (f32 / q8_0 / bf16), latched at alloc.
778        raw_keys: IdxRawCache,
779        /// POOLED indexer key cache — the per-block mean/k_layernorm/rope form the
780        /// scorer consumes, host-resident, one row per COMPLETE block. A block's pooled
781        /// key depends only on its 4 raw keys + its start position, never on the query
782        /// row, so it is computed ONCE (bit-identical to the historical per-row
783        /// recompute: same op order per block) and extended as blocks complete.
784        /// Truncated with `raw_keys` on rewind.
785        pooled_keys: Vec<f32>,
786        /// DEVICE mirror of `pooled_keys` for the device scorer (long-context lane):
787        /// same rows, grown by H2D of the delta as blocks complete. `None` until the
788        /// scorer engages (below the drop point nothing is scored at all).
789        pooled_dev: Option<CudaSlice<f32>>,
790        /// Rows currently mirrored (<= pooled_keys.len()/head_dim).
791        pooled_dev_rows: usize,
792        /// DEVICE raw-key cache (devtwin stage 3, `idxcache` seam): the k-part rows
793        /// appended d2d as chunks land; below the selection horizon `raw_keys` LAGS
794        /// this (the lazy host materialization dtohs the delta at the first scored
795        /// chunk). Row r here is absolute cache row r — rewind clamps `raw_dev_rows`
796        /// alongside the host truncation.
797        raw_dev: Option<IdxRawDev>,
798        /// Rows valid in `raw_dev` (>= raw_keys rows while the seam is on).
799        raw_dev_rows: usize,
800        /// idxq selection-identity audit twin (instrument, `MEMRA_Q4E_IDXQ_AUDIT=1`).
801        idx_audit: Option<Box<IdxAudit>>,
802    },
803    Gdn {
804        conv: CudaSlice<f32>,  // [pad, conv_dim] raw pre-conv qkv history rows
805        state: CudaSlice<f32>, // [nv, hv, hk] recurrent matrix (reference layout)
806    },
807}
808
809struct LayerState {
810    mixer: MixerState,
811    ple: Option<PleState>,
812}
813
814/// Per-GDN-layer verify-chunk stash (mtp-spec lane): per-column recurrent snapshots +
815/// the chunk's conv-rewind inputs. Sized once at `spec_arm` (k_cap columns).
816struct GdnStash {
817    /// [k_cap, nv*hv*hk] — recurrent state AFTER column i (D2D snapshot per column).
818    states: CudaSlice<f32>,
819    /// [pad, conv_dim] — pre-chunk conv history (rewind rebuild input).
820    conv_pre: CudaSlice<f32>,
821    /// [k_cap, conv_dim] — the chunk's raw pre-conv qkv rows (rewind rebuild input).
822    qkv_rows: CudaSlice<f32>,
823    /// Verify SCAN-CHAIN segment graph (mtp9, `set_verify_graphs`): dwconv + the t
824    /// per-column {scan step, state snapshot} launches + the conv-history roll, captured
825    /// at ONE chunk width. The chain is serially DEPENDENT (every column reads and writes
826    /// the recurrent state), so each launch's issue latency is fully exposed — this is the
827    /// densest all-device launch run in the verify chunk (t=6: 14 launches x 36 GDN
828    /// layers). `Some((t, graph))`; a chunk at a different t invalidates it.
829    scan_graph: Option<(usize, GraphEntry)>,
830    /// Chunk widths already WARMED at: the first chunk of a width runs eager so every
831    /// workspace slot is allocated and parked outside the capture region (allocations
832    /// inside a capture become graph mem nodes — the trunk's draft-graph lesson).
833    scan_warm: Option<usize>,
834}
835
836/// Per-PLE-layer verify-chunk stash: pre-chunk conv history + the chunk's normed
837/// gated-value rows, per stream.
838struct PleStash {
839    hist_pre: Vec<CudaSlice<f32>>,    // per stream [pad_ple, hidden]
840    normed_rows: Vec<CudaSlice<f32>>, // per stream [k_cap, hidden]
841}
842
843/// The verify-chunk instrument (mtp-spec lane). Armed by `spec_arm`; while armed,
844/// every forward captures the trunk's FINAL WIDE rows at their absolute positions
845/// (the draft's hidden seeds) and every 1 < t <= k_cap chunk (a) runs the EXACT row
846/// programs (each row bit-identical to the t == 1 decode program — the spec
847/// byte-identity contract) and (b) stashes per-column GDN/PLE state so
848/// `verify_rewind` can drop rejected columns without replay.
849pub struct VerifyStash {
850    k_cap: usize,
851    /// The live chunk (base_pos, t) — set by the last exact chunk, consumed by rewind.
852    chunk: Option<(usize, usize)>,
853    /// The last FUSED verify chunk (`vfuse` cost instrument), for the rewind refusal
854    /// message only. A fused chunk leaves no per-column stash, so the state it produced
855    /// cannot be rewound; naming the shape keeps that refusal readable as the seam's
856    /// documented limit instead of an internal inconsistency.
857    fused_chunk: Option<(usize, usize)>,
858    gdn: Vec<Option<GdnStash>>,
859    ple: Vec<Option<PleStash>>,
860    /// Trunk final wide rows, RING-slotted: absolute row r lives at slot
861    /// `r % ring_rows`. `ring_rows == capacity` (the `spec_arm` default) is the
862    /// historical whole-history layout; the long-context arm (`spec_arm_ring`) bounds it
863    /// (see that doc for the freshness contract).
864    wide: CudaSlice<f32>,
865    ring_rows: usize,
866    /// Card-1 mirror of `wide` (mtp10 dev1 draft placement): the draft's hidden seeds,
867    /// P2P-copied row-range by row-range (prefill once, then (a+1) rows per round).
868    /// Allocated lazily by `spec_generate` when the draft engine is a different card.
869    wide_dev1: Option<CudaSlice<f32>>,
870    /// Per-row argmax of the last exact chunk (device argmax, 4t-byte dtoh).
871    argmax: Vec<u32>,
872    /// Device argmax staging [k_cap].
873    toks: CudaSlice<u32>,
874    /// Skip the [t, vocab] logits dtoh on exact chunks and fill `argmax` instead
875    /// (forward returns an EMPTY vec in that mode — the spec loop's fast path).
876    want_argmax: bool,
877    /// Extend the argmax fast path to t == 1 forwards (mtp11 deferred round): the
878    /// zero-draft verify and the dynk plain tail commit a device argmax + 4-byte dtoh
879    /// instead of the full [1, vocab] row + host scan (bit-identical token by the
880    /// argmax-gate contract). Only honored with `want_argmax` (greedy non-trace).
881    want_argmax_t1: bool,
882    /// Big (t > k_cap, i.e. prefill) forwards dtoh only the LAST logits row (mtp11):
883    /// the spec loop consumes exactly one row for x0, and the full block is ~1 MB/row.
884    /// Exact chunks and t == 1 steps are untouched (sampled verify samples EVERY row).
885    last_row_only: bool,
886}
887
888pub struct Qwen4ExpState {
889    pos: usize,
890    capacity: usize,
891    /// Workspace-slot reserve unit (tokens). Equals `capacity` from `alloc_state` (the
892    /// historical behavior: one allocation serves the largest possible chunk); a
893    /// long-context state (`alloc_state_reserve`) caps it at the CHUNK bound so a
894    /// 1M-capacity state does not reserve 1M-token transients. Forwards longer than
895    /// this still work (slots grow), they just reallocate.
896    reserve: usize,
897    /// Full token history (host). PLE n-gram hashing needs the EOS-segment structure of
898    /// the whole context (reference `shift_right_ignore_eos`), and eager memory cost is
899    /// 4 B/token.
900    tokens: Vec<u32>,
901    layers: Vec<LayerState>,
902    /// Named-slot step workspace (perf lane item 2a — see `StepPool`).
903    ws: StepPool,
904    /// Captured decode-step graphs (perf lane item 2b — see `StepGraphs`).
905    graphs: StepGraphs,
906    /// TP2 half-state (perf round 3). `Some` after the first `decode_step_tp2`: the
907    /// single-card mixer state is migrated into per-card halves and goes STALE — a
908    /// TP2-touched state refuses single-card forwards (fresh state per mode; the A/B
909    /// harness allocates per arm).
910    tp2: Option<Tp2State>,
911    /// Verify-chunk stash (mtp-spec lane), armed by `spec_arm`.
912    verify: Option<VerifyStash>,
913}
914
915/// Named-slot device workspace for the forward step (perf lane item 2a: PROFILE-0
916/// counted 11,366 pooled allocs + 1,685 memsets per token; 2,234 allocs remained after
917/// round 1). Every step-transient buffer is TAKEN from a named slot and PUT back at its
918/// last use; with the seam ON (`set_step_ws`, default per receipts) the same CudaSlice —
919/// and therefore the same device ADDRESS — serves every step, which both removes the
920/// cuMemAllocAsync/FreeAsync churn and is the address-stability prerequisite for CUDA
921/// graph capture (item 2b). With the seam OFF every take allocates fresh and every put
922/// drops — byte-identical to the prior pooled-alloc behavior, the A/B twin. A slot is
923/// allocated at `reserve` elements on first take (capacity-derived at the call sites)
924/// so a growing shape (the decode mask) never reallocates mid-run.
925#[derive(Default)]
926struct StepPool {
927    f32s: std::collections::BTreeMap<&'static str, CudaSlice<f32>>,
928    i32s: std::collections::BTreeMap<&'static str, CudaSlice<i32>>,
929    u8s: std::collections::BTreeMap<&'static str, CudaSlice<u8>>,
930    u64s: std::collections::BTreeMap<&'static str, CudaSlice<u64>>,
931}
932
933/// Per-stream slot names (hc_count is 4 on the artifact, 2 on the tiny plan; the loader
934/// refuses streams > 8).
935/// TP2-prefill exit slots: the last row of each plane, copied into t == 1 buffers so
936/// the decode exit segment runs unchanged on a chunk's final row.
937const EXIT_PLANE_SLOTS: [&str; 8] = [
938    "exit.p0", "exit.p1", "exit.p2", "exit.p3", "exit.p4", "exit.p5", "exit.p6", "exit.p7",
939];
940const PLANE_SLOTS: [&str; 8] = [
941    "plane.0", "plane.1", "plane.2", "plane.3", "plane.4", "plane.5", "plane.6", "plane.7",
942];
943const INJECT_SLOTS: [&str; 8] = [
944    "hc.inj.0", "hc.inj.1", "hc.inj.2", "hc.inj.3", "hc.inj.4", "hc.inj.5", "hc.inj.6", "hc.inj.7",
945];
946
947impl StepPool {
948    fn take_f32(
949        &mut self,
950        e: &Engine,
951        name: &'static str,
952        len: usize,
953        reserve: usize,
954    ) -> Res<CudaSlice<f32>> {
955        if step_ws_on() {
956            if let Some(buf) = self.f32s.remove(name) {
957                if buf.len() >= len {
958                    return Ok(buf);
959                }
960            }
961            e.uninit(len.max(reserve))
962        } else {
963            e.uninit(len)
964        }
965    }
966
967    fn put_f32(&mut self, name: &'static str, buf: CudaSlice<f32>) {
968        if step_ws_on() {
969            self.f32s.insert(name, buf);
970        }
971    }
972
973    /// Drop every parked slot and report the bytes returned to the driver.
974    ///
975    /// `take_*` keeps a slot whenever `buf.len() >= len`, which is what makes the pool
976    /// free at steady state — and what makes a WIDE phase's slots outlive it. A chunked
977    /// co-prefill parks its t = 2,048 scratch and the spec decode that follows runs at
978    /// t <= k + 1, so without this the run carries GiBs of prefill-shaped workspace
979    /// through a phase that needs megabytes. At a 262,144 fill that is the difference
980    /// between arriving and `CUDA_ERROR_OUT_OF_MEMORY` (memra#53: the co-prefill finished
981    /// all 128 chunks in 1,476 s and then died at the transition with the trunk card at
982    /// 96,531 MiB of 97,887 MiB).
983    ///
984    /// This is not a behaviour arm and has no seam: it releases scratch the program has
985    /// finished with. Every `take_*` returns an UNINITIALIZED buffer and every consumer
986    /// writes before it reads (the pool's standing contract), so a fresh allocation is
987    /// indistinguishable from a parked one — the `mtp-spec-ring` byte-identity arm crosses
988    /// this exact boundary and is the gate. Captured graphs bake slot addresses, so the
989    /// caller invalidates `StepGraphs` alongside, the same way a growing multi-token chunk
990    /// already does.
991    fn shed(&mut self) -> usize {
992        let bytes = self.f32s.values().map(|b| b.len() * 4).sum::<usize>()
993            + self.i32s.values().map(|b| b.len() * 4).sum::<usize>()
994            + self.u8s.values().map(|b| b.len()).sum::<usize>()
995            + self.u64s.values().map(|b| b.len() * 8).sum::<usize>();
996        self.f32s.clear();
997        self.i32s.clear();
998        self.u8s.clear();
999        self.u64s.clear();
1000        bytes
1001    }
1002
1003    fn take_i32(
1004        &mut self,
1005        e: &Engine,
1006        name: &'static str,
1007        host: &[i32],
1008        reserve: usize,
1009    ) -> Res<CudaSlice<i32>> {
1010        if step_ws_on() {
1011            let mut buf = match self.i32s.remove(name) {
1012                Some(buf) if buf.len() >= host.len() => buf,
1013                _ => e.alloc_uninit::<i32>(host.len().max(reserve))?,
1014            };
1015            let mut view = buf.slice_mut(0..host.len());
1016            e.gpu.stream().memcpy_htod(host, &mut view)?;
1017            Ok(buf)
1018        } else {
1019            e.htod_i32(host)
1020        }
1021    }
1022
1023    fn put_i32(&mut self, name: &'static str, buf: CudaSlice<i32>) {
1024        if step_ws_on() {
1025            self.i32s.insert(name, buf);
1026        }
1027    }
1028
1029    /// Take an i32 slot WITHOUT uploading (device router: contents arrive from the
1030    /// `qwen4exp_route_topk_f32` launch — the take_u8 discipline for i32).
1031    fn take_i32_slot(
1032        &mut self,
1033        e: &Engine,
1034        name: &'static str,
1035        len: usize,
1036        reserve: usize,
1037    ) -> Res<CudaSlice<i32>> {
1038        if step_ws_on() {
1039            if let Some(buf) = self.i32s.remove(name) {
1040                if buf.len() >= len {
1041                    return Ok(buf);
1042                }
1043            }
1044        }
1045        e.alloc_uninit::<i32>(len.max(reserve))
1046    }
1047
1048    fn take_f32_h2d(
1049        &mut self,
1050        e: &Engine,
1051        name: &'static str,
1052        host: &[f32],
1053        reserve: usize,
1054    ) -> Res<CudaSlice<f32>> {
1055        if step_ws_on() {
1056            let mut buf = match self.f32s.remove(name) {
1057                Some(buf) if buf.len() >= host.len() => buf,
1058                _ => e.uninit(host.len().max(reserve))?,
1059            };
1060            let mut view = buf.slice_mut(0..host.len());
1061            e.gpu.stream().memcpy_htod(host, &mut view)?;
1062            Ok(buf)
1063        } else {
1064            e.htod(host)
1065        }
1066    }
1067
1068    fn take_u8_h2d(
1069        &mut self,
1070        e: &Engine,
1071        name: &'static str,
1072        host: &[u8],
1073        reserve: usize,
1074    ) -> Res<CudaSlice<u8>> {
1075        if step_ws_on() {
1076            let mut buf = match self.u8s.remove(name) {
1077                Some(buf) if buf.len() >= host.len() => buf,
1078                _ => e.alloc_u8_uninit(host.len().max(reserve))?,
1079            };
1080            let mut view = buf.slice_mut(0..host.len());
1081            e.gpu.stream().memcpy_htod(host, &mut view)?;
1082            Ok(buf)
1083        } else {
1084            e.htod_bytes(host)
1085        }
1086    }
1087
1088    fn put_u8(&mut self, name: &'static str, buf: CudaSlice<u8>) {
1089        if step_ws_on() {
1090            self.u8s.insert(name, buf);
1091        }
1092    }
1093
1094    /// Take a u8 slot WITHOUT uploading (TP2 pack blobs: contents arrive via
1095    /// `upsert_u8` before the consuming segment runs/replays).
1096    fn take_u8(
1097        &mut self,
1098        e: &Engine,
1099        name: &'static str,
1100        len: usize,
1101        reserve: usize,
1102    ) -> Res<CudaSlice<u8>> {
1103        if step_ws_on() {
1104            if let Some(buf) = self.u8s.remove(name) {
1105                if buf.len() >= len {
1106                    return Ok(buf);
1107                }
1108            }
1109        }
1110        e.alloc_u8_uninit(len.max(reserve))
1111    }
1112
1113    /// H2D into a PARKED u8 slot, seeding it on first use (the write_i32 discipline
1114    /// with a bootstrap arm — a captured graph bakes the slot address, so after the
1115    /// first take the buffer must never rebind).
1116    fn upsert_u8(
1117        &mut self,
1118        e: &Engine,
1119        name: &'static str,
1120        host: &[u8],
1121        reserve: usize,
1122    ) -> Res<()> {
1123        if !self.u8s.contains_key(name) {
1124            let buf = self.take_u8(e, name, host.len(), reserve)?;
1125            self.put_u8(name, buf);
1126        }
1127        let buf = self
1128            .u8s
1129            .get_mut(name)
1130            .ok_or_else(|| format!("step workspace: slot {name} is not parked"))?;
1131        if buf.len() < host.len() {
1132            return Err(format!("step workspace: slot {name} is too small").into());
1133        }
1134        let mut view = buf.slice_mut(0..host.len());
1135        e.gpu.stream().memcpy_htod(host, &mut view)?;
1136        Ok(())
1137    }
1138
1139    /// Borrow a parked u8 slot without removing it (graph segments read the pack blob
1140    /// a driver upsert wrote).
1141    fn peek_u8(&self, name: &'static str) -> Res<&CudaSlice<u8>> {
1142        self.u8s
1143            .get(name)
1144            .ok_or_else(|| format!("step workspace: slot {name} is not parked").into())
1145    }
1146
1147    fn take_u64_h2d(
1148        &mut self,
1149        e: &Engine,
1150        name: &'static str,
1151        host: &[u64],
1152        reserve: usize,
1153    ) -> Res<CudaSlice<u64>> {
1154        if step_ws_on() {
1155            let mut buf = match self.u64s.remove(name) {
1156                Some(buf) if buf.len() >= host.len() => buf,
1157                _ => e.alloc_uninit::<u64>(host.len().max(reserve))?,
1158            };
1159            let mut view = buf.slice_mut(0..host.len());
1160            e.gpu.stream().memcpy_htod(host, &mut view)?;
1161            Ok(buf)
1162        } else {
1163            e.htod_u64(host)
1164        }
1165    }
1166
1167    fn put_u64(&mut self, name: &'static str, buf: CudaSlice<u64>) {
1168        if step_ws_on() {
1169            self.u64s.insert(name, buf);
1170        }
1171    }
1172
1173    /// Borrow a parked slot without removing it (graph driver: the router logits dtoh
1174    /// reads the slot a captured graph wrote).
1175    fn peek_f32(&self, name: &'static str) -> Res<&CudaSlice<f32>> {
1176        self.f32s
1177            .get(name)
1178            .ok_or_else(|| format!("step workspace: slot {name} is not parked").into())
1179    }
1180
1181    /// H2D into an EXISTING slot in place (graph driver: per-step routing inputs into
1182    /// the addresses the captured graph baked). Errors if the slot is missing or short —
1183    /// a captured graph must never silently rebind.
1184    fn write_i32(&mut self, e: &Engine, name: &'static str, host: &[i32]) -> Res<()> {
1185        let buf = self
1186            .i32s
1187            .get_mut(name)
1188            .ok_or_else(|| format!("step workspace: slot {name} is not parked"))?;
1189        if buf.len() < host.len() {
1190            return Err(format!("step workspace: slot {name} is too small").into());
1191        }
1192        let mut view = buf.slice_mut(0..host.len());
1193        e.gpu.stream().memcpy_htod(host, &mut view)?;
1194        Ok(())
1195    }
1196
1197    fn write_f32(&mut self, e: &Engine, name: &'static str, host: &[f32]) -> Res<()> {
1198        let buf = self
1199            .f32s
1200            .get_mut(name)
1201            .ok_or_else(|| format!("step workspace: slot {name} is not parked"))?;
1202        if buf.len() < host.len() {
1203            return Err(format!("step workspace: slot {name} is too small").into());
1204        }
1205        let mut view = buf.slice_mut(0..host.len());
1206        e.gpu.stream().memcpy_htod(host, &mut view)?;
1207        Ok(())
1208    }
1209}
1210
1211/// Captured decode-step graphs (perf lane item 2b). Layer graphs bake the workspace
1212/// slot ADDRESSES (StepPool, item 2a), the state buffers, and the resident weights, so
1213/// they live beside the state they were captured against. `a[l]` = the device-only
1214/// layer interior (attn read gate → GDN mixer → write → mlp read gate) for GDN layers
1215/// without a PLE block; `b[l]` = the grouped-MoE tail (sel matvecs → shared expert →
1216/// mlp write) for all-NVFP4 layers; `exit` = exit mixer + lm head. QSA layers keep
1217/// their eager interior (the indexer host twin + mask h2d live there). Capture is
1218/// no-warmup (`capture_graph_retained_nowarm`): stream capture enqueues WITHOUT
1219/// executing, and the step's side effects (GDN state/conv advance, plane writes) must
1220/// not run twice.
1221#[derive(Default)]
1222struct StepGraphs {
1223    /// The first graph-eligible decode step runs EAGER to warm every slot (allocations
1224    /// inside a capture region become graph mem nodes — the draft-graph lesson).
1225    warm: bool,
1226    a: Vec<Option<GraphEntry>>,
1227    b: Vec<Option<GraphEntry>>,
1228    exit: Option<GraphEntry>,
1229}
1230
1231type GraphEntry = (
1232    cudarc::driver::CudaGraph,
1233    Vec<Box<dyn std::any::Any + Send>>,
1234);
1235
1236impl Qwen4ExpState {
1237    pub fn position(&self) -> usize {
1238        self.pos
1239    }
1240}
1241
1242/// Per-layer parity capture from a prefill — mirrors the transformers hidden-goldens
1243/// hook points (`make-goldens.py`): decoder-layer outputs on the WIDE stream and the
1244/// exit `hyper_connection_mixer` output.
1245pub struct PrefillCapture {
1246    /// One entry per trunk layer: post-layer wide rows, token-major [t, streams*hidden].
1247    pub layer_wide: Vec<Vec<f32>>,
1248    /// Exit mixer output [t, hidden].
1249    pub exit_mixed: Vec<f32>,
1250}
1251
1252// ---------------------------------------------------------------- profiling (perf lane)
1253
1254/// Wall-clock section profiler for the eager forward (perf lane:
1255/// research/qwen4exp-bringup-20260829/perf/). Disabled (default) the wrappers are
1256/// zero-cost passthroughs; enabled, every section boundary synchronizes the stream so a
1257/// section's time covers everything it queued. Synchronization itself distorts the step
1258/// total — the receipt therefore always banks the UNPROFILED warm ms/token beside the
1259/// profiled table and reads shares, not absolutes, from the latter.
1260pub mod prof {
1261    use std::cell::RefCell;
1262    use std::collections::BTreeMap;
1263
1264    thread_local! {
1265        static STATE: RefCell<Option<BTreeMap<&'static str, (f64, u64)>>> =
1266            const { RefCell::new(None) };
1267    }
1268
1269    thread_local! {
1270        /// Rows accumulated BEFORE `split_prefill` (the prompt + draft prefill of a spec
1271        /// run), kept apart so a round-shape receipt never absorbs them. Every spec
1272        /// profile cut before 2026-09-02 (mtp4/5/6, ep2 cell A) attributed the all-rows
1273        /// prompt prefill — which runs the per-expert MoE executor — to the ROUND, which
1274        /// is where the "30% per-expert dequant" term in those receipts came from.
1275        static PREFILL: RefCell<Option<BTreeMap<&'static str, (f64, u64)>>> =
1276            const { RefCell::new(None) };
1277        static ROUNDS_ONLY: RefCell<bool> = const { RefCell::new(false) };
1278    }
1279
1280    /// Start accumulating (resets any previous accumulation).
1281    pub fn enable() {
1282        STATE.with(|s| *s.borrow_mut() = Some(BTreeMap::new()));
1283        PREFILL.with(|s| *s.borrow_mut() = None);
1284    }
1285
1286    /// Ask `spec_generate_ext` to call `split_prefill` once its prefills are done, so the
1287    /// main accumulation covers ROUNDS ONLY. Instrument-only; default false.
1288    pub fn set_rounds_only(on: bool) {
1289        ROUNDS_ONLY.with(|s| *s.borrow_mut() = on);
1290    }
1291
1292    pub fn rounds_only() -> bool {
1293        ROUNDS_ONLY.with(|s| *s.borrow())
1294    }
1295
1296    /// Move everything accumulated so far into the PREFILL bucket and start the main
1297    /// accumulation afresh. No-op unless profiling is on and `rounds_only` was requested.
1298    pub fn split_prefill() {
1299        if !on() || !rounds_only() {
1300            return;
1301        }
1302        let pre = STATE.with(|s| s.borrow_mut().replace(BTreeMap::new()));
1303        PREFILL.with(|s| *s.borrow_mut() = pre);
1304    }
1305
1306    /// Drain the PREFILL bucket (section, total_seconds, calls); empty when no split ran.
1307    pub fn take_prefill() -> Vec<(&'static str, f64, u64)> {
1308        PREFILL.with(|s| {
1309            s.borrow_mut()
1310                .take()
1311                .map(|map| map.into_iter().map(|(k, (t, c))| (k, t, c)).collect())
1312                .unwrap_or_default()
1313        })
1314    }
1315
1316    pub fn on() -> bool {
1317        STATE.with(|s| s.borrow().is_some())
1318    }
1319
1320    /// Drain the accumulated rows (section, total_seconds, calls) and disable.
1321    pub fn take() -> Vec<(&'static str, f64, u64)> {
1322        STATE.with(|s| {
1323            s.borrow_mut()
1324                .take()
1325                .map(|map| map.into_iter().map(|(k, (t, c))| (k, t, c)).collect())
1326                .unwrap_or_default()
1327        })
1328    }
1329
1330    pub(super) fn add(name: &'static str, seconds: f64) {
1331        STATE.with(|s| {
1332            if let Some(map) = s.borrow_mut().as_mut() {
1333                let entry = map.entry(name).or_insert((0.0, 0));
1334                entry.0 += seconds;
1335                entry.1 += 1;
1336            }
1337        });
1338    }
1339}
1340
1341/// Grouped selected-experts decode path (attack (a) of the perf lane). Default ON —
1342/// better-wins-by-default with the interleaved A/B receipts in
1343/// research/qwen4exp-bringup-20260829/perf/; the per-expert path stays as the prefill
1344/// executor, the non-NVFP4 arm, and the A/B twin. Flipped per-arm by the gate binary.
1345static MOE_SEL_PATH: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1346
1347pub fn set_moe_sel_path(on: bool) {
1348    MOE_SEL_PATH.store(on, std::sync::atomic::Ordering::Relaxed);
1349}
1350
1351fn moe_sel_path_on() -> bool {
1352    MOE_SEL_PATH.load(std::sync::atomic::Ordering::Relaxed)
1353}
1354
1355/// Fused hyper-connection read gate (attack (c)). Default ON with the interleaved A/B
1356/// receipts in the perf lane; the unfused chain stays as the A/B twin (`gate_read_legacy`)
1357/// and as the readable statement of the reference program.
1358static HC_FUSED_GATE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1359
1360pub fn set_hc_fused_gate(on: bool) {
1361    HC_FUSED_GATE.store(on, std::sync::atomic::Ordering::Relaxed);
1362}
1363
1364fn hc_fused_gate_on() -> bool {
1365    HC_FUSED_GATE.load(std::sync::atomic::Ordering::Relaxed)
1366}
1367
1368/// bf16 trunk residency (perf lane item: PROFILE-1 residual §2 — gdn.proj/qsa.proj/
1369/// lm_head/gate GEMVs are memory-bound on f32 trunk weights at ~1.3 TB/s). Dense trunk
1370/// mats keep their f32 residency AND gain a bf16 twin when (a) every value is exactly
1371/// bf16-representable (true for BF16 checkpoints — dequant was exact, so the twin equals
1372/// the artifact bytes) and (b) in_f % 8 == 0 (the matvec kernel's uint4 vector width) —
1373/// geometry/value guards, never policy. Default ON with the interleaved A/B receipts in
1374/// research/qwen4exp-bringup-20260829/perf/PROFILE-2.md; the f32 cuBLASLt path stays
1375/// resident as the A/B twin (`--ab-seam trunk`) and the fallback for guarded tensors.
1376static TRUNK_BF16: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1377
1378pub fn set_trunk_bf16(on: bool) {
1379    TRUNK_BF16.store(on, std::sync::atomic::Ordering::Relaxed);
1380}
1381
1382fn trunk_bf16_on() -> bool {
1383    TRUNK_BF16.load(std::sync::atomic::Ordering::Relaxed)
1384}
1385
1386/// INSTRUMENT-ONLY: run a `HeadMode::All` single-card forward on the GROUPED MoE executor
1387/// instead of the per-expert one.
1388///
1389/// **Default OFF, and that is a decision with a reason, not an implementation accident.**
1390/// OFF is byte-for-byte today's behavior: `HeadMode::All` selects the per-expert executor,
1391/// which is the reference-shaped program the goldens capture and every hidden/greedy
1392/// exactness receipt in this lane rest on. Flipping the default would silently re-base
1393/// every one of those receipts, so OFF is the only safe default and there is no perf
1394/// argument on the other side (the per-expert path is the SLOW one — see the executor
1395/// comment at the `grouped` selection).
1396///
1397/// ON exists for exactly one caller: the TP2-prefill CLASS gate's PRIME regime. That regime
1398/// compares an all-rows single-card forward against an all-rows TP2 forward, and TP2's
1399/// `tp2_moe_rows` is grouped on both cards. With this flag OFF the comparison therefore
1400/// straddles TWO independent variables — the TP2 expert-half split AND the
1401/// grouped-vs-per-expert executor difference — and the executor term DOMINATES: measured on
1402/// this artifact, grouped-vs-grouped lands at 1.4e-5 while per-expert-vs-grouped lands at
1403/// 2e-3..4e-3, and the tiny gate's own `prefill-extend` arm prices the executor difference
1404/// alone at 1.865e-4 on a fixture. A band calibrated against the straddled number would be
1405/// ~100x too loose for the question the gate is asking, which is the same "calibrated
1406/// against nothing" failure the two-regime gate was written to end.
1407///
1408/// It is an instrument, not a serving seam: nothing in a serving path reads it, and
1409/// long-context prefill already rides the grouped program through `HeadMode::LastRow`.
1410static PREFILL_GROUPED_ALL: std::sync::atomic::AtomicBool =
1411    std::sync::atomic::AtomicBool::new(false);
1412
1413pub fn set_prefill_grouped_all(on: bool) {
1414    PREFILL_GROUPED_ALL.store(on, std::sync::atomic::Ordering::Relaxed);
1415}
1416
1417fn prefill_grouped_all_on() -> bool {
1418    PREFILL_GROUPED_ALL.load(std::sync::atomic::Ordering::Relaxed)
1419}
1420
1421/// Allocation-stable decode step (perf lane item 2a — see `StepPool`). Default ON with
1422/// the interleaved A/B receipts in PROFILE-2.md; OFF reproduces the pooled-alloc
1423/// behavior exactly (`--ab-seam ws`).
1424static STEP_WS: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1425
1426pub fn set_step_ws(on: bool) {
1427    STEP_WS.store(on, std::sync::atomic::Ordering::Relaxed);
1428}
1429
1430fn step_ws_on() -> bool {
1431    STEP_WS.load(std::sync::atomic::Ordering::Relaxed)
1432}
1433
1434/// Decode-step CUDA graphs (perf lane item 2b — see `StepGraphs`). Replay is
1435/// bit-identical to the ws-eager path by construction (same kernels, same launch
1436/// parameters, same baked addresses, same order — only the CPU issue path changes), so
1437/// the graph A/B's rep-0 chains must be IDENTICAL, a stronger bar than the
1438/// accumulation-class seams. Requires the step workspace (item 2a); disabled while the
1439/// section profiler is on (sync boundaries cannot cross a replay) and during prefill
1440/// capture. Default ON with the PROFILE-2.md receipts; `--ab-seam graph`.
1441static DECODE_GRAPHS: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1442
1443pub fn set_decode_graphs(on: bool) {
1444    DECODE_GRAPHS.store(on, std::sync::atomic::Ordering::Relaxed);
1445}
1446
1447fn decode_graphs_on() -> bool {
1448    DECODE_GRAPHS.load(std::sync::atomic::Ordering::Relaxed)
1449}
1450
1451/// VERIFY scan-chain segment graphs (mtp9): the spec verify chunk's per-GDN-layer
1452/// {dwconv, t x (scan step + state snapshot), conv-history roll} run, captured once per
1453/// chunk width and replayed. Replay is bit-identical to the eager chain BY CONSTRUCTION
1454/// (same kernels, same launch parameters, same baked addresses, same order — only the CPU
1455/// issue path changes), so `--verify-bit-gate` must stay 24/24 and `--spec-gate` byte
1456/// identity must hold; those are the gates, not a tolerance.
1457///
1458/// **Default OFF, deliberately** (new-flags law): the trunk's own decode-graph receipt on
1459/// this box is +1.3% for an 84-graph, 2,400-launch reduction (PROFILE-2.md), so launch
1460/// issue is mostly overlapped here and the expected value is small. This seam exists to
1461/// MEASURE the one case the trunk receipt does not cover — a serially dependent chain,
1462/// where issue latency cannot overlap — and it flips only on its own interleaved A/B.
1463/// Requires the step workspace (address stability) and no section profiler (sync
1464/// boundaries cannot cross a replay).
1465static VERIFY_GRAPHS: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
1466
1467pub fn set_verify_graphs(on: bool) {
1468    VERIFY_GRAPHS.store(on, std::sync::atomic::Ordering::Relaxed);
1469}
1470
1471fn verify_graphs_on() -> bool {
1472    VERIFY_GRAPHS.load(std::sync::atomic::Ordering::Relaxed)
1473}
1474
1475/// v2 grouped sel matvec (perf lane item 3: PROFILE-1 residual §3 — the v1 kernel sits
1476/// at ~225-275 GB/s, scalar byte loads). Default ON with the PROFILE-2.md receipts; v1
1477/// stays the fallback for guarded geometry and the A/B twin (`--ab-seam selv2`).
1478/// NOTE: flipping this invalidates nothing structurally, but captured decode graphs
1479/// bake the kernel choice — the A/B harness allocates a fresh state per arm.
1480static SEL_V2: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1481
1482pub fn set_sel_v2(on: bool) {
1483    SEL_V2.store(on, std::sync::atomic::Ordering::Relaxed);
1484}
1485
1486fn sel_v2_on() -> bool {
1487    SEL_V2.load(std::sync::atomic::Ordering::Relaxed)
1488}
1489
1490/// v3 grouped sel matvec (perf round 3: PROFILE-2 residual — v2 sits at ~340-420 GB/s;
1491/// at the artifact's down geometry a v2 thread runs at most ONE strided iteration, so
1492/// the warp has almost no memory-level parallelism). v3 = 4 rows/warp sharing the
1493/// activation registers. Default ON with the round-3 receipts
1494/// (perf/ab-selv3-nvfp4.tsv: interleaved ×5, 17.06 → 16.57 ms mean-of-means, rep-0
1495/// chains identical); v2 stays the fallback for guarded geometry (out_f % 4 != 0) and
1496/// the A/B twin (`--ab-seam selv3`).
1497pub const SEL_V3_DEFAULT: bool = true;
1498static SEL_V3: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(SEL_V3_DEFAULT);
1499
1500pub fn set_sel_v3(on: bool) {
1501    SEL_V3.store(on, std::sync::atomic::Ordering::Relaxed);
1502}
1503
1504fn sel_v3_on() -> bool {
1505    SEL_V3.load(std::sync::atomic::Ordering::Relaxed)
1506}
1507
1508// ---- sel matvec SUB-WARP pair groups (`selgroup`, downsel lane mtp14) ------------------
1509//
1510// THE DEFECT, and why it is the priced-next lever in this section. v3/gufuse partition the
1511// pair loop over all 32 lanes (`for p = lane; p < pairs; p += 32`, `pairs = in_f/32`). At
1512// this artifact's geometry that does not fill a warp:
1513//
1514// | launch  | in_f            | pairs | lane occupancy                            |
1515// |---------|-----------------|-------|-------------------------------------------|
1516// | down    | expert ff 640   |    20 | 20/32 = **62.5%** (lanes 20-31 idle, ONE iteration each) |
1517// | gate+up | hidden 2560     |    80 | 80/96 = **83.3%** (3 warp iterations for 2.5 iterations of work) |
1518//
1519// KNEE:q4e-sel-slots-not-bytes measured that this section is per-SLOT-WORK bound, not
1520// weight-traffic bound (10 -> 60 slots costs 4.13x at fixed bytes; a 6x distinct-byte cut
1521// buys 1.101x, inside the instrument's own 8.6-11.7% spread). Idle lanes are exactly
1522// wasted per-slot work, so occupancy is where the section's time is.
1523//
1524// THE SHAPE. `qmatvec_nvfp4_modelopt_sel_g_f32` / `..._gu_silu_g_f32` make the pair loop a
1525// SUB-WARP of `g` lanes: the warp carries `32/g` groups, group `gi` owns `rows` consecutive
1526// output rows, and the reduce is log2(g) shfl steps inside the group. Rows per warp is
1527// `(32/g) * rows`, which is what the grid is tiled by. `(g=32, rows=4)` is the shipped v3 /
1528// gufuse program EXACTLY — byte-compared in `gate_nvfp4_sel_matvec`.
1529//
1530// **DEFAULT OFF at introduction, by design (new-flags law).** The ceiling is priced
1531// (research/qwen4exp-bringup-20260829/spec/downsel/DOWNSEL.md: recovering both kernels'
1532// idle lanes is worth ~5-7% of the K=5 round, 136.2 -> ~144-146 tok/s) and the exactness
1533// arms are green on the rig, but this lane had NO timing hardware — the rig is
1534// exactness-only (LAW:rig-gpu-exactness-only) and no cloud box was approved. A default
1535// flip needs the interleaved A/B rows the three OWED (scripted, none ran) cells in
1536// `spec/downsel/` produce; until those exist, ON would be an unmeasured default.
1537//
1538// Arm: `MEMRA_Q4E_SEAMS=selgroup` (both families AUTO). Per-family shapes for the A/B
1539// ladder: `selgroup=dn:4:1+gu:16:2`, `selgroup=dn:8:1+gu:off`, ... Roll back: `selgroup=0` (omitting the name arms AUTO since the 2026-09-02 default flip).
1540//
1541// AUTO derives the shape from the geometry rather than pinning a number, because the two
1542// families have different `pairs` and a single global shape would starve one of them:
1543// `g` = the largest power of two dividing `pairs`, and `rows` = 4 ALWAYS — the ladder
1544// inverted the first design here (rows_per_warp≈4 was BACKWARDS): rows-per-LANE is what
1545// pays, because one pair's activation float4 loads amortize across 4 independent rows'
1546// code loads, and arms that bought 100% occupancy by spending rows measured WORSE than
1547// the 62.5% kernel (gu (16,2): −12-14%; down (8,1): −27%; DOWNSEL.md §3). At the serving
1548// geometry AUTO resolves to **gu (g=16, rows=4)** and **down (g=4, rows=4)** — more rows
1549// per warp than the shipped kernels, fewer warps in the grid. That grid shrink is the one
1550// thing the box A/B has to check at t=1, where the down launch already runs only
1551// out_f/4 * selected warps.
1552// SCOPE (revuto, PR #27): the `dn` seam reaches ONLY `launch_nvfp4_sel_matvec`. The TP2
1553// seg-C tail has a third launcher, `launch_nvfp4_sel_matvec_pack` (below, ~L19840), which
1554// hardcodes `qmatvec_nvfp4_modelopt_sel_f32_v3c` and never reads the seam — while that
1555// same seg C's gate+up goes through the seam-aware `launch_nvfp4_sel_gu_silu`. Deliberate
1556// for now: TP2 is not the shipped route on this family (depth regression, receipts in
1557// ROUND-BUDGET-COMPOSITION.md) and the pack kernel's shape differs; if the EP2 lane
1558// revives a two-card route through seg C, extend the seam there THEN, with its own gate
1559// arm, rather than silently inheriting a shape never measured on the pack kernel.
1560// DEFAULT FLIPPED TO AUTO 2026-09-02 on box receipts (research/qwen4exp-bringup-20260829/spec/
1561// downsel/box/): cell B (K=5 spec A/B, serving caches q8_0/q5_1 + idxq q8, 5x64 interleaved,
1562// arm order flipped per hold, spec-vs-plain byte identity on every arm) auto vs off =
1563// 90.07/87.38, 90.60/87.14, 90.08/87.47 tok/s (+3.1/+4.0/+3.0%); cell C t=1 decode 32k
1564// 0.9999x/1.0001x, cell D 262k rung 1.0003x (5 reps each) — no depth regression. The
1565// pre-registered bar "gain > both arms' spread" was MISSED BY A HAIR on each hold (gain
1566// 2.9-3.8% vs spreads 2.3-4.0%) while the sign never flipped across six holds; the owner
1567// took the flip on that record (2026-09-02, PR #56). Rollback: `MEMRA_Q4E_SEAMS=selgroup=0`.
1568const SEL_GROUP_OFF: u32 = 0;
1569const SEL_GROUP_AUTO: u32 = 1;
1570/// Down-projection family (`launch_nvfp4_sel_matvec`).
1571static SEL_GROUP_DN: std::sync::atomic::AtomicU32 =
1572    std::sync::atomic::AtomicU32::new(SEL_GROUP_AUTO);
1573/// Fused gate+up+silu family (`launch_nvfp4_sel_gu_silu`).
1574static SEL_GROUP_GU: std::sync::atomic::AtomicU32 =
1575    std::sync::atomic::AtomicU32::new(SEL_GROUP_AUTO);
1576
1577fn sel_group_dn() -> u32 {
1578    SEL_GROUP_DN.load(std::sync::atomic::Ordering::Relaxed)
1579}
1580
1581fn sel_group_gu() -> u32 {
1582    SEL_GROUP_GU.load(std::sync::atomic::Ordering::Relaxed)
1583}
1584
1585/// The seam's current spec, in the grammar `set_sel_group` accepts — for exact
1586/// save/restore around an A/B that flips it (`seam_state` cannot carry it: this seam is not
1587/// boolean, like `idxq`).
1588pub fn sel_group_spec() -> String {
1589    let one = |c: u32| -> String {
1590        match c {
1591            SEL_GROUP_OFF => "off".to_string(),
1592            SEL_GROUP_AUTO => "auto".to_string(),
1593            v => format!("{}:{}", (v >> 8) & 0xff, v & 0xff),
1594        }
1595    };
1596    format!("dn:{}+gu:{}", one(sel_group_dn()), one(sel_group_gu()))
1597}
1598
1599/// Parse and apply the `selgroup` seam value. Grammar (no commas — `MEMRA_Q4E_SEAMS`
1600/// splits on them):
1601///
1602/// - `0` / `off` — both families OFF (the shipped v3 / gufuse kernels).
1603/// - `` (bare) / `auto` / `1` — both families AUTO.
1604/// - `dn:<spec>` / `gu:<spec>` joined by `+`, where `<spec>` is `off`, `auto`, or
1605///   `<g>:<rows>` with `g` a power of two in [1,32] and `rows` in {1,2,4}.
1606///
1607/// Returns false (applying nothing) on a malformed spec, so a typo in a cell script fails
1608/// the seam-name check instead of silently measuring the default arm.
1609pub fn set_sel_group(spec: &str) -> bool {
1610    let parse_one = |s: &str| -> Option<u32> {
1611        match s {
1612            "off" | "0" => Some(SEL_GROUP_OFF),
1613            "auto" | "1" | "" => Some(SEL_GROUP_AUTO),
1614            other => {
1615                let (g, rows) = other.split_once(':')?;
1616                let g: u32 = g.parse().ok()?;
1617                let rows: u32 = rows.parse().ok()?;
1618                if !matches!(g, 1 | 2 | 4 | 8 | 16 | 32) || !matches!(rows, 1 | 2 | 4) {
1619                    return None;
1620                }
1621                Some((g << 8) | rows)
1622            }
1623        }
1624    };
1625    if let Some(both) = parse_one(spec) {
1626        SEL_GROUP_DN.store(both, std::sync::atomic::Ordering::Relaxed);
1627        SEL_GROUP_GU.store(both, std::sync::atomic::Ordering::Relaxed);
1628        return true;
1629    }
1630    let mut dn = None;
1631    let mut gu = None;
1632    for part in spec.split('+').filter(|p| !p.is_empty()) {
1633        let Some((family, rest)) = part.split_once(':') else {
1634            return false;
1635        };
1636        let Some(code) = parse_one(rest) else {
1637            return false;
1638        };
1639        match family {
1640            "dn" | "down" => dn = Some(code),
1641            "gu" | "gateup" => gu = Some(code),
1642            _ => return false,
1643        }
1644    }
1645    if dn.is_none() && gu.is_none() {
1646        return false;
1647    }
1648    if let Some(c) = dn {
1649        SEL_GROUP_DN.store(c, std::sync::atomic::Ordering::Relaxed);
1650    }
1651    if let Some(c) = gu {
1652        SEL_GROUP_GU.store(c, std::sync::atomic::Ordering::Relaxed);
1653    }
1654    true
1655}
1656
1657/// Resolve a family's seam code to a concrete `(g, rows)` for THIS launch's geometry, or
1658/// `None` to take the shipped kernel. Every geometry that the sub-warp form cannot tile
1659/// exactly falls back rather than clamping: groups inside one warp have different `o0`, so
1660/// a ragged tile would put lanes with live and dead rows in the same `__shfl_down_sync`.
1661fn sel_group_resolve(code: u32, in_f: usize, out_f: usize) -> Option<(usize, usize)> {
1662    if code == SEL_GROUP_OFF || in_f % 32 != 0 {
1663        return None;
1664    }
1665    let pairs = in_f / 32;
1666    if code != SEL_GROUP_AUTO {
1667        let (g, rows) = (((code >> 8) & 0xff) as usize, (code & 0xff) as usize);
1668        if !matches!(g, 1 | 2 | 4 | 8 | 16 | 32) || !matches!(rows, 1 | 2 | 4) {
1669            return None;
1670        }
1671        if out_f % ((32 / g) * rows) != 0 {
1672            return None;
1673        }
1674        return Some((g, rows));
1675    }
1676    // AUTO. Largest power-of-two lane group that divides `pairs` exactly (100% lane
1677    // occupancy); the chain is monotone (2^k | pairs implies 2^(k-1) | pairs), so the first
1678    // miss ends it.
1679    let mut g = 1usize;
1680    for cand in [2usize, 4, 8, 16, 32] {
1681        if pairs % cand != 0 {
1682            break;
1683        }
1684        g = cand;
1685    }
1686    // `rows` (rows per LANE) is held at 4, and that is the measured shape rule rather than
1687    // an arbitrary pick — an earlier AUTO derived `rows` from `g` so that `rows_per_warp`
1688    // stayed at the shipped 4, and the ladder says that rule is BACKWARDS. Rows per LANE is
1689    // what pays, not lane occupancy alone: v3's body exists to share one pair's 8 activation
1690    // float4 loads across 4 rows and keep 4 independent uint4 code loads in flight, and an
1691    // arm that reaches 100% lane occupancy by SPENDING rows-per-lane loses that and measures
1692    // WORSE than the shipped kernel (gate+up g=16 rows=2 -> 100% lanes but ~12% slower;
1693    // down g=8 rows=1 -> flat). Filling the lanes is only worth doing at rows=4.
1694    // Rows per warp therefore GROWS to (32/g)*4, which costs warp count — the thing the
1695    // box cell has to confirm, since these rows were taken on the rig for DIRECTION only
1696    // (research/qwen4exp-bringup-20260829/spec/downsel/DOWNSEL.md §4).
1697    let mut rows = 4usize;
1698    while rows > 1 && out_f % ((32 / g) * rows) != 0 {
1699        rows /= 2;
1700    }
1701    let rows_per_warp = (32 / g) * rows;
1702    if out_f % rows_per_warp != 0 {
1703        return None;
1704    }
1705    Some((g, rows))
1706}
1707
1708/// Read/write-gate micro bundle (perf lane, after items 1-3 the residue is EXECUTION):
1709/// batched per-stream gate norms (384 one-block launches → 96 stream-batched), the
1710/// two-stage inject (the single-stage kernel ran 4 blocks on a 188-SM card), slab gate
1711/// writes (kills 384 add_scaled_rows + 384 inject-row d2d copies per token), and bf16
1712/// residency for the shared-expert mats (~2.5 GB/token of f32 reads). Default ON with
1713/// the PROFILE-2.md receipts; OFF is the exact item-3-era composition (`--ab-seam
1714/// hcmicro`).
1715static HC_MICRO: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1716
1717pub fn set_hc_micro(on: bool) {
1718    HC_MICRO.store(on, std::sync::atomic::Ordering::Relaxed);
1719}
1720
1721fn hc_micro_on() -> bool {
1722    HC_MICRO.load(std::sync::atomic::Ordering::Relaxed)
1723}
1724
1725/// GDN decode-step scan twin (perf round 3: PROFILE-2 residual — `gdn_scan_naive_f32`
1726/// at t=1 runs `nv` blocks (48) with the whole state row per thread in registers,
1727/// latency-bound). The twin launches grid (nv, hv) with one state ELEMENT per thread;
1728/// same per-element math, block reduction trees instead of sequential row sums — the
1729/// accumulation class, gated by `gate_gdn_step_kernels` + the real gates. Default ON
1730/// with the round-3 receipts (perf/ab-gdnstep-nvfp4.tsv: interleaved ×5, 16.59 → 15.60
1731/// ms mean-of-means, rep-0 chains identical); the naive kernel stays the prefill
1732/// executor, the tiny-geometry fallback (hk % 32 != 0), and the A/B twin
1733/// (`--ab-seam gdnstep`).
1734pub const GDN_STEP_DEFAULT: bool = true;
1735static GDN_STEP: std::sync::atomic::AtomicBool =
1736    std::sync::atomic::AtomicBool::new(GDN_STEP_DEFAULT);
1737
1738pub fn set_gdn_step(on: bool) {
1739    GDN_STEP.store(on, std::sync::atomic::Ordering::Relaxed);
1740}
1741
1742fn gdn_step_on() -> bool {
1743    GDN_STEP.load(std::sync::atomic::Ordering::Relaxed)
1744}
1745
1746/// GDN norm+gate fusion (perf round 3): `rms_sigmul_f32` folds the mixer's rms_norm +
1747/// sigmoid + mul chain into one launch — rms_norm_f32-verbatim reduction, sigmoid_f32
1748/// gate, no contraction seam, so BIT-IDENTICAL to the chain (asserted exactly by
1749/// `gate_gdn_step_kernels`). Sigmoid gate arm only; Silu keeps the chain. Default ON
1750/// with the round-3 receipts (perf/ab-gdnfuse-nvfp4.tsv: interleaved ×5, 16.65 → 16.52
1751/// ms mean-of-means, rep-0 chains identical; small but real, and the kernel is
1752/// bit-identical to the chain it replaces); `--ab-seam gdnfuse`.
1753pub const GDN_FUSE_DEFAULT: bool = true;
1754static GDN_FUSE: std::sync::atomic::AtomicBool =
1755    std::sync::atomic::AtomicBool::new(GDN_FUSE_DEFAULT);
1756
1757pub fn set_gdn_fuse(on: bool) {
1758    GDN_FUSE.store(on, std::sync::atomic::Ordering::Relaxed);
1759}
1760
1761fn gdn_fuse_on() -> bool {
1762    GDN_FUSE.load(std::sync::atomic::Ordering::Relaxed)
1763}
1764
1765/// Projection stack (perf round 4): same-activation trunk projections that ran as
1766/// separate `qmatvec_bf16w_f32` launches — GDN qkv/z/beta/alpha (4), QSA wq/wk/wv (3),
1767/// shared-expert gate/up (2) — collapse into ONE `qmatvec_bf16w_multi4_f32` launch over
1768/// a load-time row-stacked bf16 twin, each output row routed to its original slot buffer
1769/// by row range. Per-row math is the bf16w kernel VERBATIM, so outputs are BIT-IDENTICAL
1770/// to the per-mat launches; decode only (t == 1), requires the bf16 trunk seam. Default
1771/// ON with the round-4 receipts (perf20/ab-projstack-nvfp4.tsv: interleaved x5,
1772/// 15.72 -> 15.25 ms mean-of-means, rep-0 chains IDENTICAL; tiny gate ON/OFF receipts
1773/// byte-identical; real gate r4-on: argmax 10/10, greedy forks unchanged, tp2-gate
1774/// 24/24); the per-mat row-offset-view launches stay the OFF arm; `--ab-seam projstack`.
1775pub const PROJ_STACK_DEFAULT: bool = true;
1776static PROJ_STACK: std::sync::atomic::AtomicBool =
1777    std::sync::atomic::AtomicBool::new(PROJ_STACK_DEFAULT);
1778
1779pub fn set_proj_stack(on: bool) {
1780    PROJ_STACK.store(on, std::sync::atomic::Ordering::Relaxed);
1781}
1782
1783fn proj_stack_on() -> bool {
1784    PROJ_STACK.load(std::sync::atomic::Ordering::Relaxed)
1785}
1786
1787/// Hyper-gate diet (perf round 4): the read gate's 7-launch serial chain (norm, batched
1788/// down GEMV, lowrank reduce, batched up GEMV, mix epilogue, inject partials + reduce)
1789/// re-fuses into THREE launches at t == 1 — stage 1 (per-stream RMS recompute + normed
1790/// smem row + down/inject rows), stage 2 (silu mean + inject sigmoid), stage 3 (up dots +
1791/// mix epilogue from the stage-1 inv scalars). ACCUMULATION CLASS (new reduce widths);
1792/// gated by `gate_hc_diet_kernels` (real geometry vs the classic fused chain) + the real
1793/// gates. Requires the bf16 trunk twins + hcmicro inject posture (the Slab inject form);
1794/// geometry guards hidden % 8 == 0 && rank % 8 == 0 (tiny plans fall back). Default ON
1795/// with the round-4 receipts (perf20/ab-hcdiet-nvfp4.tsv: interleaved x5, 15.69 ->
1796/// 15.32 ms mean-of-means, rep-0 chains IDENTICAL; oracle arm 0e worst rel 2.369e-6;
1797/// real gate r4-on: argmax 10/10, greedy forks unchanged, tp2-gate 24/24); the fused
1798/// chain stays the OFF arm; `--ab-seam hcdiet`.
1799pub const HC_DIET_DEFAULT: bool = true;
1800static HC_DIET: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(HC_DIET_DEFAULT);
1801
1802pub fn set_hc_diet(on: bool) {
1803    HC_DIET.store(on, std::sync::atomic::Ordering::Relaxed);
1804}
1805
1806fn hc_diet_on() -> bool {
1807    HC_DIET.load(std::sync::atomic::Ordering::Relaxed)
1808}
1809
1810/// Fused gate+up+silu sel matvec (perf round 4, post the W4A4 owner retirement — the
1811/// activation-precision-NEUTRAL half of the sel lever): the MoE tail's gate launch +
1812/// up launch + silu launch collapse into ONE `qmatvec_nvfp4_modelopt_sel_gu_silu_f32`
1813/// (each warp runs 4 gate + 4 up rows off shared f32 activation registers; per-row
1814/// arithmetic v3-VERBATIM, epilogue silu_mul_f32-VERBATIM => BIT-IDENTICAL to the
1815/// chain, asserted by the sel oracle's gufuse mode). Cuts the sel serial chain 5 -> 3
1816/// launches and doubles outstanding code loads per warp (the slice is latency-bound at
1817/// ~27% of card bandwidth — PROFILE-4 re-profile). Geometry in_f % 32 == 0 &&
1818/// ff % 4 == 0, else the v3 chain. Default ON with the round-4 receipts
1819/// (perf24/ab-gufuse-nvfp4{,-tp2}.tsv: interleaved x5, single 14.75 -> 14.58, TP2
1820/// route 13.43 -> 13.10, rep-0 chains IDENTICAL both configs; oracle gufuse mode
1821/// asserts byte identity incl. the count-gated pack twin); `--ab-seam gufuse`.
1822pub const SEL_GUFUSE_DEFAULT: bool = true;
1823static SEL_GUFUSE: std::sync::atomic::AtomicBool =
1824    std::sync::atomic::AtomicBool::new(SEL_GUFUSE_DEFAULT);
1825
1826pub fn set_sel_gufuse(on: bool) {
1827    SEL_GUFUSE.store(on, std::sync::atomic::Ordering::Relaxed);
1828}
1829
1830fn sel_gufuse_on() -> bool {
1831    SEL_GUFUSE.load(std::sync::atomic::Ordering::Relaxed)
1832}
1833
1834/// Verify multi-token WEIGHT-SHARED kernels (mtp-spec): trunk dense mats run
1835/// `qmatvec_bf16w_mt_f32` (one block per output row, W read ONCE for every verify
1836/// column — the qwen38 t-parallel pattern) and the MoE verify columns merge into ONE
1837/// grouped launch per projection via the gufuse tok_map. Every per-(row,token) fma
1838/// chain is the t == 1 program VERBATIM => rows stay BIT-IDENTICAL to per-token
1839/// launches (asserted by the bf16-matvec oracle's mt mode and the verify-bit gate);
1840/// only weight-read counts and launch counts drop. Engages ONLY at 2 <= t <= 12 exact
1841/// chunks (plain decode and prefill untouched). Default ON with the mtp-spec lane's
1842/// receipts (spec/MTP-SPEC.md: verify-bit-gate bit-identity + interleaved spec A/B);
1843/// OFF twin = the per-token grid path, `--ab-seam vmt`.
1844pub const VERIFY_MT_DEFAULT: bool = true;
1845static VERIFY_MT: std::sync::atomic::AtomicBool =
1846    std::sync::atomic::AtomicBool::new(VERIFY_MT_DEFAULT);
1847
1848pub fn set_verify_mt(on: bool) {
1849    VERIFY_MT.store(on, std::sync::atomic::Ordering::Relaxed);
1850}
1851
1852fn verify_mt_on() -> bool {
1853    VERIFY_MT.load(std::sync::atomic::Ordering::Relaxed)
1854}
1855
1856/// FUSED verify program (`vfuse`, mtp12 cost lane): route a `1 < t <= k_cap` verify chunk
1857/// through the FUSED (prefill-style) program instead of the EXACT per-row programs.
1858///
1859/// **This is a COST INSTRUMENT, not a serving arm, and it is default OFF forever unless a
1860/// receipt moves it** (new-flags law). What it changes and what it cannot:
1861///
1862/// - Changes (the only sections where exact and fused differ): trunk dense mats
1863///   (`qmatvec_bf16w_mt` W-once → cuBLASLt m=t), the hyper read gate (hc-diet MT 3-launch
1864///   → the t-generic fused chain), the GDN scan (per-column `gdn_scan_step_at` + snapshots
1865///   → chunk scan), the QSA indexer projection and the PLE projections (t × m=1 → 1 × m=t).
1866/// - Cannot change, BY CONSTRUCTION: the MoE routed union (already ONE grouped gufuse
1867///   launch over every column on the exact arm — this seam FORCES `grouped` so the fused
1868///   chunk does not fall into the per-expert prefill executor, which costs minutes/chunk),
1869///   `sdpa_naive_mask` (same kernel both arms), and the ~12 ms/round of per-layer HOST
1870///   TWIN bubbles (48 MoE router dtoh + 12 QSA indexer masks are PER CHUNK, not per
1871///   column, so a fused chunk pays them identically).
1872///
1873/// **No rewind exists on this arm.** The exact program stashes per-column GDN recurrent
1874/// state and PLE segment state so `verify_rewind` can drop rejected columns replay-free;
1875/// the fused chunk scan materializes only the final state, so `verify_rewind` refuses
1876/// loudly (`vfuse_chunk`) rather than silently rewinding to a wrong state. That is why the
1877/// seam is a timing probe on a throwaway state and NOT wired into `spec_generate`.
1878pub const VERIFY_FUSED_DEFAULT: bool = false;
1879static VERIFY_FUSED: std::sync::atomic::AtomicBool =
1880    std::sync::atomic::AtomicBool::new(VERIFY_FUSED_DEFAULT);
1881
1882pub fn set_verify_fused(on: bool) {
1883    VERIFY_FUSED.store(on, std::sync::atomic::Ordering::Relaxed);
1884}
1885
1886pub fn verify_fused_on() -> bool {
1887    VERIFY_FUSED.load(std::sync::atomic::Ordering::Relaxed)
1888}
1889
1890/// Router bf16 residency (perf round 4): the MoE router GEMV was the last dense trunk
1891/// mat still on f32 cuBLASLt (the TP2 nsys counts it among the ~70 f32 gemvx
1892/// calls/token). Same guards and arithmetic class as the trunk seam (exact bf16
1893/// widening, accumulation-class reduction change — routing near-ties are gated by the
1894/// real gate's argmax/greedy battery). Default ON with the round-4 receipts
1895/// (perf24/ab-routerb16-nvfp4{,-tp2}.tsv: interleaved x5, single 14.75 -> 14.68, TP2
1896/// route 13.47 -> 13.36, rep-0 chains IDENTICAL; decode-row seam-gate 24/24 argmax,
1897/// worst KL 0.00116 — the trunk accumulation class); `--ab-seam routerb16`.
1898pub const ROUTER_B16_DEFAULT: bool = true;
1899static ROUTER_B16: std::sync::atomic::AtomicBool =
1900    std::sync::atomic::AtomicBool::new(ROUTER_B16_DEFAULT);
1901
1902pub fn set_router_bf16(on: bool) {
1903    ROUTER_B16.store(on, std::sync::atomic::Ordering::Relaxed);
1904}
1905
1906fn router_bf16_on() -> bool {
1907    ROUTER_B16.load(std::sync::atomic::Ordering::Relaxed)
1908}
1909
1910/// Gate/battery instrumentation: apply `MEMRA_Q4E_SEAMS` ("name" or "name=0", comma
1911/// separated) to the seam setters, so the tiny + real gates can prove a NEW seam green
1912/// while its shipped default is still OFF (flags law: correctness receipts precede the
1913/// default flip). Names match the `--ab-seam` vocabulary.
1914/// The masked SDPA kernel's smem score bound in KV tokens (48 KB of f32 scores). Past
1915/// this the dense-mask path is impossible; the block-list kernel takes over.
1916const SDPA_MASK_TKV_BOUND: usize = 12288;
1917
1918/// Device QSA indexer block scorer (long-context lane). Default ON: scores are
1919/// BIT-IDENTICAL to the host twin (same dim order, relu-sum and division), the host twin
1920/// stays the reference/TP2 path, and the host cost it replaces is O(context) per token
1921/// per layer — 52% of the decode token at a 32k fill and quadratic across a long
1922/// prefill (receipts in research/qwen4exp-bringup-20260829/yarn/). Rollback:
1923/// `MEMRA_Q4E_SEAMS=idxdev=0`.
1924static IDX_DEV: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1925fn idx_dev_on() -> bool {
1926    IDX_DEV.load(std::sync::atomic::Ordering::Relaxed)
1927}
1928pub fn set_idx_dev(on: bool) {
1929    IDX_DEV.store(on, std::sync::atomic::Ordering::Relaxed);
1930}
1931
1932/// Device QSA indexer top-k SELECTION (262k perf lane, `qsa_index_topk_u32`). The
1933/// `idxdev` seam above moved the block SCORING to the GPU and then dtoh'd the whole score
1934/// slab so the HOST could run `top_blocks_ascending` per row. At the product window that
1935/// host half is the wall: at a 131,072 fill `qsa.idx_host` measured **51,235 ms — 83% of a
1936/// prefill chunk** while every GPU section stayed flat within 4%, and it is what prices the
1937/// whole 262k window down from ~32 to ~15-18 tok/s
1938/// (research/qwen4exp-bringup-20260829/round2-box-receipts/LADDER.md §4c). This seam runs
1939/// the selection on device and reads back `rows x budget` u32 instead of `rows x blocks`
1940/// f32 (4 MB instead of up to 128 MB per sub-batch).
1941///
1942/// Selection is EXACT by construction, not by tolerance: the kernel's u64 key orders
1943/// ascending exactly as the host `sel_cmp` (score desc under `total_cmp`, block index asc)
1944/// over the whole f32 domain, keys are distinct, and the emitted order is ascending block
1945/// index. Gated by `gate_qsa_index_topk` (real geometry + tie batteries incl. the
1946/// structural all-zero-score class) and by the live cross-surface audit
1947/// `MEMRA_Q4E_IDXSEL_AUDIT=1`, which recomputes the host twin from the SAME slab and
1948/// hard-compares ids AND order.
1949///
1950/// **Default ON (2026-09-01), FLIPPED on receipts** (new-flags law: a default is a decision
1951/// with its reasons and receipts stated, and it flips only once both arms are measured).
1952/// Introduced default OFF the day before; the flip carries:
1953///
1954/// - **Interleaved same-fill A/B at 131,072** (`--ladder-ab-seam idxsel`, both arms on ONE
1955///   prefill, exclusive measurement lock, sole tenant): off 56.64 ms / 17.66 tok/s vs on
1956///   32.25 ms / 31.01 tok/s = **1.7562x**, 7 reps per arm (escalated from 5), 224 warm
1957///   samples per arm, within-arm spreads 2.40% / 2.12% — the verdict is ~18x the pooled
1958///   spread. Reproduces the independent two-process pair (1.76x) on both arms.
1959/// - **The target window**: 262,144 tokens goes **15.21 -> 23.44 tok/s (1.54x)** with the
1960///   prefill wall **4,779.1 -> 1,439.2 s (3.32x)**, spread 2.56% (escalated x5) -> 0.30%.
1961/// - **The cliff is gone**: 100,000 -> 131,072 was 1.9x slower for 1.31x depth; it is now
1962///   -7.6%, and prefill per chunk is flat across a continuous 262k fill (82.8 -> 96.4 s per
1963///   16k, where the OFF arm stepped 105 -> 475).
1964/// - **Exactness**: tie-battery oracle EXACT on ids AND order at real budget 512 up to
1965///   65,536 blocks, on BOTH card classes; live at-depth audit **1,549,452 rows / 0
1966///   mismatches / deepest_blocks 32,793**; decode-row-volume audit **120,000 decode-row
1967///   selections / 0 mismatches**; greedy chain byte-identical across the seam at a
1968///   100,000-token fill; all four rule gates green and identical to the prior battery.
1969/// - **Variance improves too**: both deep rungs auto-escalated to x5 on the OFF arm (2.74% /
1970///   1.62%) and sit at 0.36% / 0.02% with the seam on — the 48-thread host top-k pool was
1971///   also the jitter source.
1972///
1973/// Rollback: `MEMRA_Q4E_SEAMS=idxsel=0` (the pure host top-k over the dtoh'd slab). Unlike
1974/// the devtwin pair, this seam has NO pairing requirement — it wins alone on every measured
1975/// surface and it is measured on top of the shipped `routerdev` + `idxcache` + `kvq` stack.
1976/// Receipts: research/qwen4exp-bringup-20260829/perf/PROFILE-11.md.
1977pub const IDX_SEL_DEFAULT: bool = true;
1978static IDX_SEL: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(IDX_SEL_DEFAULT);
1979fn idx_sel_on() -> bool {
1980    IDX_SEL.load(std::sync::atomic::Ordering::Relaxed)
1981}
1982pub fn set_idx_sel(on: bool) {
1983    IDX_SEL.store(on, std::sync::atomic::Ordering::Relaxed);
1984}
1985/// INCREMENTAL PLE n-gram id cache (262k perf lane, `plecache`). `ple_block` calls
1986/// `host_ngram_ids`, a `ngram_ids` twin over the FULL token history, and then slices the last
1987/// `t` rows — so a decode step at a 150,000-token fill rebuilds 150,000 rows of hashes to
1988/// consume ONE. Measured on the deep decode profile with `idxsel` armed:
1989/// `ple.host_ngram_gather` is **7.3 ms, 19.5% of the token**, second only to `qsa.sdpa` and
1990/// the largest remaining HOST section (PROFILE-11 §5).
1991///
1992/// This is the correction the deep profile forced on the owner's stated prefetch lever, and
1993/// it is worth stating rather than quietly fixing: the assumed mechanism was "the gather from
1994/// the 102 GB host table is synchronous, so overlap it with compute". The gather itself is
1995/// `t * 16` random rows — 16 reads of 160 f32 at decode, microseconds. The 7.3 ms is the
1996/// O(context) ID RECOMPUTE in front of it. Async-prefetching the table would have bought
1997/// ~nothing; caching the ids removes essentially all of it. Same class as the yarn lane's
1998/// O(context) host selection, in a different section.
1999///
2000/// Exact by construction (see `host_ngram_ids_cached`): `ids[token]` is a pure function of
2001/// `token_ids[..=token]`, so the cache appends and never recomputes. Divergence and rewind
2002/// are handled by a real longest-common-PREFIX compare, not a length compare.
2003///
2004/// **Default ON as of 2026-09-01, by design** (new-flags law: the decision and its reasons are
2005/// written, and the receipts landed before the flip). Introduced default OFF on 2026-08-31 with
2006/// no perf receipts; flipped after the A/B and the exactness battery below. Rollback is one
2007/// token: `MEMRA_Q4E_SEAMS=plecache=0`.
2008///
2009/// PERFORMANCE — x3 interleaved, both arms sharing one prefill and one exclusive lock hold, lead
2010/// flipped on odd reps, no escalation owed on any arm (PROFILE-12 §2, §10):
2011///
2012/// | depth | OFF | ON | speedup | this section, OFF arm |
2013/// |---|---|---|---|---|
2014/// | 131,072 | 33.52 ms / 29.83 tok/s | 25.91 ms / 38.60 tok/s | 1.2938x | 7.8 ms (20.3%) |
2015/// | 262,144 | 41.38 ms / 24.17 tok/s | 28.30 ms / 35.34 tok/s | **1.4620x** | **13.2 ms (28.9%)** |
2016///
2017/// The gain GROWS with depth because the deleted work is O(fill) per token, and at the target
2018/// window this was **the largest section of the whole token**, ahead of `qsa.sdpa`. With the seam
2019/// armed it leaves the top twelve entirely while every other section holds to a tenth of a
2020/// millisecond. It also removes decode JITTER: cv 2.48% -> 0.11% at 131,072, p99 41.70 -> 28.38 ms
2021/// at 262,144 — a p99-latency result, which is what a deep-context agentic workload feels.
2022///
2023/// EXACTNESS — the flip rests on the two arms that can actually falsify it, not on the many that
2024/// cannot:
2025/// - **Real-geometry truth pin** (`MEMRA_Q4E_PLECACHE_AUDIT=1`): `rows=32828 mismatched=0
2026///   deepest_fill=32828`. Cached ids hard-compared against the full `host_ngram_ids` twin at the
2027///   CHECKPOINT's own multipliers/sizes/offsets, over both growth shapes (2,048-token prefill
2028///   chunks and one-at-a-time decode appends).
2029/// - **Behavioural control**: the greedy chain is IDENTICAL across the seam on the same artifact
2030///   (`-1/0/-1/26` both arms, hidden-goldens argmax 10/10 both arms).
2031/// - Host oracle vs the full twin: EXACT over 69,635 cumulative-sequence comparisons across 6 case
2032///   families (decode growth, ragged prefill chunks, eos resets incl. adjacent/leading/trailing,
2033///   all-eos, repeated rewinds to DIVERGING prefixes, shorter-unrelated-sequence state reuse).
2034/// - `verify-bit` 24 `mismatched=0 policy=bit-identity`; spec byte-identity 256
2035///   `policy=byte-identity pass=true` with `first_divergence=-1` on all four prompts.
2036///
2037/// **Why those last two carry less weight than they look like they do, stated so the flip is not
2038/// over-credited:** `verify-bit` and spec byte-identity are INTRA-ARM, and an intra-arm identity
2039/// gate cannot detect a CONSISTENT error — a uniformly-wrong id set is perfectly self-consistent
2040/// and passes both with full marks. The truth pin and the greedy control are what close it.
2041///
2042/// STILL OWED (PROFILE-12 §9): `--verify-bit-deep 131072` with the seam armed has not passed — it
2043/// failed three times on this box with ~96 GB free, i.e. on the instrument rather than on the seam.
2044/// It is intra-arm, so it cannot add exactness assurance the truth pin does not already give; the
2045/// flip does not wait on it, and it stays owed rather than being quietly dropped.
2046///
2047/// COST: one `i64` id vector per state, `fill * 16 * 8` bytes = 33.5 MB of HOST memory at 262,144
2048/// (the box carries 499 GB), plus the token-history mirror. No device memory, no new kernel.
2049pub const PLE_CACHE_DEFAULT: bool = true;
2050static PLE_CACHE: std::sync::atomic::AtomicBool =
2051    std::sync::atomic::AtomicBool::new(PLE_CACHE_DEFAULT);
2052fn ple_cache_on() -> bool {
2053    PLE_CACHE.load(std::sync::atomic::Ordering::Relaxed)
2054}
2055pub fn set_ple_cache(on: bool) {
2056    PLE_CACHE.store(on, std::sync::atomic::Ordering::Relaxed);
2057}
2058/// Live cross-surface audit for the PLE id cache (`MEMRA_Q4E_PLECACHE_AUDIT=1`): recompute
2059/// the FULL `host_ngram_ids` twin and hard-compare the chunk's rows against the cached ones.
2060/// Instrument only — it restores exactly the O(context) work the seam deletes.
2061fn ple_cache_audit_on() -> bool {
2062    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2063    *C.get_or_init(|| std::env::var("MEMRA_Q4E_PLECACHE_AUDIT").as_deref() == Ok("1"))
2064}
2065static PLE_CACHE_AUDIT_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2066static PLE_CACHE_AUDIT_MISMATCH: std::sync::atomic::AtomicU64 =
2067    std::sync::atomic::AtomicU64::new(0);
2068static PLE_CACHE_AUDIT_MAX_FILL: std::sync::atomic::AtomicU64 =
2069    std::sync::atomic::AtomicU64::new(0);
2070/// (rows audited, id mismatches, deepest history length seen) since process start.
2071pub fn ple_cache_audit_stats() -> (u64, u64, u64) {
2072    (
2073        PLE_CACHE_AUDIT_ROWS.load(std::sync::atomic::Ordering::Relaxed),
2074        PLE_CACHE_AUDIT_MISMATCH.load(std::sync::atomic::Ordering::Relaxed),
2075        PLE_CACHE_AUDIT_MAX_FILL.load(std::sync::atomic::Ordering::Relaxed),
2076    )
2077}
2078
2079/// Live device-vs-host indexer-selection audit (`MEMRA_Q4E_IDXSEL_AUDIT=1`): every device
2080/// selection ALSO dtohs the score slab and runs `top_blocks_ascending` on the same bytes,
2081/// hard-comparing the block ids AND their emitted order. Instrument only — it restores the
2082/// very dtoh this seam deletes, so it is never a perf arm. Counters feed the receipt
2083/// (`idx_sel_audit_stats`); `rows=0` is the silent-no-op failure the counter exists to
2084/// catch.
2085fn idx_sel_audit_on() -> bool {
2086    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2087    *C.get_or_init(|| std::env::var("MEMRA_Q4E_IDXSEL_AUDIT").as_deref() == Ok("1"))
2088}
2089static IDX_SEL_AUDIT_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2090static IDX_SEL_AUDIT_MISMATCH: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2091static IDX_SEL_AUDIT_MAX_BLOCKS: std::sync::atomic::AtomicU64 =
2092    std::sync::atomic::AtomicU64::new(0);
2093/// (rows audited, selection mismatches, deepest block count seen) since process start.
2094pub fn idx_sel_audit_stats() -> (u64, u64, u64) {
2095    (
2096        IDX_SEL_AUDIT_ROWS.load(std::sync::atomic::Ordering::Relaxed),
2097        IDX_SEL_AUDIT_MISMATCH.load(std::sync::atomic::Ordering::Relaxed),
2098        IDX_SEL_AUDIT_MAX_BLOCKS.load(std::sync::atomic::Ordering::Relaxed),
2099    )
2100}
2101
2102/// Device MoE router (devtwin lane): `qwen4exp_route_topk_f32` replaces the per-layer
2103/// router dtoh + `host_route_softmax_topk` + selection h2d — the census's 48 blocking
2104/// drains per forward and the round-3 doctrine's whole-step-graph blocker. Engages on
2105/// the GROUPED dispatch paths only (NVFP4 t==1 decode / verify columns / graph-driver
2106/// slots); the per-expert prefill executor and the TP2 route keep the host twin (they
2107/// consume host expert ids by construction). Selection set + order are gated EXACTLY
2108/// against the host twin (gate_route_kernel + MEMRA_Q4E_ROUTER_AUDIT); weights within
2109/// documented ULP (exp is the one non-bit-pinned op — kernel doc).
2110///
2111/// **Default ON (2026-08-31), decided on receipts** (better-wins-by-default): the
2112/// combined devtwin stack wins every measured surface — spec at ship admission thinkon
2113/// 1.168x / thinkoff 1.174x / efflow 1.160x / raw 1.194x / long-724 1.116x with
2114/// BYTE-IDENTICAL 256-token chains, K ladder 1.14-1.18x over K=1..8, plain decode
2115/// 1.099x with decode graphs ON and 1.112x with them OFF — under all three rule gates
2116/// green (verify-bit 24/24, spec-gate byte identity, tp2-gate) plus a 250k-row live
2117/// host-twin audit with ZERO selection mismatches. **Pair with `idxcache`: this seam
2118/// ALONE with decode graphs ON measured 0.906x** (PROFILE-9 §3/§3a) — the stack is the
2119/// unit, which is why both defaults flip together. Rollback:
2120/// `MEMRA_Q4E_SEAMS=routerdev=0`.
2121pub const ROUTER_DEV_DEFAULT: bool = true;
2122static ROUTER_DEV: std::sync::atomic::AtomicBool =
2123    std::sync::atomic::AtomicBool::new(ROUTER_DEV_DEFAULT);
2124fn router_dev_on() -> bool {
2125    ROUTER_DEV.load(std::sync::atomic::Ordering::Relaxed)
2126}
2127pub fn set_router_dev(on: bool) {
2128    ROUTER_DEV.store(on, std::sync::atomic::Ordering::Relaxed);
2129}
2130/// The device router's geometry envelope: register top-k (<= 32 slots) + smem softmax
2131/// slab (experts f32 <= 48 KB). Real geometry 512/10 sits comfortably inside; a plan
2132/// outside the envelope keeps the host twin.
2133fn route_dev_geometry(experts: usize, selected: usize) -> bool {
2134    // Even expert count: the u64 selection-key slab follows the f32 weight slab in
2135    // dynamic smem (12 B/expert total) and needs 8-byte alignment.
2136    selected > 0
2137        && selected <= 32
2138        && selected <= experts
2139        && experts % 2 == 0
2140        && experts * 12 <= 48 * 1024
2141}
2142
2143/// Live device-vs-host router twin audit (`MEMRA_Q4E_ROUTER_AUDIT=1`): every device
2144/// route ALSO computes the host twin from the same logits and hard-compares — selection
2145/// ids order-exact (Err on any mismatch), weights within `ROUTE_AUDIT_ULP_BOUND` ULP
2146/// (worst observed kept for the receipt). The sigrouter-precedent cross-surface
2147/// contract, run over REAL decode rows by any existing gate invocation. Instrument
2148/// only: it dtohs per route, so it is never a perf arm.
2149fn router_audit_on() -> bool {
2150    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2151    *C.get_or_init(|| std::env::var("MEMRA_Q4E_ROUTER_AUDIT").as_deref() == Ok("1"))
2152}
2153/// DIAGNOSTIC seam (`MEMRA_Q4E_ROUTE_SYNC=1`): keep the device route but restore the
2154/// host arm's per-layer stream sync — the instrument that separates kernel cost from
2155/// sync-structure cost in the graphs-ON regression. Never a serving arm; no FLAGS row
2156/// because it is an instrument, and it is read once per process.
2157fn route_sync_diag() -> bool {
2158    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2159    *C.get_or_init(|| std::env::var("MEMRA_Q4E_ROUTE_SYNC").as_deref() == Ok("1"))
2160}
2161
2162/// Row ceiling for a PEER-RESIDENT QSA KV state (`alloc_state_reserve` with a
2163/// `kv_engine` on another card — the `--ladder-kv-dev1` arm). Default 8,192 rows;
2164/// `MEMRA_Q4E_PEER_KV_MAX_CAP` moves it for a deliberate re-measurement. `pub` so the
2165/// ladder CLI can refuse at arg-parse time, BEFORE paying a ~100 s checkpoint load.
2166///
2167/// Why there is a ceiling at all (memra#53, lane box, 4x RTX PRO 6000, all pairs PHB,
2168/// `nvidia-smi topo -p2p r` OK everywhere). The block-list attention form is the ONLY
2169/// read path for a quantized cache, and it is a SCATTER reader: `q4e_sdpa_blocklist_q8q5`
2170/// phase 1 is thread-per-position, so the 32 lanes of a warp sit on 32 different cache
2171/// rows `k_tok_bytes` apart and every load instruction replays 32 ways into 32 distinct
2172/// sectors (the kernel's own comment records this as the measured kvq-at-depth penalty).
2173/// On the local card the reading SM's L2 absorbs that replay -- the selected-row working
2174/// set is shared by all 24 query heads and by neighbouring query rows in the chunk. Peer
2175/// memory is NOT cached in the reading card's L2, so the same access pattern turns into
2176/// one PCIe round trip per sector, and the redundancy that L2 used to hide becomes real
2177/// wire traffic: at a 262,144 fill a single 2,048-token prefill chunk asks for
2178/// 12 layers x 24 heads x 2,048 rows x ~2,052 selected positions x 432 B = ~523 GB across
2179/// the link, and there are 128 such chunks. That is why the 262k kv-dev1 cell showed
2180/// sm 100% / mem 0% on the trunk card for 113 minutes with no rung row: the SMs were
2181/// resident and stalled on peer loads while the local framebuffer sat idle. It was never
2182/// a deadlock and no timeout wrapper would have helped.
2183///
2184/// The placement is also backwards on its own terms. The QSA KV is the SMALL allocation:
2185/// 864 B per row per QSA layer (q8_0 K 544 B + q5_1 V 320 B at kv_width 512), 12 QSA
2186/// layers = 10,368 B/row, i.e. **2.7 GiB** at a 262,144 capacity. The allocation that
2187/// actually does not fit beside 90 GiB of trunk weights is the MTP DRAFT state (~17.6 GiB
2188/// at the same capacity), and `load_from_dir_dev1` + `--mtp-dev1` already place that on
2189/// card 1. Moving the 2.7 GiB KV instead buys ~2.7 GiB and pays for it with the scatter
2190/// cliff above.
2191pub fn peer_kv_max_cap() -> usize {
2192    static C: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
2193    *C.get_or_init(|| {
2194        std::env::var("MEMRA_Q4E_PEER_KV_MAX_CAP")
2195            .ok()
2196            .and_then(|v| v.trim().parse::<usize>().ok())
2197            .unwrap_or(8192)
2198    })
2199}
2200
2201const ROUTE_AUDIT_ULP_BOUND: u32 = 8;
2202static ROUTE_AUDIT_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2203static ROUTE_AUDIT_MAX_ULP: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
2204/// (rows audited, worst weight ULP distance) since process start.
2205pub fn route_audit_stats() -> (u64, u32) {
2206    (
2207        ROUTE_AUDIT_ROWS.load(std::sync::atomic::Ordering::Relaxed),
2208        ROUTE_AUDIT_MAX_ULP.load(std::sync::atomic::Ordering::Relaxed),
2209    )
2210}
2211
2212/// Device-resident indexer raw-key cache (devtwin stage 3): below the QSA selection
2213/// horizon ((base_pos + t)/block <= budget — every row structurally full), the
2214/// idx_proj dtoh exists ONLY to feed the host raw-key cache for a possible future
2215/// scored row. This seam appends the k-part rows d2d (`copy_rows_col_f32`, exact byte
2216/// moves) and materializes the host cache LAZILY at the first scored chunk — the same
2217/// bytes dtoh'd later, so the scored path is bit-identical by construction. Kills the
2218/// census's 12 idx_proj blocking dtoh per forward (+1 per draft chain step) on every
2219/// sub-horizon shape.
2220///
2221/// **Default ON (2026-08-31), decided on receipts** with `routerdev` as ONE stack (see
2222/// that seam's note and PROFILE-9): isolated plain-decode row 1.024x, and it is the half
2223/// that makes the router's sign positive with decode graphs ON. Rollback:
2224/// `MEMRA_Q4E_SEAMS=idxcache=0`.
2225pub const IDX_CACHE_DEFAULT: bool = true;
2226static IDX_CACHE: std::sync::atomic::AtomicBool =
2227    std::sync::atomic::AtomicBool::new(IDX_CACHE_DEFAULT);
2228fn idx_cache_on() -> bool {
2229    IDX_CACHE.load(std::sync::atomic::Ordering::Relaxed)
2230}
2231pub fn set_idx_cache(on: bool) {
2232    IDX_CACHE.store(on, std::sync::atomic::Ordering::Relaxed);
2233}
2234
2235/// Quantized QSA KV cache (kvq lane): K = q8_0, V = q5_1 — the owner's asymmetric
2236/// default (K feeds the score dots + rope, so it keeps symmetric 8-bit; V errors
2237/// average under the attention weighting, so affine 5-bit suffices). The format is
2238/// LATCHED PER STATE at `alloc_state`/`mtp_state` time (a byte cache cannot flip
2239/// mid-run); the f32 arm stays the exactness instrument and the rollback seam
2240/// (`MEMRA_Q4E_SEAMS=kvq=0`). Storage-only: attention math runs f32 on dequanted
2241/// values (the block-list kernel's program with in-place dequant, gated bit-identical
2242/// to the dequant-rows + f32-kernel composition). Default ON per the owner decision,
2243/// with this lane's receipts attached (flags law): within-config exactness green
2244/// (spec byte-identity 6/6, verify-bit 24/24 x3, envelope 24/24 @ 3.0e-5), cross-config
2245/// drift is the near-tie quant class stated in KVQ-CELL.md (worst rows flip between the
2246/// two eos ids; greedy forks on the valid raw instrument match the f32 class).
2247///
2248/// PERF JUSTIFICATION, DEPTH-SCOPED (corrected 2026-08-31; docs/FLAGS.md carried the scoping
2249/// and this doc comment did not, so the stale claim was still riding here). The flip cited
2250/// "the quantized cache is FASTER, 13.36-13.39 vs 13.53-13.57 ms/token interleaved". That was
2251/// measured at a SHALLOW fill and the sign REVERSES with depth: at a 100,000-token fill kvq is
2252/// **-7.4% decode and -7.3% prefill wall** vs the f32 twin (LADDER.md, KVQ-CELL.md round 2).
2253/// Never quote "kvq is faster" at depth. The DECISION stands on memory: 11.08 vs 49.0
2254/// KiB/token, and at the 262,144 target window kvq is memory-REQUIRED (the f32 arm does not
2255/// allocate that state at all), so there is no alternative to compare against.
2256/// The -7.4% is a READ-PATTERN artifact, not the cost of quantization -- see `KV_HOIST_DEFAULT`.
2257/// Receipts: research/qwen4exp-bringup-20260829/kvq/ + box ~/realgate/kvq.
2258pub const KV_QUANT_DEFAULT: bool = true;
2259static KV_QUANT: std::sync::atomic::AtomicBool =
2260    std::sync::atomic::AtomicBool::new(KV_QUANT_DEFAULT);
2261fn kv_quant_on() -> bool {
2262    KV_QUANT.load(std::sync::atomic::Ordering::Relaxed)
2263}
2264pub fn set_kv_quant(on: bool) {
2265    KV_QUANT.store(on, std::sync::atomic::Ordering::Relaxed);
2266}
2267
2268/// HOISTED K block scale in the quantized block-list attention (`kvhoist`, memory lane
2269/// 2026-08-31). Selects `q4e_sdpa_blocklist_q8q5_hoist` over `q4e_sdpa_blocklist_q8q5`;
2270/// BIT-IDENTICAL by construction (same product, same `acc +=` order, phase 2 and phase 3
2271/// verbatim), so this is a pure read-pattern seam and the bar is bit-identity, not a band.
2272///
2273/// It exists because it is the mechanism behind the kvq perf SIGN FLIP, and the flip turns out
2274/// to be a layout artifact rather than a tax. `q4e_deq_q8` recomputes the block pointer from the
2275/// element index, so the score loop reloads the fp16 block scale ONCE PER ELEMENT. Measured
2276/// statically in the sm_120 SASS (`PROFILE-C0.md` §2), score-phase inner loop per 8 K elements:
2277///
2278/// | kernel | instrs | KV-cache loads | fp16 scale loads |
2279/// |---|---|---|---|
2280/// | `sdpa_blocklist_f32` | 37 | 8 | -- |
2281/// | `q4e_sdpa_blocklist_q8q5` | **120** | 8 | **8** |
2282/// | `q4e_sdpa_blocklist_q8q5_hoist` | **52** | 8 | **0** (1 per 32-elem block) |
2283///
2284/// Phase 1 is thread-per-position (lanes sit on 32 different tokens, `k_tok_bytes` apart), so
2285/// every load instruction replays 32 ways into 32 distinct sectors. The quantized cache
2286/// therefore issued 2x the f32 twin's KV transactions while reading 3.76x fewer bytes: the byte
2287/// saving cannot land, and the extra instruction stream is a straight loss. That is the -7.4%
2288/// at a 100,000-token fill, and it is why the +1.3% shallow flip receipt had the opposite sign
2289/// (a shallow fill reads almost no rows, so phase 1 barely runs).
2290///
2291/// Default OFF at introduction, by design (new-flags law): the correctness receipts land with
2292/// the seam and the default flip is a separate change carrying the interleaved A/B. Arm with
2293/// `MEMRA_Q4E_SEAMS=kvhoist`; rollback `kvhoist=0`. Mid-run flippable (no layout latch).
2294pub const KV_HOIST_DEFAULT: bool = false;
2295static KV_HOIST: std::sync::atomic::AtomicBool =
2296    std::sync::atomic::AtomicBool::new(KV_HOIST_DEFAULT);
2297fn kv_hoist_on() -> bool {
2298    KV_HOIST.load(std::sync::atomic::Ordering::Relaxed)
2299}
2300pub fn set_kv_hoist(on: bool) {
2301    KV_HOIST.store(on, std::sync::atomic::Ordering::Relaxed);
2302}
2303/// For receipt headers, same reason as `kv_quant_is_on`.
2304pub fn kv_hoist_is_on() -> bool {
2305    kv_hoist_on()
2306}
2307
2308/// DIM-MAJOR pooled-key device plane (`poolT`, memory lane 2026-08-31). Selects
2309/// `qsa_index_score_f32_t` over `qsa_index_score_f32` and mirrors the pooled cache transposed;
2310/// BIT-IDENTICAL by construction (identical loop order and identical explicit
2311/// `__fmul_rn`/`__fadd_rn`/`__fdiv_rn` -- only the address of `pooled` changes).
2312///
2313/// It targets the SECOND depth-scaling term in the deep decode profile. With `idxsel` armed
2314/// (`ladder-r2prof-step-idxsel.tsv`), `qsa.idx_host` is 2.5 ms at 100,000 / 3.0 at 131,072 /
2315/// 3.2 at 150,000 -- linear in context, extrapolating to ~5.7 ms at 262,144, behind only
2316/// `ple.host_ngram_gather` among the terms that grow. The score kernel is thread-per-block over
2317/// the pooled plane, so lane L reads `pooled[(block0+L)*head_dim + d]`: lanes are head_dim*4 =
2318/// 512 B apart, one warp's `k[d]` touches 32 DISTINCT sectors and moves 1024 B to use 128 B.
2319/// Dim-major makes the same 32 lanes read 32 consecutive floats: 4 sectors, zero waste, 8x less
2320/// sector traffic on the one array whose size IS the context.
2321///
2322/// Default OFF at introduction, by design (new-flags law). Arm `MEMRA_Q4E_SEAMS=poolT`, roll
2323/// back `poolT=0`. **Mid-run flippable with NO rebuild**: both layouts are maintained on every
2324/// append (see the append site for why), so `**mirrored` is the single truth for both and a flip
2325/// can neither read a stale plane nor leave one behind. The seam selects only the kernel.
2326pub const POOL_T_DEFAULT: bool = false;
2327static POOL_T: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(POOL_T_DEFAULT);
2328fn pool_t_on() -> bool {
2329    POOL_T.load(std::sync::atomic::Ordering::Relaxed)
2330}
2331pub fn set_pool_t(on: bool) {
2332    POOL_T.store(on, std::sync::atomic::Ordering::Relaxed);
2333}
2334/// For receipt headers.
2335pub fn pool_t_is_on() -> bool {
2336    pool_t_on()
2337}
2338
2339/// The live KV cache format, for RECEIPT HEADERS. A receipt that does not record which
2340/// cache arm it ran cannot be read: the round-2 ladder measured the f32 arm for a full
2341/// rung while its commit message said "kvq ship defaults", and nothing in the receipt
2342/// could have contradicted that. Reported, not inferred.
2343pub fn kv_quant_is_on() -> bool {
2344    kv_quant_on()
2345}
2346
2347/// Indexer raw-key cache precision (idxq lane). The 128-dim raw keys are cached
2348/// pre-norm/pre-rope and consumed ONLY through fp32 mean-pooling into pooled keys —
2349/// this seam quantizes the CACHE and dequants at read; the pooling math is identical.
2350/// Precision is picked by measurement (selection-identity flip rate on real prompts at
2351/// depth): q8 is the target, bf16 the fallback if q8 flips selections, f32 the
2352/// rollback/reference. Latched per state at alloc. Default Q8 per the measured
2353/// receipt: the q8-vs-f32 seam gate came back BIT-ZERO on the real checkpoint
2354/// (selection provably unmoved, 24/24 argmax, worst_abs 0.000e0 —
2355/// kvq/seam-gate-idxq-idxq1.tsv), so the cheaper cache wins by measurement.
2356#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2357pub enum IdxQMode {
2358    F32,
2359    Q8,
2360    Bf16,
2361}
2362static IDXQ_MODE: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(1);
2363fn idxq_mode() -> IdxQMode {
2364    match IDXQ_MODE.load(std::sync::atomic::Ordering::Relaxed) {
2365        1 => IdxQMode::Q8,
2366        2 => IdxQMode::Bf16,
2367        _ => IdxQMode::F32,
2368    }
2369}
2370pub fn set_idxq(mode: &str) {
2371    let v = match mode {
2372        "q8" | "1" => 1,
2373        "bf16" => 2,
2374        _ => 0,
2375    };
2376    IDXQ_MODE.store(v, std::sync::atomic::Ordering::Relaxed);
2377}
2378
2379/// The live indexer raw-key cache precision, for RECEIPT HEADERS (see `kv_quant_is_on`).
2380pub fn idxq_mode_name() -> &'static str {
2381    match idxq_mode() {
2382        IdxQMode::F32 => "f32",
2383        IdxQMode::Q8 => "q8",
2384        IdxQMode::Bf16 => "bf16",
2385    }
2386}
2387
2388/// Selection-identity audit (`MEMRA_Q4E_IDXQ_AUDIT=1`): with a quantized raw-key cache,
2389/// ALSO maintain an f32 twin cache (forcing the idx_proj dtoh the idxcache seam
2390/// removed — instrument, never a perf arm) and compute every scored row's selection
2391/// twice; count rows whose selected block set differs. The 1-ULP FMA lesson says
2392/// near-tie blocks CAN flip — this measures the rate on real prompts at depth.
2393fn idxq_audit_on() -> bool {
2394    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2395    *C.get_or_init(|| std::env::var("MEMRA_Q4E_IDXQ_AUDIT").as_deref() == Ok("1"))
2396}
2397static IDXQ_AUDIT_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2398static IDXQ_AUDIT_FLIPPED: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2399static IDXQ_AUDIT_BLOCKS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2400/// (scored rows audited, rows with a flipped selection set, total symmetric-difference
2401/// blocks) since process start.
2402pub fn idxq_audit_stats() -> (u64, u64, u64) {
2403    (
2404        IDXQ_AUDIT_ROWS.load(std::sync::atomic::Ordering::Relaxed),
2405        IDXQ_AUDIT_FLIPPED.load(std::sync::atomic::Ordering::Relaxed),
2406        IDXQ_AUDIT_BLOCKS.load(std::sync::atomic::Ordering::Relaxed),
2407    )
2408}
2409
2410/// Long-context QSA attention form (yarn lane). Auto = block-list kernel ONLY past the
2411/// masked kernel's smem bound (every historical receipt is byte-stable below it);
2412/// Force = block-list everywhere (the gate arms' A/B); Off = refuse long contexts (the
2413/// historical error). FLAGS.md row `q4e-longatt`.
2414#[derive(Clone, Copy, PartialEq, Eq)]
2415enum LongAttMode {
2416    Auto,
2417    Force,
2418    Off,
2419}
2420static LONGATT_MODE: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(0);
2421fn longatt_mode() -> LongAttMode {
2422    match LONGATT_MODE.load(std::sync::atomic::Ordering::Relaxed) {
2423        1 => LongAttMode::Force,
2424        2 => LongAttMode::Off,
2425        _ => LongAttMode::Auto,
2426    }
2427}
2428pub fn set_longatt(mode: &str) {
2429    let v = match mode {
2430        "force" | "1" => 1,
2431        "off" | "0" => 2,
2432        _ => 0,
2433    };
2434    LONGATT_MODE.store(v, std::sync::atomic::Ordering::Relaxed);
2435}
2436
2437// ------------------------------------------------------------ TP2 MoE expert placement
2438//
2439// Owner directive 2026-08-31 (LAW:coactivation-expert-placement): expert placement is
2440// MEASURED, never even-split — bundles by co-activation, the always-active set pinned to
2441// a KNOWN card the token enters and leaves. This lane does NOT do that measurement; it
2442// makes the seam exist so the placement lane is a measurement + config exercise instead
2443// of an engine rewrite.
2444//
2445// The artifact is the FROZEN shared format `memra-ep-map-v1`, minted by
2446// `tools/build_expert_placement_map.py` (merged on main, 4e46be545) from
2447// `MEMRA_MOE_TRACE` route traces. Reading the shared format rather than a lane-local one
2448// is the whole point: the glm5 arm consumes the same maps through `MEMRA_GLM5_EP_MAP`,
2449// so a map minted from qwen4_exp traces is comparable with theirs.
2450//
2451// Door: `MEMRA_Q4E_EP_MAP=<path>`. UNSET is the EVEN split — this lane's CONTROL ARM,
2452// and bit-identical to the pre-placement engine BY CONSTRUCTION, not by tolerance: an
2453// even assignment makes the card-1 bank gather a contiguous copy of exactly the suffix
2454// the old code sliced, and leaves card 0 addressing its full resident bank by global id.
2455// Default OFF is a deliberate decision under the new-flags law: an unmeasured placement
2456// must not become the serving default, and no placement has been measured yet.
2457//
2458// Fail-closed, loudly, on every mismatch (a map that silently half-applies would move
2459// expert weights under the router and read as a model bug):
2460//   * format != memra-ep-map-v1, or ranks != 2 (TP2 is a two-card route)
2461//   * expert_count != the plan's expert count
2462//   * a MoE layer in the plan missing from the map, or an assignment of the wrong length
2463//   * a rank id outside {0, 1}
2464//   * an UNBALANCED layer: card 1 must own exactly experts/2. The card-1 bank halves are
2465//     equal-size device allocations, so an unbalanced map is not a slower placement, it
2466//     is an out-of-bounds one. The placement lane must balance inside the tool (it has
2467//     `--balance-tolerance`) and ranks==2 with expert_count even means exact halves.
2468#[derive(Debug, Clone)]
2469pub struct Tp2Placement {
2470    /// layer index -> rank (0 or 1) per GLOBAL expert id. Empty map = even split.
2471    by_layer: std::collections::BTreeMap<u32, Vec<u8>>,
2472    expert_count: usize,
2473    entry_rank: u8,
2474    strategy: String,
2475    source: String,
2476}
2477
2478/// One layer's resolved placement. Card 0 keeps the FULL resident bank, so a card-0
2479/// expert's local slot IS its global id (no remap, exactly as the even split behaved);
2480/// card 1 holds a gathered half, so its local slot is the position in `card1`.
2481#[derive(Debug, Clone)]
2482pub struct LayerPlacement {
2483    /// GLOBAL expert ids owned by card 1, ASCENDING — the bank gather order and the
2484    /// local-slot order. Ascending is load-bearing: it makes the even case a contiguous
2485    /// copy, and it makes the gather order a function of the map alone (no host set
2486    /// iteration order can leak into device bytes).
2487    pub card1: Vec<u32>,
2488    /// global expert id -> local slot on its owner card.
2489    local_of: Vec<u32>,
2490    /// global expert id -> owner rank.
2491    rank_of: Vec<u8>,
2492}
2493
2494impl LayerPlacement {
2495    #[inline]
2496    pub fn rank(&self, expert: usize) -> u8 {
2497        self.rank_of[expert]
2498    }
2499    #[inline]
2500    pub fn local(&self, expert: usize) -> usize {
2501        self.local_of[expert] as usize
2502    }
2503    /// True when this layer is the plain contiguous even split (the control arm).
2504    pub fn is_even(&self) -> bool {
2505        let half = self.rank_of.len() / 2;
2506        self.card1.len() == half
2507            && self
2508                .card1
2509                .iter()
2510                .enumerate()
2511                .all(|(i, &e)| e as usize == half + i)
2512    }
2513}
2514
2515impl Tp2Placement {
2516    /// The even split: `rank = expert / (experts / 2)`, the engine's historical law.
2517    pub fn even(expert_count: usize) -> Self {
2518        Self {
2519            by_layer: std::collections::BTreeMap::new(),
2520            expert_count,
2521            entry_rank: 0,
2522            strategy: "even".to_string(),
2523            source: "built-in (MEMRA_Q4E_EP_MAP unset)".to_string(),
2524        }
2525    }
2526
2527    pub fn strategy(&self) -> &str {
2528        &self.strategy
2529    }
2530    pub fn source(&self) -> &str {
2531        &self.source
2532    }
2533    pub fn entry_rank(&self) -> u8 {
2534        self.entry_rank
2535    }
2536
2537    /// Read `MEMRA_Q4E_EP_MAP`; `Ok(None)` when the door is closed (even split).
2538    pub fn from_env(expert_count: usize) -> Res<Option<Self>> {
2539        let Ok(path) = std::env::var("MEMRA_Q4E_EP_MAP") else {
2540            return Ok(None);
2541        };
2542        if path.is_empty() || path == "0" {
2543            return Ok(None);
2544        }
2545        Some(Self::load(std::path::Path::new(&path), expert_count)).transpose()
2546    }
2547
2548    pub fn load(path: &std::path::Path, expert_count: usize) -> Res<Self> {
2549        let text = std::fs::read_to_string(path)
2550            .map_err(|e| format!("MEMRA_Q4E_EP_MAP {}: {e}", path.display()))?;
2551        let v = memra_tokenizer::json::parse(&text)
2552            .map_err(|e| format!("MEMRA_Q4E_EP_MAP {}: {e}", path.display()))?;
2553        // Every refusal in this function names the file and the exact contract clause
2554        // broken: a rejected map has to tell the placement lane what to fix.
2555        let want = |k: &str| -> Res<Self> {
2556            Err(format!("MEMRA_Q4E_EP_MAP {}: {k}", path.display()).into())
2557        };
2558        match v.get("format").and_then(|f| f.as_str()) {
2559            Some("memra-ep-map-v1") => {}
2560            other => {
2561                return want(&format!(
2562                    "format is {other:?}, expected \"memra-ep-map-v1\" (mint it with \
2563                     tools/build_expert_placement_map.py)"
2564                ));
2565            }
2566        }
2567        let ranks = v.get("ranks").and_then(|r| r.as_u64()).unwrap_or(0);
2568        if ranks != 2 {
2569            return want(&format!(
2570                "ranks={ranks}, but the TP2 route is exactly two cards"
2571            ));
2572        }
2573        let map_experts = v.get("expert_count").and_then(|r| r.as_u64()).unwrap_or(0) as usize;
2574        if map_experts != expert_count {
2575            return want(&format!(
2576                "expert_count={map_experts} but this plan has {expert_count} experts"
2577            ));
2578        }
2579        // An ODD routed bank has no equal halves. Note precisely what the balance clause below
2580        // does and does not do here, because "it was already covered" is the easy wrong reading:
2581        // `half = expert_count / 2` FLOORS, so on 5 experts a map placing exactly 2 on card 1
2582        // SATISFIES `on1 == half` and loaded clean before this check existed. The balance clause
2583        // caught only the unbalanced odd maps, and for those it named the wrong problem (it read
2584        // as a rebalance request against a bank that cannot be balanced). Refuse the geometry by
2585        // name instead. Checked here AND in `layer()` because the built-in even split never
2586        // passes through this parser.
2587        if expert_count % 2 != 0 {
2588            return want(&format!(
2589                "this plan has {expert_count} routed experts, which is ODD: the TP2 route \
2590                 splits the bank into two EQUAL-size device allocations, so no two-card \
2591                 placement exists for it"
2592            ));
2593        }
2594        let entry_rank = v.get("entry_rank").and_then(|r| r.as_u64()).unwrap_or(0) as u8;
2595        if entry_rank > 1 {
2596            return want(&format!("entry_rank={entry_rank} outside {{0,1}}"));
2597        }
2598        let strategy = v
2599            .get("strategy")
2600            .and_then(|s| s.as_str())
2601            .unwrap_or("unnamed")
2602            .to_string();
2603        let Some(layers) = v.get("layers").and_then(|l| l.as_arr()) else {
2604            return want("no `layers` array");
2605        };
2606        let half = expert_count / 2;
2607        let mut by_layer = std::collections::BTreeMap::new();
2608        for row in layers {
2609            let Some(index) = row.get("layer").and_then(|l| l.as_u64()) else {
2610                return want("a layer row without an integer `layer`");
2611            };
2612            let Some(assign) = row.get("assignment").and_then(|a| a.as_arr()) else {
2613                return want(&format!("layer {index}: no `assignment` array"));
2614            };
2615            if assign.len() != expert_count {
2616                return want(&format!(
2617                    "layer {index}: assignment has {} entries, expected {expert_count}",
2618                    assign.len()
2619                ));
2620            }
2621            let mut ranks_vec = Vec::with_capacity(expert_count);
2622            for (eid, a) in assign.iter().enumerate() {
2623                match a.as_u64() {
2624                    Some(r) if r <= 1 => ranks_vec.push(r as u8),
2625                    other => {
2626                        return want(&format!(
2627                            "layer {index} expert {eid}: rank {other:?} outside {{0,1}}"
2628                        ));
2629                    }
2630                }
2631            }
2632            let on1 = ranks_vec.iter().filter(|&&r| r == 1).count();
2633            if on1 != half {
2634                return want(&format!(
2635                    "layer {index}: card 1 owns {on1} experts but the bank halves are \
2636                     equal-size allocations, so it must own exactly {half} — rebalance \
2637                     the map (build_expert_placement_map.py --balance-tolerance)"
2638                ));
2639            }
2640            by_layer.insert(index as u32, ranks_vec);
2641        }
2642        if by_layer.is_empty() {
2643            return want("`layers` is empty");
2644        }
2645        Ok(Self {
2646            by_layer,
2647            expert_count,
2648            entry_rank,
2649            strategy,
2650            source: path.display().to_string(),
2651        })
2652    }
2653
2654    /// Resolve one MoE layer. A loaded map MUST cover every MoE layer it is asked about
2655    /// (fail-closed: silently falling one layer back to even would make the receipt a
2656    /// lie about which placement ran).
2657    pub fn layer(&self, index: u32, expert_count: usize) -> Res<LayerPlacement> {
2658        if expert_count != self.expert_count {
2659            return Err(format!(
2660                "qwen4exp_gpu tp2 placement: layer {index} has {expert_count} experts, \
2661                 map is for {}",
2662                self.expert_count
2663            )
2664            .into());
2665        }
2666        // DEFENSE IN DEPTH ON A `pub` API, and scoped honestly: production cannot reach this
2667        // with an odd bank, because the only caller (`build_tp2_shard`) already refuses
2668        // `experts % 2 != 0` eleven lines before it asks for a `LayerPlacement`. So this is not
2669        // a latent out-of-bounds and nothing was silently wrong: the card-1 bank upload sizes
2670        // its allocation on `place.card1.len()`, so an odd split would have produced an
2671        // UNBALANCED (3-of-5) card-1 half, not an overflowing one.
2672        //
2673        // What it does buy: `layer()` and `load()` are `pub`, and on an odd bank the even split
2674        // `rank = expert / (experts/2)` has no two-card answer at all. Naming that geometry here
2675        // means a future caller gets the refusal from the function whose contract it breaks
2676        // instead of relying on an upstream check it may not have. It also closes a real hole in
2677        // `load()`: `half` FLOORS, so a map placing exactly 2 of 5 experts on card 1 satisfied
2678        // the balance clause and loaded clean before this check existed.
2679        if expert_count % 2 != 0 {
2680            return Err(format!(
2681                "qwen4exp_gpu tp2 placement: layer {index} has {expert_count} routed \
2682                 experts, which is ODD: the TP2 route splits the bank into two EQUAL-size \
2683                 device allocations, so no two-card placement exists for it"
2684            )
2685            .into());
2686        }
2687        let half = expert_count / 2;
2688        let rank_of: Vec<u8> = if self.by_layer.is_empty() {
2689            (0..expert_count).map(|e| u8::from(e >= half)).collect()
2690        } else {
2691            self.by_layer
2692                .get(&index)
2693                .ok_or_else(|| {
2694                    format!(
2695                        "qwen4exp_gpu tp2 placement: map {} does not cover MoE layer \
2696                         {index} (fail-closed; a partly-applied map is not a placement)",
2697                        self.source
2698                    )
2699                })?
2700                .clone()
2701        };
2702        let card1: Vec<u32> = (0..expert_count)
2703            .filter(|&e| rank_of[e] == 1)
2704            .map(|e| e as u32)
2705            .collect();
2706        let mut local_of = vec![0u32; expert_count];
2707        for (slot, &eid) in card1.iter().enumerate() {
2708            local_of[eid as usize] = slot as u32;
2709        }
2710        // Card 0 addresses its FULL resident bank by global id.
2711        for e in 0..expert_count {
2712            if rank_of[e] == 0 {
2713                local_of[e] = e as u32;
2714            }
2715        }
2716        Ok(LayerPlacement {
2717            card1,
2718            local_of,
2719            rank_of,
2720        })
2721    }
2722}
2723
2724/// Engagement counter: PEER-owned (card 1) expert slots dispatched by the TP2 MoE split,
2725/// since process start. Copied from the glm5 TP lane's
2726/// `GLM5_EP_PEER_SLOT_DISPATCHES` for the reason that lane learned the hard way — its
2727/// first seed search found a token stream that NEVER routed a peer expert, so the arm's
2728/// identity claim would have been VACUOUS. Any TP2 exactness claim must assert this
2729/// counter moved, or it is a claim about a program that did not run.
2730static TP2_PEER_EXPERT_SLOTS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2731/// Same for card 0, so a receipt can print the per-rank token-touch/byte split instead of
2732/// only proving non-vacuity (the glm5 lane reported its ~99.3% peer-touch and ~64%
2733/// slowest-rank byte fraction as CLOSED-FORM derivations with no measurement behind them;
2734/// these two counters are what make ours measured).
2735static TP2_HOME_EXPERT_SLOTS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2736/// Layer-tokens whose top-k touched BOTH cards (the "peer is on the critical path"
2737/// fraction — the number the glm5 lane derived as ~99.3% for its 288/top-8 geometry).
2738static TP2_BOTH_TOUCH_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2739static TP2_TOUCH_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2740
2741/// (peer slots, home slots, rows touching both cards, rows counted) since process start.
2742pub fn tp2_expert_split_stats() -> (u64, u64, u64, u64) {
2743    use std::sync::atomic::Ordering::Relaxed;
2744    (
2745        TP2_PEER_EXPERT_SLOTS.load(Relaxed),
2746        TP2_HOME_EXPERT_SLOTS.load(Relaxed),
2747        TP2_BOTH_TOUCH_ROWS.load(Relaxed),
2748        TP2_TOUCH_ROWS.load(Relaxed),
2749    )
2750}
2751
2752fn tp2_count_split(routes0: &[Vec<(usize, f32)>], routes1: &[Vec<(usize, f32)>]) {
2753    use std::sync::atomic::Ordering::Relaxed;
2754    let (mut peer, mut home, mut both) = (0u64, 0u64, 0u64);
2755    for (r0, r1) in routes0.iter().zip(routes1.iter()) {
2756        home += r0.len() as u64;
2757        peer += r1.len() as u64;
2758        if !r0.is_empty() && !r1.is_empty() {
2759            both += 1;
2760        }
2761    }
2762    TP2_HOME_EXPERT_SLOTS.fetch_add(home, Relaxed);
2763    TP2_PEER_EXPERT_SLOTS.fetch_add(peer, Relaxed);
2764    TP2_BOTH_TOUCH_ROWS.fetch_add(both, Relaxed);
2765    TP2_TOUCH_ROWS.fetch_add(routes0.len() as u64, Relaxed);
2766}
2767
2768/// Gate-only deliberate defects for the TP2 class gate: `MEMRA_Q4E_TP2_GATE_RED=<name>`.
2769/// A band is only a bar if a WRONG program lands orders outside it, so the gate runs
2770/// these and REQUIRES them to be loud (the glm5 `MEMRA_GLM5_TP_GATE_RED` pattern).
2771/// Never a serving door — an unknown value refuses at the first MoE layer.
2772#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2773pub enum Tp2GateRed {
2774    None,
2775    /// Drop the peer card's routed-expert contribution from the join.
2776    SkipPeerMoe,
2777    /// Route peer-owned experts to card 0's bank at their LOCAL slot — a plausible
2778    /// off-by-remap bug (right magnitudes, wrong experts).
2779    PeerLocalIds,
2780    /// Feed the peer half its slot weights in reversed order within each token.
2781    ReverseePeerWeights,
2782}
2783
2784fn tp2_gate_red() -> Res<Tp2GateRed> {
2785    static C: std::sync::OnceLock<Result<Tp2GateRed, String>> = std::sync::OnceLock::new();
2786    C.get_or_init(
2787        || match std::env::var("MEMRA_Q4E_TP2_GATE_RED").as_deref() {
2788            Err(_) | Ok("") | Ok("0") | Ok("none") => Ok(Tp2GateRed::None),
2789            Ok("skip-peer-moe") => Ok(Tp2GateRed::SkipPeerMoe),
2790            Ok("peer-local-ids") => Ok(Tp2GateRed::PeerLocalIds),
2791            Ok("reverse-peer-weights") => Ok(Tp2GateRed::ReverseePeerWeights),
2792            Ok(other) => Err(format!(
2793                "MEMRA_Q4E_TP2_GATE_RED={other:?}: want skip-peer-moe|peer-local-ids|\
2794             reverse-peer-weights|none"
2795            )),
2796        },
2797    )
2798    .clone()
2799    .map_err(Into::into)
2800}
2801
2802/// Per-layer MoE route trace in the FROZEN shared format
2803/// `tools/build_expert_placement_map.py` consumes (`<layer> <t> <id,id,...>`, one line
2804/// per (layer, forward); decode steps are t == 1) — byte-compatible with
2805/// `hybrid_forward.rs::trace_moe_routes` so one tool reads both arms' traces.
2806///
2807/// Doors: `MEMRA_MOE_TRACE` (ids) and `MEMRA_MOE_WEIGHT_TRACE` (`<expert>:<weight>`).
2808/// Both OFF by default: this writes an unbounded append-only file and costs host I/O per
2809/// layer per forward, which is fine for a battery and wrong for serving.
2810///
2811/// Where it taps, and the honest limit: the qwen4_exp MoE route exists on the HOST on
2812/// the TP2 route (which keeps the host router twin by construction) and on the
2813/// per-expert prefill executor. Under the shipped single-card default the route is
2814/// DEVICE-side (`routerdev`, PROFILE-9) with no readback at all, so there is nothing to
2815/// tap without re-adding the very sync that lane deleted — arming
2816/// `MEMRA_Q4E_ROUTER_AUDIT=1` restores a host recompute of every device route and the
2817/// trace rides THAT readback at zero new syncs. So: TP2 batteries trace for free;
2818/// single-card batteries trace with the audit armed.
2819fn trace_moe_routes(layer: u32, t: usize, routes: &[Vec<(usize, f32)>]) {
2820    use std::io::Write as _;
2821    static IDS: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
2822    static WEIGHTS: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
2823    let ids = IDS.get_or_init(|| {
2824        std::env::var("MEMRA_MOE_TRACE")
2825            .ok()
2826            .filter(|p| !p.is_empty())
2827    });
2828    let weights = WEIGHTS.get_or_init(|| {
2829        std::env::var("MEMRA_MOE_WEIGHT_TRACE")
2830            .ok()
2831            .filter(|p| !p.is_empty())
2832    });
2833    if ids.is_none() && weights.is_none() {
2834        return;
2835    }
2836    // One line per (layer, forward) with EVERY row's selections concatenated is what the
2837    // shared format specifies for t > 1 forwards, and the tool's co-occurrence is
2838    // "within-line", so a prefill chunk's line legitimately carries t tokens' picks.
2839    let flat: Vec<&(usize, f32)> = routes.iter().flatten().collect();
2840    let append = |path: &str, body: String| {
2841        if let Ok(mut f) = std::fs::OpenOptions::new()
2842            .create(true)
2843            .append(true)
2844            .open(path)
2845        {
2846            let _ = writeln!(f, "{layer} {t} {body}");
2847        }
2848    };
2849    if let Some(path) = ids {
2850        let body: Vec<String> = flat.iter().map(|(e, _)| e.to_string()).collect();
2851        append(path, body.join(","));
2852    }
2853    if let Some(path) = weights {
2854        let body: Vec<String> = flat.iter().map(|(e, w)| format!("{e}:{w:.9}")).collect();
2855        append(path, body.join(","));
2856    }
2857}
2858
2859/// Arm or disarm ONE seam by its `MEMRA_Q4E_SEAMS` name, returning false when the name is
2860/// unknown. Extracted from `apply_env_seams` (which is now its only-at-startup caller) so a
2861/// measurement harness can flip a seam BETWEEN timed rounds inside one process — the
2862/// interleaved-A/B instrument the 262k host lane needs, because at these depths a per-arm
2863/// process pays a fresh 25-80 minute prefill for a decode-only lever and box clock drift
2864/// then sits between the arms. `value` carries the raw `name=value` right-hand side for the
2865/// three-valued seams; `on` is already decoded for the boolean ones.
2866///
2867/// This is a MEASUREMENT seam-setter, not a serving one: flipping a seam mid-run is sound
2868/// only for seams whose state is rebuildable from the token history (`plecache` appends to a
2869/// cache it can also rebuild by longest-common-prefix), and the caller owns that judgement.
2870pub fn set_seam(name: &str, on: bool, value: Option<&str>) -> bool {
2871    seam_dispatch(name, on, value, true)
2872}
2873
2874/// The CURRENT boolean state of a seam, for exact save/restore around a measurement that
2875/// flips it. `None` for a name with no boolean state (`idxq` is three-valued, `longatt`
2876/// three-valued) and for an unknown name.
2877///
2878/// This exists because the alternative — "restore by re-running `apply_env_seams`" — is
2879/// wrong in a way that would not show up as a failure: a seam absent from
2880/// `MEMRA_Q4E_SEAMS` is not reset by that call, so the run would silently continue on
2881/// whichever arm happened to execute last. Save/restore has to read the real state.
2882pub fn seam_state(name: &str) -> Option<bool> {
2883    Some(match name {
2884        "moe" => moe_sel_path_on(),
2885        "hc" => hc_fused_gate_on(),
2886        "trunk" => trunk_bf16_on(),
2887        "ws" => step_ws_on(),
2888        "graph" => decode_graphs_on(),
2889        "selv2" => sel_v2_on(),
2890        "hcmicro" => hc_micro_on(),
2891        "selv3" => sel_v3_on(),
2892        "gdnstep" => gdn_step_on(),
2893        "gdnfuse" => gdn_fuse_on(),
2894        "projstack" => proj_stack_on(),
2895        "hcdiet" => hc_diet_on(),
2896        "gufuse" => sel_gufuse_on(),
2897        "routerb16" => router_bf16_on(),
2898        "vgraph" => verify_graphs_on(),
2899        "vfuse" => verify_fused_on(),
2900        "idxdev" => idx_dev_on(),
2901        "idxsel" => idx_sel_on(),
2902        "plecache" => ple_cache_on(),
2903        "routerdev" => router_dev_on(),
2904        "idxcache" => idx_cache_on(),
2905        "kvq" => kv_quant_on(),
2906        "kvhoist" => kv_hoist_on(),
2907        "poolT" => pool_t_on(),
2908        // Shape-valued, but it DOES carry a boolean state and must report it: the shared
2909        // `--ab-seam` / `--ladder-ab-seam` harness restores the entry arm only when
2910        // `seam_state` answers, and returning None there would leave the ON arm armed for
2911        // every number after the A/B block — the silent arm flip that harness's own comment
2912        // warns about. OFF <-> AUTO (the two arms a seam A/B runs) round-trips exactly.
2913        // Restoring a PINNED shape does not: it comes back as AUTO, so a cell that pins
2914        // `dn:8:1` must carry it in `MEMRA_Q4E_SEAMS` per invocation (which is how the
2915        // banked downsel cells run their ladder) or save/restore `sel_group_spec()`.
2916        "selgroup" => sel_group_dn() != SEL_GROUP_OFF || sel_group_gu() != SEL_GROUP_OFF,
2917        _ => return None,
2918    })
2919}
2920
2921/// Does this seam name exist? Same table as `set_seam`, applying NOTHING. A harness that
2922/// validates a seam name up front (before a 25-80 minute prefill it would otherwise waste on
2923/// a typo) must not have to arm or disarm the seam to find out — a validator with a silent
2924/// side effect on global state is the kind of thing that later reads as a mystery flip.
2925pub fn seam_exists(name: &str) -> bool {
2926    seam_dispatch(name, false, None, false)
2927}
2928
2929/// Every seam name `seam_dispatch` accepts, as DATA, sitting directly above the match so the two
2930/// are read together. `gate_seam_table` walks this list, so a name here that the match does not
2931/// accept fails that gate loudly.
2932///
2933/// The reverse drift — a match arm added without a list entry — is NOT machine-detectable from
2934/// here, and that seam is then uncovered rather than wrong. Said out loud instead of dressed up
2935/// as completeness, because a non-vacuity check that cannot fail is worse than no check.
2936/// **Adding a seam: add its arm below AND its name here.**
2937pub fn seam_names() -> &'static [&'static str] {
2938    &[
2939        "moe",
2940        "hc",
2941        "trunk",
2942        "ws",
2943        "graph",
2944        "selv2",
2945        "hcmicro",
2946        "selv3",
2947        "gdnstep",
2948        "gdnfuse",
2949        "projstack",
2950        "hcdiet",
2951        "gufuse",
2952        "routerb16",
2953        "vgraph",
2954        "vfuse",
2955        "longatt",
2956        "idxdev",
2957        "idxsel",
2958        "plecache",
2959        "routerdev",
2960        "idxcache",
2961        "kvq",
2962        "idxq",
2963        "kvhoist",
2964        "poolT",
2965        "selgroup",
2966    ]
2967}
2968
2969/// The one seam name table. `apply` false walks the same arms and calls no setter, so the
2970/// name check and the action can never drift apart.
2971fn seam_dispatch(name: &str, on: bool, value: Option<&str>, apply: bool) -> bool {
2972    macro_rules! seam {
2973        ($call:expr) => {{
2974            if apply {
2975                $call;
2976            }
2977            true
2978        }};
2979    }
2980    match name {
2981        "moe" => seam!(set_moe_sel_path(on)),
2982        "hc" => seam!(set_hc_fused_gate(on)),
2983        "trunk" => seam!(set_trunk_bf16(on)),
2984        "ws" => seam!(set_step_ws(on)),
2985        "graph" => seam!(set_decode_graphs(on)),
2986        "selv2" => seam!(set_sel_v2(on)),
2987        "hcmicro" => seam!(set_hc_micro(on)),
2988        "selv3" => seam!(set_sel_v3(on)),
2989        "gdnstep" => seam!(set_gdn_step(on)),
2990        "gdnfuse" => seam!(set_gdn_fuse(on)),
2991        "projstack" => seam!(set_proj_stack(on)),
2992        "hcdiet" => seam!(set_hc_diet(on)),
2993        "gufuse" => seam!(set_sel_gufuse(on)),
2994        "routerb16" => seam!(set_router_bf16(on)),
2995        "vgraph" => seam!(set_verify_graphs(on)),
2996        // COST INSTRUMENT, no rewind (see VERIFY_FUSED_DEFAULT): a spec loop with this
2997        // armed refuses at the first `verify_rewind`. Timing probes only.
2998        "vfuse" => seam!(set_verify_fused(on)),
2999        "longatt" => seam!(set_longatt(if on { "force" } else { "off" })),
3000        "idxdev" => seam!(set_idx_dev(on)),
3001        "idxsel" => seam!(set_idx_sel(on)),
3002        "plecache" => seam!(set_ple_cache(on)),
3003        "routerdev" => seam!(set_router_dev(on)),
3004        "idxcache" => seam!(set_idx_cache(on)),
3005        "kvq" => seam!(set_kv_quant(on)),
3006        // Bit-identical READ-PATTERN seams (memory lane): no layout latch on `kvhoist`,
3007        // and `poolT` re-mirrors on flip, so both are sound to flip between timed rounds.
3008        "kvhoist" => seam!(set_kv_hoist(on)),
3009        "poolT" => seam!(set_pool_t(on)),
3010        // Three-valued: `idxq=q8`, `idxq=bf16`, `idxq=0`/`idxq=f32` (rollback);
3011        // bare `idxq` arms the q8 target.
3012        "idxq" => seam!(set_idxq(value.unwrap_or("q8"))),
3013        // SHAPE-valued (see set_sel_group): bare `selgroup` = both families AUTO,
3014        // `selgroup=dn:4:1+gu:16:2` pins the A/B ladder's arms, `selgroup=0` rolls back.
3015        // A malformed spec must not read as "seam applied": it returns false here so the
3016        // caller reports an unknown/bad seam instead of measuring the default arm.
3017        "selgroup" => {
3018            if apply {
3019                set_sel_group(if on { value.unwrap_or("auto") } else { "off" })
3020            } else {
3021                true
3022            }
3023        }
3024        _ => {
3025            debug_assert!(
3026                !seam_names().contains(&name),
3027                "seam_names() lists {name:?} but seam_dispatch has no arm for it"
3028            );
3029            false
3030        }
3031    }
3032}
3033
3034pub fn apply_env_seams() {
3035    let Ok(spec) = std::env::var("MEMRA_Q4E_SEAMS") else {
3036        return;
3037    };
3038    for part in spec.split(',').filter(|p| !p.is_empty()) {
3039        let (name, on) = match part.split_once('=') {
3040            Some((n, v)) => (n, v != "0"),
3041            None => (part, true),
3042        };
3043        if !set_seam(name, on, part.split_once('=').map(|(_, v)| v)) {
3044            eprintln!("MEMRA_Q4E_SEAMS: unknown seam {name:?} ignored");
3045        }
3046    }
3047}
3048
3049/// Per-piece kill switches for the hcmicro bundle (bisect instrumentation: set
3050/// MEMRA_Q4E_MICRO_{NORM,INJ,SHEXP}=0 to fall a single piece back while the seam stays
3051/// on). Read once per process.
3052fn micro_env_on(name: &'static str, cell: &'static std::sync::OnceLock<bool>) -> bool {
3053    *cell.get_or_init(|| std::env::var(name).as_deref() != Ok("0"))
3054}
3055
3056fn micro_norm_on() -> bool {
3057    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
3058    hc_micro_on() && micro_env_on("MEMRA_Q4E_MICRO_NORM", &C)
3059}
3060
3061fn micro_inj_on() -> bool {
3062    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
3063    hc_micro_on() && micro_env_on("MEMRA_Q4E_MICRO_INJ", &C)
3064}
3065
3066fn micro_shexp_on() -> bool {
3067    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
3068    hc_micro_on() && micro_env_on("MEMRA_Q4E_MICRO_SHEXP", &C)
3069}
3070
3071/// Run `f` as a named profile section (sync–time–sync when profiling is on).
3072fn prof_section<T>(e: &Engine, name: &'static str, f: impl FnOnce() -> Res<T>) -> Res<T> {
3073    if !prof::on() {
3074        return f();
3075    }
3076    e.gpu.stream().synchronize()?;
3077    let t0 = std::time::Instant::now();
3078    let out = f()?;
3079    e.gpu.stream().synchronize()?;
3080    prof::add(name, t0.elapsed().as_secs_f64());
3081    Ok(out)
3082}
3083
3084// ---------------------------------------------------------------- host twins (oracle math)
3085
3086fn host_sigmoid(x: f32) -> f32 {
3087    1.0 / (1.0 + (-x).exp())
3088}
3089
3090/// memra_reference `softmax_in_place` twin.
3091fn host_softmax(values: &mut [f32]) {
3092    let max = values.iter().copied().fold(f32::NEG_INFINITY, f32::max);
3093    let mut sum = 0.0;
3094    for value in values.iter_mut() {
3095        *value = (*value - max).exp();
3096        sum += *value;
3097    }
3098    for value in values {
3099        *value /= sum;
3100    }
3101}
3102
3103/// The router renorm denominator floor (memra_reference `route_experts`, mirrored by
3104/// the device twin). Note it is UNBINDABLE on real softmax geometry: the top-k weights
3105/// are the k largest of a distribution summing to 1, so their sum is >= k/experts
3106/// (10/512 ~ 0.0195 >> 6.1e-5) — kept because the reference ships it.
3107const ROUTE_DENOM_FLOOR: f32 = 6.103_515_6e-5;
3108
3109/// memra_reference `route_experts` twin, Softmax arm only (qwen4_exp router — softmax,
3110/// top-k renormalized with the 6.1035156e-5 floor, tie rule score-desc/index-asc).
3111fn host_route_softmax_topk(logits: &[f32], selected: usize) -> Vec<(usize, f32)> {
3112    let mut weights = logits.to_vec();
3113    host_softmax(&mut weights);
3114    let mut indices: Vec<usize> = (0..logits.len()).collect();
3115    indices.sort_by(|&left, &right| {
3116        weights[right]
3117            .total_cmp(&weights[left])
3118            .then(left.cmp(&right))
3119    });
3120    indices.truncate(selected);
3121    let denominator = indices
3122        .iter()
3123        .map(|&index| weights[index])
3124        .sum::<f32>()
3125        .max(ROUTE_DENOM_FLOOR);
3126    indices
3127        .into_iter()
3128        .map(|index| (index, weights[index] / denominator))
3129        .collect()
3130}
3131
3132/// memra_reference `rms_norm` twin (host, effective weights).
3133fn host_rms_norm(x: &mut [f32], width: usize, weight: &[f32], epsilon: f32) {
3134    for row in x.chunks_exact_mut(width) {
3135        let mean_square = row.iter().map(|v| v * v).sum::<f32>() / width as f32;
3136        let inverse = 1.0 / (mean_square + epsilon).sqrt();
3137        for (value, w) in row.iter_mut().zip(weight) {
3138            *value = *value * inverse * w;
3139        }
3140    }
3141}
3142
3143/// memra_reference `apply_rope_at_position` twin (NeoX split-half). `yarn` = the shared
3144/// (divisor table, mscale) pair when the plan carries YaRN factors — identical divisor
3145/// semantics to the reference (`frequency / divisor`, cos/sin scaled by mscale); `None`
3146/// keeps the historical byte-exact plain path.
3147fn host_rope_at(
3148    values: &mut [f32],
3149    head_dim: usize,
3150    dimensions: usize,
3151    base: f32,
3152    yarn: Option<(&[f32], f32)>,
3153    position: usize,
3154) {
3155    let dimensions = dimensions.min(head_dim) / 2 * 2;
3156    let half = dimensions / 2;
3157    for head in values.chunks_exact_mut(head_dim) {
3158        for index in 0..half {
3159            let frequency = base.powf(-2.0 * index as f32 / dimensions as f32);
3160            let frequency = match yarn {
3161                Some((ff, _)) => frequency / ff[index],
3162                None => frequency,
3163            };
3164            let angle = position as f32 * frequency;
3165            let (sin, cos) = angle.sin_cos();
3166            let (sin, cos) = match yarn {
3167                Some((_, mscale)) => (sin * mscale, cos * mscale),
3168                None => (sin, cos),
3169            };
3170            let first = head[index];
3171            let second = head[index + half];
3172            head[index] = first * cos - second * sin;
3173            head[index + half] = first * sin + second * cos;
3174        }
3175    }
3176}
3177
3178/// What the forward's exit computes (chunked long-context prefill skips the head: the
3179/// [t, vocab] logits block of a big chunk is gigabytes and reads/writes no state).
3180#[derive(Clone, Copy, PartialEq, Eq)]
3181pub enum HeadMode {
3182    /// Exit mixer + lm_head on every row ([t, vocab] logits) — the historical shape.
3183    All,
3184    /// Exit mixer on the chunk, lm_head on the LAST row only ([vocab] logits).
3185    LastRow,
3186    /// No exit mixer, no lm_head, empty return (mid-prefill chunks).
3187    Skip,
3188}
3189
3190/// One query row's QSA visibility in BLOCK form — the selection's native shape (the
3191/// dense [t, t_kv] mask is a rendering of this for the smem-bounded masked kernel; the
3192/// long-context block-list kernel consumes it directly).
3193struct RowSel {
3194    /// Structural fast path (complete <= budget): the FULL causal prefix is visible.
3195    full: bool,
3196    /// Selected complete blocks, ascending. Empty when `full`.
3197    blocks: Vec<u32>,
3198    /// Visible prefix length (absolute row + 1). Positions
3199    /// [complete*block_size .. visible) are the always-visible incomplete tail.
3200    visible: usize,
3201}
3202
3203/// Extend the POOLED indexer-key cache to cover every complete block of `raw_keys`:
3204/// fp32 mean over the block's raw rows (offset-outer/dim-inner, the historical loop
3205/// order), k_layernorm, rope at the block-start position + pos_off. A block's pooled key
3206/// never depends on the query row, so each block is computed ONCE — bit-identical to the
3207/// historical per-(row, block) recompute.
3208#[allow(clippy::too_many_arguments)]
3209fn extend_pooled_keys(
3210    pooled_keys: &mut Vec<f32>,
3211    raw_keys: &IdxRawCache,
3212    head_dim: usize,
3213    block_size: usize,
3214    idx_k_norm: &[f32],
3215    epsilon: f32,
3216    rope_dims: usize,
3217    rope_base: f32,
3218    yarn: Option<(&[f32], f32)>,
3219    pos_off: usize,
3220) {
3221    let complete_total = raw_keys.rows(head_dim) / block_size;
3222    let cached = pooled_keys.len() / head_dim;
3223    let mut block_rows: Vec<f32> = Vec::new();
3224    for block in cached..complete_total {
3225        let start = block * block_size;
3226        // idxq lane: dequant the block's raw rows at read; the fp32 mean-pool below is
3227        // the historical op order verbatim (f32 arm: an exact copy of the same rows).
3228        raw_keys.rows_f32(start, block_size, head_dim, &mut block_rows);
3229        let mut pooled = vec![0.0f32; head_dim];
3230        for offset in 0..block_size {
3231            for dim in 0..head_dim {
3232                pooled[dim] += block_rows[offset * head_dim + dim];
3233            }
3234        }
3235        for value in &mut pooled {
3236            *value /= block_size as f32;
3237        }
3238        host_rms_norm(&mut pooled, head_dim, idx_k_norm, epsilon);
3239        host_rope_at(
3240            &mut pooled,
3241            head_dim,
3242            rope_dims,
3243            rope_base,
3244            yarn,
3245            start + pos_off,
3246        );
3247        pooled_keys.extend_from_slice(&pooled);
3248    }
3249}
3250
3251/// Comparator of the pinned tie rule: score desc, block index asc (a STRICT total order
3252/// — `total_cmp` plus the index tiebreak leaves no equal pair).
3253#[inline]
3254fn sel_cmp(scores: &[f32], a: u32, b: u32) -> std::cmp::Ordering {
3255    scores[b as usize]
3256        .total_cmp(&scores[a as usize])
3257        .then(a.cmp(&b))
3258}
3259
3260/// Top-`budget` blocks under the pinned tie rule, returned ASCENDING. Replaces the
3261/// historical full `sort_by` + `take(budget)` with `select_nth_unstable_by` under the
3262/// SAME strict total order — the kept SET is identical by definition of a total order
3263/// (both keep exactly the `budget` smallest elements under the comparator), and the
3264/// emitted ascending order erases any within-set permutation. When the block count is
3265/// large, disjoint ranges are reduced to per-range top-`budget` candidates first: any
3266/// global top-`budget` element is beaten by fewer than `budget` blocks overall, hence by
3267/// fewer than `budget` in its own range, hence survives its range cut — the union of
3268/// range winners contains the global set, and the final cut recovers it EXACTLY.
3269fn top_blocks_ascending(scores: &[f32], budget: usize, threads: usize) -> Vec<u32> {
3270    fn cut(scores: &[f32], idx: &mut Vec<u32>, budget: usize) {
3271        let k = budget.min(idx.len());
3272        if k < idx.len() {
3273            idx.select_nth_unstable_by(k - 1, |&a, &b| sel_cmp(scores, a, b));
3274            idx.truncate(k);
3275        }
3276    }
3277    let complete = scores.len();
3278    debug_assert!(budget < complete);
3279    const PAR_MIN: usize = 1 << 15;
3280    let mut candidates: Vec<u32> = if threads > 1 && complete >= PAR_MIN {
3281        let ranges: Vec<(u32, u32)> = {
3282            let per = complete.div_ceil(threads);
3283            (0..threads)
3284                .map(|i| ((i * per) as u32, ((i + 1) * per).min(complete) as u32))
3285                .filter(|(a, b)| a < b)
3286                .collect()
3287        };
3288        std::thread::scope(|scope| {
3289            let handles: Vec<_> = ranges
3290                .iter()
3291                .map(|&(a, b)| {
3292                    scope.spawn(move || {
3293                        let mut idx: Vec<u32> = (a..b).collect();
3294                        cut(scores, &mut idx, budget);
3295                        idx
3296                    })
3297                })
3298                .collect();
3299            handles
3300                .into_iter()
3301                .flat_map(|h| h.join().unwrap())
3302                .collect()
3303        })
3304    } else {
3305        (0..complete as u32).collect()
3306    };
3307    cut(scores, &mut candidates, budget);
3308    candidates.sort_unstable();
3309    candidates
3310}
3311
3312/// Score every complete block for one prepared query row (relu-sum over heads / sqrt(d),
3313/// fp32 — the reference arithmetic verbatim, reading the pooled cache). Parallel over
3314/// DISJOINT block ranges when large: per-block values are independent, so the split
3315/// changes nothing but wall time.
3316fn score_blocks(
3317    query: &[f32],
3318    pooled_keys: &[f32],
3319    heads: usize,
3320    head_dim: usize,
3321    complete: usize,
3322    scale: f32,
3323    threads: usize,
3324) -> Vec<f32> {
3325    let mut scores = vec![0.0f32; complete];
3326    let run = |scores: &mut [f32], block0: usize| {
3327        for (i, slot) in scores.iter_mut().enumerate() {
3328            let block = block0 + i;
3329            let pooled = &pooled_keys[block * head_dim..(block + 1) * head_dim];
3330            let mut score = 0.0f32;
3331            for head in 0..heads {
3332                let mut dot = 0.0f32;
3333                for dim in 0..head_dim {
3334                    dot += query[head * head_dim + dim] * pooled[dim];
3335                }
3336                score += dot.max(0.0);
3337            }
3338            *slot = score / scale;
3339        }
3340    };
3341    const PAR_MIN: usize = 1 << 14;
3342    if threads > 1 && complete >= PAR_MIN {
3343        let per = complete.div_ceil(threads);
3344        let run = &run;
3345        std::thread::scope(|scope| {
3346            for (i, chunk) in scores.chunks_mut(per).enumerate() {
3347                scope.spawn(move || run(chunk, i * per));
3348            }
3349        });
3350    } else {
3351        run(&mut scores, 0);
3352    }
3353    scores
3354}
3355
3356/// memra_reference `micro_block_selection_mask` twin over the raw-key CACHE — the decode
3357/// form of the same program in BLOCK form: per query token at absolute position
3358/// `base_pos + qt`, score the pooled complete blocks (cache: `extend_pooled_keys`), then
3359/// the pinned tie rule (score desc, block index asc) and the always-visible incomplete
3360/// tail. Values and selected sets are bit-identical to the historical per-row recompute
3361/// (see the helper docs above); rows are computed in PARALLEL when the work is large
3362/// (rows are independent; single-row chunks parallelize across block ranges instead).
3363#[allow(clippy::too_many_arguments)]
3364fn indexer_select_rows(
3365    overlay: &MicroBlockIndexPlan,
3366    rope_base: f32,
3367    // YaRN (divisors, mscale) — the indexer consumes the MAIN rotary (SEMANTICS.md §Rope),
3368    // so the caller passes the layer's shared table; `None` on the shipped config.
3369    yarn: Option<(&[f32], f32)>,
3370    epsilon: f32,
3371    idx_q_norm: &[f32],
3372    idx_k_norm: &[f32],
3373    proj_rows: &[f32],      // [t, (ih+ikv)*id] this chunk's index_qk_proj output
3374    raw_keys: &IdxRawCache, // [t_kv, id] cache INCLUDING the current chunk
3375    pooled_keys: &mut Vec<f32>,
3376    // Device scorer (long-context lane): `Some((engine, device pooled mirror, mirrored
3377    // rows))` runs block scoring on the GPU with the host twin's exact arithmetic
3378    // (thread-per-block sequential dim loop, same relu-sum, same division — bit-identical
3379    // scores, identical selected sets); the mirror grows by H2D of the new rows. `None`
3380    // keeps the pure-host path (the tiny/reference shape).
3381    mut dev: Option<(&Engine, &mut Option<CudaSlice<f32>>, &mut usize)>,
3382    base_pos: usize,
3383    t: usize,
3384    t_kv: usize,
3385    // Rope-position offset: cache row i carries absolute position i + pos_off. 0 for
3386    // the trunk; 1 for the MTP draft, whose row i holds TARGET position i + 1
3387    // (position 0 never enters the draft — SGLang alignment, SEMANTICS.md §MTP).
3388    pos_off: usize,
3389) -> Res<Vec<RowSel>> {
3390    let heads = overlay.query_heads as usize;
3391    let head_dim = overlay.head_dim as usize;
3392    let block_size = overlay.block_size as usize;
3393    let budget_blocks = overlay.budget_blocks as usize;
3394    let rope_dims = overlay.rope_dimensions as usize;
3395    let qk_width = (heads + overlay.kv_heads as usize) * head_dim;
3396    let scale = (head_dim as f32).sqrt();
3397    debug_assert_eq!(raw_keys.rows(head_dim), t_kv);
3398    extend_pooled_keys(
3399        pooled_keys,
3400        raw_keys,
3401        head_dim,
3402        block_size,
3403        idx_k_norm,
3404        epsilon,
3405        rope_dims,
3406        rope_base,
3407        yarn,
3408        pos_off,
3409    );
3410    let threads = std::thread::available_parallelism()
3411        .map(|n| n.get())
3412        .unwrap_or(1);
3413    // ---- device scoring path: mirror the new pooled rows, then score in row
3414    // sub-batches (the score slab is rows x n_blocks floats — at 250k blocks a whole
3415    // prefill chunk of rows would be terabytes, so rows batch).
3416    if let Some((e, mirror, mirrored)) = dev.as_mut() {
3417        let rows_needed: Vec<usize> = (0..t)
3418            .map(|qt| (base_pos + qt + 1) / block_size)
3419            .filter(|&c| c > budget_blocks)
3420            .collect();
3421        if let Some(&max_blocks) = rows_needed.iter().max() {
3422            let pooled_rows = pooled_keys.len() / head_dim;
3423            // Grow + fill the device mirror with any rows it does not have yet.
3424            let want = pooled_rows.max(max_blocks);
3425            // POOL_PLANES regions of `cap_rows * head_dim`: the row-major mirror, then the
3426            // dim-major `poolT` plane. The pitch of the plane is `cap_rows`, so it is baked at
3427            // allocation and a capacity change invalidates the plane's addressing — hence the
3428            // full re-mirror below rather than a strided forward copy of the old plane.
3429            if mirror
3430                .as_ref()
3431                .is_none_or(|m| m.len() < want * head_dim * POOL_PLANES)
3432            {
3433                let cap_rows = want.next_power_of_two().max(1024);
3434                let fresh = e.zeros(cap_rows * head_dim * POOL_PLANES)?;
3435                // The old growth path copied the mirrored prefix forward and kept `**mirrored`.
3436                // That is not sound for the plane (new pitch => every dim lands elsewhere), and a
3437                // half-addressed plane scores stale keys silently. Re-mirror from the host cache
3438                // instead, which holds every row and is the same source the append already uses.
3439                // Costs one H2D of the pooled cache per capacity DOUBLING (log2 times over a
3440                // fill), against a class of wrong-value bug this lane has already paid for twice.
3441                **mirror = Some(fresh);
3442                **mirrored = 0;
3443            }
3444            let m = mirror.as_mut().expect("allocated above");
3445            if pooled_rows > **mirrored {
3446                let delta = &pooled_keys[**mirrored * head_dim..pooled_rows * head_dim];
3447                let mut view = m.slice_mut(**mirrored * head_dim..pooled_rows * head_dim);
3448                e.gpu.stream().memcpy_htod(delta, &mut view)?;
3449                // `poolT`: keep the DIM-MAJOR twin of the same rows in the second half of the
3450                // buffer. Both layouts are maintained UNCONDITIONALLY and only the kernel choice
3451                // reads the seam. Two reasons, and the second is the important one:
3452                //
3453                //  - Experimental design. The append is then identical in both A/B arms, so the
3454                //    measurement isolates exactly the variable under test (the READ pattern) and
3455                //    the transpose cost cannot flatter or penalise either arm.
3456                //  - There is no silent-wrong-value mode. A seam that is flippable between timed
3457                //    rounds plus a layout that is only maintained while armed means an arm that
3458                //    was OFF for a while leaves the plane missing every row appended meanwhile —
3459                //    and a stale pooled plane scores stale keys, which reads as plausible output
3460                //    rather than as a failure. Maintaining both makes `**mirrored` the single
3461                //    truth for BOTH layouts, so a flip needs no rebuild and can leave nothing
3462                //    behind. (Same class as the `pooled_dev_rows` truncation trap already
3463                //    recorded at the rewind sites.)
3464                //
3465                // Instrument cost, stated: one pooled plane of extra VRAM (33.5 MB at the 262,144
3466                // target geometry, 1.6% of the ~2 GB free there) plus one transpose over the
3467                // delta — 512 rows per 2,048-token prefill chunk, 0-1 rows per decode step. When
3468                // the A/B verdict lands, the losing layout goes away in the same commit; carrying
3469                // both is an A/B instrument, not a shipping design.
3470                let cap_rows = m.len() / (head_dim * POOL_PLANES);
3471                launch_qsa_pooled_transpose(
3472                    e,
3473                    m,
3474                    **mirrored,
3475                    pooled_rows - **mirrored,
3476                    head_dim,
3477                    cap_rows,
3478                )?;
3479                **mirrored = pooled_rows;
3480            }
3481            // Per-row prepared queries (norm + rope) — the host twin's own preparation.
3482            let mut sels: Vec<RowSel> = Vec::with_capacity(t);
3483            let mut queries: Vec<f32> = Vec::new();
3484            let mut scored_rows: Vec<usize> = Vec::new();
3485            for qt in 0..t {
3486                let row = base_pos + qt;
3487                let visible = row + 1;
3488                let complete = visible / block_size;
3489                if complete <= budget_blocks {
3490                    sels.push(RowSel {
3491                        full: true,
3492                        blocks: Vec::new(),
3493                        visible,
3494                    });
3495                    continue;
3496                }
3497                let mut query = proj_rows[qt * qk_width..qt * qk_width + heads * head_dim].to_vec();
3498                host_rms_norm(&mut query, head_dim, idx_q_norm, epsilon);
3499                host_rope_at(
3500                    &mut query,
3501                    head_dim,
3502                    rope_dims,
3503                    rope_base,
3504                    yarn,
3505                    row + pos_off,
3506                );
3507                queries.extend_from_slice(&query);
3508                scored_rows.push(qt);
3509                sels.push(RowSel {
3510                    full: false,
3511                    blocks: Vec::new(),
3512                    visible,
3513                });
3514            }
3515            // Row sub-batches bounded by the score slab (default 32 M floats = 128 MB).
3516            //
3517            // TUNABLE because this constant appears to SET THE 262k PERFORMANCE CLIFF.
3518            // `qsa.idx_host` grows linearly with fill up to 120,000 (2,710 -> 3,199 ms) and then
3519            // jumps 16x to 51,235 ms — 83% of a prefill chunk — somewhere before 131,072. The
3520            // arithmetic lands exactly there: rows per sub-batch is `SCORE_CAP / complete`, and
3521            // at fill 131,072 `complete = 32,768`, so `per = 1,024` and 2,048 scored rows fit in
3522            // EXACTLY 2 sub-batches; one block deeper it becomes 3. Each sub-batch does an
3523            // `e.htod` plus an `e.uninit` of up to 128 MB and ends in a BLOCKING `dtoh`, at
3524            // depths where card 0 has ~2-4 GB free.
3525            //
3526            // The test this knob exists for: if the cliff MOVES with the cap, the mechanism is
3527            // the sub-batch transition (and the fix is a persistent pooled slab, or a cap that
3528            // keeps the transition out of the product window). If the cliff does NOT move, the
3529            // hypothesis is dead and the next suspect is the blocking dtoh count.
3530            // Default 32 reproduces today's behaviour exactly.
3531            let score_cap_mf: usize = std::env::var("MEMRA_Q4E_IDX_SCORE_CAP_MF")
3532                .ok()
3533                .and_then(|v| v.parse::<usize>().ok())
3534                .filter(|v| *v > 0)
3535                .unwrap_or(32);
3536            let score_cap: usize = score_cap_mf << 20;
3537            #[allow(non_snake_case)]
3538            let SCORE_CAP = score_cap;
3539            let mut done = 0usize;
3540            while done < scored_rows.len() {
3541                // Every row in a batch scores its OWN block count; the kernel writes a
3542                // rows x max_blocks slab and each row reads its own prefix.
3543                let batch_max = scored_rows[done..]
3544                    .iter()
3545                    .map(|&qt| (base_pos + qt + 1) / block_size)
3546                    .max()
3547                    .unwrap_or(0);
3548                let per = (SCORE_CAP / batch_max.max(1)).max(1);
3549                let n = per.min(scored_rows.len() - done);
3550                let qslab = &queries[done * heads * head_dim..(done + n) * heads * head_dim];
3551                let q_dev = e.htod(qslab)?;
3552                let mut scores_dev = e.uninit(n * batch_max)?;
3553                launch_qsa_index_score(
3554                    e,
3555                    &q_dev,
3556                    m,
3557                    &mut scores_dev,
3558                    heads,
3559                    head_dim,
3560                    batch_max,
3561                    n,
3562                    scale,
3563                )?;
3564                if idx_sel_on() {
3565                    // Device selection (`idxsel`): read back rows x budget u32 instead of
3566                    // the rows x batch_max f32 slab, and never touch the scores on the
3567                    // host at all. The audit arm below is the ONLY thing that restores
3568                    // the slab dtoh, which is why it is an instrument and not an arm.
3569                    let counts: Vec<usize> = (0..n)
3570                        .map(|i| (base_pos + scored_rows[done + i] + 1) / block_size)
3571                        .collect();
3572                    let picked =
3573                        launch_qsa_index_topk(e, &scores_dev, &counts, batch_max, budget_blocks)?;
3574                    if idx_sel_audit_on() {
3575                        let host = e.dtoh(&scores_dev)?;
3576                        let mut mismatched = 0u64;
3577                        let mut deepest = 0u64;
3578                        for i in 0..n {
3579                            let complete = counts[i];
3580                            let row_scores = &host[i * batch_max..i * batch_max + complete];
3581                            let twin = top_blocks_ascending(row_scores, budget_blocks, threads);
3582                            if twin != picked[i] {
3583                                mismatched += 1;
3584                            }
3585                            deepest = deepest.max(complete as u64);
3586                        }
3587                        IDX_SEL_AUDIT_ROWS
3588                            .fetch_add(n as u64, std::sync::atomic::Ordering::Relaxed);
3589                        IDX_SEL_AUDIT_MISMATCH
3590                            .fetch_add(mismatched, std::sync::atomic::Ordering::Relaxed);
3591                        IDX_SEL_AUDIT_MAX_BLOCKS
3592                            .fetch_max(deepest, std::sync::atomic::Ordering::Relaxed);
3593                        if mismatched > 0 {
3594                            return Err(format!(
3595                                "idxsel audit: {mismatched} of {n} device selections differ \
3596                                 from the host twin (ids or order) at fill {t_kv}"
3597                            )
3598                            .into());
3599                        }
3600                    }
3601                    for (i, blocks) in picked.into_iter().enumerate() {
3602                        sels[scored_rows[done + i]].blocks = blocks;
3603                    }
3604                } else {
3605                    let host = e.dtoh(&scores_dev)?;
3606                    for i in 0..n {
3607                        let qt = scored_rows[done + i];
3608                        let complete = (base_pos + qt + 1) / block_size;
3609                        let row_scores = &host[i * batch_max..i * batch_max + complete];
3610                        sels[qt].blocks = top_blocks_ascending(row_scores, budget_blocks, threads);
3611                    }
3612                }
3613                done += n;
3614            }
3615            for sel in &sels {
3616                if sel.visible == 0
3617                    || (!sel.full && sel.blocks.is_empty() && sel.visible % block_size == 0)
3618                {
3619                    return Err("indexer selection left a query with no visible source".into());
3620                }
3621            }
3622            return Ok(sels);
3623        }
3624    }
3625    let pooled_ref: &[f32] = pooled_keys;
3626    let select_row = |qt: usize, threads_in_row: usize| -> RowSel {
3627        let row = base_pos + qt;
3628        let position = row + pos_off;
3629        let visible = row + 1;
3630        let complete = visible / block_size;
3631        // Structural fast path (perf lane, semantic no-op): with complete <= budget the
3632        // top-k keeps EVERY complete block whatever the scores say, and the incomplete
3633        // tail is always visible — the row is the full causal prefix. Real geometry:
3634        // budget 512 x block 4 => every position < 2051 takes this path (SEMANTICS.md
3635        // §QSA); the scoring arm below stays the reference for long contexts and is
3636        // exercised by the tiny gate's budget-2 fixture at every position past 11.
3637        if complete <= budget_blocks {
3638            return RowSel {
3639                full: true,
3640                blocks: Vec::new(),
3641                visible,
3642            };
3643        }
3644        let mut query = proj_rows[qt * qk_width..qt * qk_width + heads * head_dim].to_vec();
3645        host_rms_norm(&mut query, head_dim, idx_q_norm, epsilon);
3646        host_rope_at(&mut query, head_dim, rope_dims, rope_base, yarn, position);
3647        let scores = score_blocks(
3648            &query,
3649            pooled_ref,
3650            heads,
3651            head_dim,
3652            complete,
3653            scale,
3654            threads_in_row,
3655        );
3656        let blocks = top_blocks_ascending(&scores, budget_blocks, threads_in_row);
3657        RowSel {
3658            full: false,
3659            blocks,
3660            visible,
3661        }
3662    };
3663    const ROW_PAR_MIN_WORK: usize = 1 << 16;
3664    let total_scored_blocks: usize = (0..t)
3665        .map(|qt| {
3666            let complete = (base_pos + qt + 1) / block_size;
3667            if complete <= budget_blocks {
3668                0
3669            } else {
3670                complete
3671            }
3672        })
3673        .sum();
3674    let sels: Vec<RowSel> = if t > 1 && threads > 1 && total_scored_blocks >= ROW_PAR_MIN_WORK {
3675        // Rows are independent: a work-stealing cursor over rows, each row sequential
3676        // inside (identical arithmetic to the sequential path).
3677        let cursor = std::sync::atomic::AtomicUsize::new(0);
3678        let mut out: Vec<Option<RowSel>> = (0..t).map(|_| None).collect();
3679        let slots = std::sync::Mutex::new(&mut out);
3680        std::thread::scope(|scope| {
3681            for _ in 0..threads.min(t) {
3682                scope.spawn(|| {
3683                    loop {
3684                        let qt = cursor.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
3685                        if qt >= t {
3686                            break;
3687                        }
3688                        let sel = select_row(qt, 1);
3689                        slots.lock().unwrap()[qt] = Some(sel);
3690                    }
3691                });
3692            }
3693        });
3694        out.into_iter().map(|s| s.unwrap()).collect()
3695    } else {
3696        (0..t).map(|qt| select_row(qt, threads)).collect()
3697    };
3698    for sel in &sels {
3699        if sel.visible == 0 || (!sel.full && sel.blocks.is_empty() && sel.visible % block_size == 0)
3700        {
3701            return Err("indexer selection left a query with no visible source".into());
3702        }
3703    }
3704    Ok(sels)
3705}
3706
3707/// Render row selections as the dense [t, t_kv] u8 mask the smem-bounded masked kernel
3708/// consumes — byte-identical to the historical `indexer_mask_rows` output.
3709fn rowsel_to_mask(sels: &[RowSel], block_size: usize, t_kv: usize) -> Vec<u8> {
3710    let t = sels.len();
3711    let mut mask = vec![0u8; t * t_kv];
3712    for (qt, sel) in sels.iter().enumerate() {
3713        let row = &mut mask[qt * t_kv..(qt + 1) * t_kv];
3714        if sel.full {
3715            for slot in row.iter_mut().take(sel.visible) {
3716                *slot = 1;
3717            }
3718            continue;
3719        }
3720        for &block in &sel.blocks {
3721            for offset in 0..block_size {
3722                row[block as usize * block_size + offset] = 1;
3723            }
3724        }
3725        let complete = sel.visible / block_size;
3726        for slot in row.iter_mut().take(sel.visible).skip(complete * block_size) {
3727            *slot = 1;
3728        }
3729    }
3730    mask
3731}
3732
3733/// Render row selections as ASCENDING position lists for the block-list attention
3734/// kernel: flat i32 positions + per-row (offset, count) meta. Every row is bounded by
3735/// budget*block + (block-1) + ... <= 2052 positions on real geometry, so the kernel's
3736/// smem stays fixed whatever t_kv is.
3737fn rowsel_positions(sels: &[RowSel], block_size: usize) -> (Vec<i32>, Vec<i32>, usize) {
3738    let mut flat: Vec<i32> = Vec::new();
3739    let mut meta: Vec<i32> = Vec::with_capacity(sels.len() * 2);
3740    let mut max_count = 0usize;
3741    for sel in sels {
3742        let start = flat.len();
3743        if sel.full {
3744            flat.extend(0..sel.visible as i32);
3745        } else {
3746            for &block in &sel.blocks {
3747                let first = block as usize * block_size;
3748                flat.extend(first as i32..(first + block_size) as i32);
3749            }
3750            let complete = sel.visible / block_size;
3751            flat.extend((complete * block_size) as i32..sel.visible as i32);
3752        }
3753        let count = flat.len() - start;
3754        max_count = max_count.max(count);
3755        meta.push(start as i32);
3756        meta.push(count as i32);
3757    }
3758    (flat, meta, max_count)
3759}
3760
3761/// One launch of the QSA indexer block scorer (`qsa_index_score_f32`): thread-per-block
3762/// over a [rows, n_blocks] slab. Per-score arithmetic is the host twin's verbatim (same
3763/// dim order, same relu-sum, same division by sqrt(head_dim)) — bit-identical scores.
3764#[allow(clippy::too_many_arguments)]
3765fn launch_qsa_index_score(
3766    e: &Engine,
3767    q: &CudaSlice<f32>,
3768    pooled: &CudaSlice<f32>,
3769    out: &mut CudaSlice<f32>,
3770    heads: usize,
3771    head_dim: usize,
3772    n_blocks: usize,
3773    rows: usize,
3774    scale: f32,
3775) -> Res<()> {
3776    if rows == 0 || n_blocks == 0 {
3777        return Ok(());
3778    }
3779    if out.len() < rows * n_blocks {
3780        return Err("qsa_index_score_f32: score slab too short".into());
3781    }
3782    if rows > 65535 {
3783        return Err("qsa_index_score_f32: rows exceed grid.y (caller sub-batches)".into());
3784    }
3785    // `poolT`: read the dim-major plane in the second half of the mirror (bit-identical twin —
3786    // see POOL_T_DEFAULT). The plane's pitch is the mirror's block CAPACITY, not `n_blocks`:
3787    // passing `n_blocks` would read dim d of block b as dim d of some other block for every
3788    // d > 0, which is silent wrong values, so the pitch is derived from the allocation.
3789    let cap_rows = pooled.len() / (head_dim * POOL_PLANES);
3790    let pool_t = pool_t_on();
3791    if pool_t && cap_rows < n_blocks {
3792        return Err("qsa_index_score_f32_t: pooled plane capacity below n_blocks".into());
3793    }
3794    let f = e.func(if pool_t {
3795        "qsa_index_score_f32_t"
3796    } else {
3797        "qsa_index_score_f32"
3798    });
3799    const TPB: usize = 128;
3800    let cfg = LaunchConfig {
3801        grid_dim: (n_blocks.div_ceil(TPB) as u32, rows as u32, 1),
3802        block_dim: (TPB as u32, 1, 1),
3803        shared_mem_bytes: 0,
3804    };
3805    let (h, hd, nb, r) = (heads as i32, head_dim as i32, n_blocks as i32, rows as i32);
3806    let pitch = cap_rows as i64;
3807    let stream = e.gpu.stream();
3808    if pool_t {
3809        // The plane starts at `cap_rows * head_dim`; the kernel indexes `pooled_t[d*pitch + b]`
3810        // from that base, so the slice is the plane region, not the whole buffer.
3811        let plane = pooled.slice(cap_rows * head_dim..cap_rows * head_dim * POOL_PLANES);
3812        let mut b = stream.launch_builder(&f);
3813        b.arg(q)
3814            .arg(&plane)
3815            .arg(&mut *out)
3816            .arg(&h)
3817            .arg(&hd)
3818            .arg(&nb)
3819            .arg(&r)
3820            .arg(&scale)
3821            .arg(&pitch);
3822        unsafe {
3823            b.launch(cfg)?;
3824        }
3825        return Ok(());
3826    }
3827    let mut b = stream.launch_builder(&f);
3828    b.arg(q)
3829        .arg(pooled)
3830        .arg(&mut *out)
3831        .arg(&h)
3832        .arg(&hd)
3833        .arg(&nb)
3834        .arg(&r)
3835        .arg(&scale);
3836    unsafe {
3837        b.launch(cfg)?;
3838    }
3839    Ok(())
3840}
3841
3842/// How many `cap_rows * head_dim` regions the pooled device mirror carries: the row-major
3843/// mirror, then the dim-major `poolT` plane. See the append site for why both are maintained
3844/// unconditionally (A/B isolation, and no stale-plane failure mode on a mid-run seam flip).
3845const POOL_PLANES: usize = 2;
3846
3847/// Mirror the freshly-appended pooled rows `[r0, r0+rows)` into the dim-major plane. Pure data
3848/// movement inside one buffer; `cap_rows` is the plane pitch (the mirror's block capacity).
3849fn launch_qsa_pooled_transpose(
3850    e: &Engine,
3851    buf: &mut CudaSlice<f32>,
3852    r0: usize,
3853    rows: usize,
3854    head_dim: usize,
3855    cap_rows: usize,
3856) -> Res<()> {
3857    if rows == 0 {
3858        return Ok(());
3859    }
3860    if r0 + rows > cap_rows {
3861        return Err("qsa_pooled_transpose_f32: delta exceeds the plane capacity".into());
3862    }
3863    let f = e.func("qsa_pooled_transpose_f32");
3864    const TPB: usize = 128;
3865    let cfg = LaunchConfig {
3866        grid_dim: (rows.div_ceil(TPB) as u32, head_dim as u32, 1),
3867        block_dim: (TPB as u32, 1, 1),
3868        shared_mem_bytes: 0,
3869    };
3870    let (r, hd, r0i) = (rows as i32, head_dim as i32, r0 as i32);
3871    let cap = cap_rows as i64;
3872    let stream = e.gpu.stream();
3873    let mut b = stream.launch_builder(&f);
3874    b.arg(buf).arg(&r).arg(&hd).arg(&r0i).arg(&cap);
3875    unsafe {
3876        b.launch(cfg)?;
3877    }
3878    Ok(())
3879}
3880
3881/// One launch of the device indexer top-k (`qsa_index_topk_u32`) over a score slab, plus
3882/// the structural checks that make a silent mis-write loud: every row's block count must
3883/// EXCEED the budget (so the row genuinely needs a selection and every out slot is
3884/// written), and the returned lists come back strictly ascending and in range. Returns the
3885/// `rows x budget` block ids.
3886fn launch_qsa_index_topk(
3887    e: &Engine,
3888    scores: &CudaSlice<f32>,
3889    counts: &[usize],
3890    stride: usize,
3891    budget: usize,
3892) -> Res<Vec<Vec<u32>>> {
3893    let rows = counts.len();
3894    if rows == 0 || budget == 0 {
3895        return Ok(Vec::new());
3896    }
3897    if rows > 65535 {
3898        return Err("qsa_index_topk_u32: rows exceed grid.x (caller sub-batches)".into());
3899    }
3900    if scores.len() < rows * stride {
3901        return Err("qsa_index_topk_u32: score slab too short".into());
3902    }
3903    for (r, &c) in counts.iter().enumerate() {
3904        if c <= budget || c > stride {
3905            return Err(format!(
3906                "qsa_index_topk_u32: row {r} block count {c} outside (budget {budget}, \
3907                 stride {stride}] — the caller only routes scored rows here"
3908            )
3909            .into());
3910        }
3911    }
3912    let counts_i32: Vec<i32> = counts.iter().map(|&c| c as i32).collect();
3913    let counts_dev = e.htod_i32(&counts_i32)?;
3914    // -1 fill: an unwritten slot is then VISIBLE (the check below), not a plausible block.
3915    let mut out = e.htod_i32(&vec![-1i32; rows * budget])?;
3916    let f = e.func("qsa_index_topk_u32");
3917    let cfg = LaunchConfig {
3918        grid_dim: (rows as u32, 1, 1),
3919        block_dim: (256, 1, 1),
3920        shared_mem_bytes: 0,
3921    };
3922    let (st, bu, ro) = (stride as i32, budget as i32, rows as i32);
3923    let stream = e.gpu.stream();
3924    let mut b = stream.launch_builder(&f);
3925    b.arg(scores)
3926        .arg(&counts_dev)
3927        .arg(&mut out)
3928        .arg(&st)
3929        .arg(&bu)
3930        .arg(&ro);
3931    unsafe {
3932        b.launch(cfg)?;
3933    }
3934    let host = e.gpu.stream().clone_dtoh(&out)?;
3935    e.gpu.stream().synchronize()?;
3936    let mut out_rows: Vec<Vec<u32>> = Vec::with_capacity(rows);
3937    for r in 0..rows {
3938        let row = &host[r * budget..(r + 1) * budget];
3939        let mut blocks: Vec<u32> = Vec::with_capacity(budget);
3940        let mut prev: i64 = -1;
3941        for (j, &v) in row.iter().enumerate() {
3942            if v < 0 || (v as usize) >= counts[r] || (v as i64) <= prev {
3943                return Err(format!(
3944                    "qsa_index_topk_u32: row {r} slot {j} = {v} is not a strictly ascending \
3945                     in-range block id (blocks {}, budget {budget})",
3946                    counts[r]
3947                )
3948                .into());
3949            }
3950            prev = v as i64;
3951            blocks.push(v as u32);
3952        }
3953        out_rows.push(blocks);
3954    }
3955    Ok(out_rows)
3956}
3957
3958/// One launch of the row-window column-slice copy (`copy_rows_col_f32`): append the
3959/// k-part of `rows` idx_proj rows (column offset `src_col`, row stride `src_stride`)
3960/// to the device raw-key cache at row `dst_row`. Exact byte moves, no arithmetic.
3961#[allow(clippy::too_many_arguments)]
3962fn launch_copy_rows_col(
3963    e: &Engine,
3964    src: &CudaSlice<f32>,
3965    dst: &mut CudaSlice<f32>,
3966    rows: usize,
3967    width: usize,
3968    src_stride: usize,
3969    src_col: usize,
3970    dst_row: usize,
3971) -> Res<()> {
3972    if rows == 0 {
3973        return Ok(());
3974    }
3975    if src.len() < (rows - 1) * src_stride + src_col + width || dst.len() < (dst_row + rows) * width
3976    {
3977        return Err("copy_rows_col_f32: window out of range".into());
3978    }
3979    let f = e.func("copy_rows_col_f32");
3980    let total = rows * width;
3981    let cfg = LaunchConfig::for_num_elems(total as u32);
3982    let (r, w) = (rows as i32, width as i32);
3983    let (ss, sc, dr) = (src_stride as i64, src_col as i64, dst_row as i64);
3984    let stream = e.gpu.stream();
3985    let mut b = stream.launch_builder(&f);
3986    b.arg(src)
3987        .arg(&mut *dst)
3988        .arg(&r)
3989        .arg(&w)
3990        .arg(&ss)
3991        .arg(&sc)
3992        .arg(&dr);
3993    unsafe {
3994        b.launch(cfg)?;
3995    }
3996    Ok(())
3997}
3998
3999/// One launch of the device MoE router (`qwen4exp_route_topk_f32`): per token row, the
4000/// full host_route_softmax_topk program on device (kernel doc — order-sensitive
4001/// reductions sequential on thread 0, host op order verbatim; exp through double).
4002/// `tok` = optional (slot->token map, tok_base) for the gufuse merged verify path.
4003/// Geometry guards live in the CALLER's engage condition; violations here are errors,
4004/// never silent fallbacks.
4005#[allow(clippy::too_many_arguments)]
4006fn launch_route_topk(
4007    e: &Engine,
4008    logits: &CudaSlice<f32>,
4009    sel: &mut CudaSlice<i32>,
4010    w: &mut CudaSlice<f32>,
4011    tok: Option<(&mut CudaSlice<i32>, usize)>,
4012    experts: usize,
4013    selected: usize,
4014    rows: usize,
4015) -> Res<()> {
4016    if rows == 0 {
4017        return Ok(());
4018    }
4019    if selected == 0 || selected > 32 || selected > experts {
4020        return Err("qwen4exp_route_topk_f32: selected out of range (caller guards)".into());
4021    }
4022    if experts % 2 != 0 {
4023        // The u64 key slab sits after the f32 weight slab in dynamic smem; an even
4024        // expert count keeps it 8-byte aligned (caller guards via route_dev_geometry).
4025        return Err("qwen4exp_route_topk_f32: odd expert count".into());
4026    }
4027    if logits.len() < rows * experts || sel.len() < rows * selected || w.len() < rows * selected {
4028        return Err("qwen4exp_route_topk_f32: buffer too short".into());
4029    }
4030    let smem = experts * 12; // f32 weights + u64 selection keys
4031    if smem > 48 * 1024 {
4032        return Err("qwen4exp_route_topk_f32: experts exceed the smem bound".into());
4033    }
4034    let stream = e.gpu.stream();
4035    let (tok_raw, tok_base) = match tok {
4036        Some((buf, base)) => {
4037            if buf.len() < rows * selected {
4038                return Err("qwen4exp_route_topk_f32: tok map too short".into());
4039            }
4040            (buf.device_ptr(&stream).0, base)
4041        }
4042        None => (0u64, 0usize),
4043    };
4044    let f = e.func("qwen4exp_route_topk_f32");
4045    let cfg = LaunchConfig {
4046        grid_dim: (rows as u32, 1, 1),
4047        block_dim: (128, 1, 1),
4048        shared_mem_bytes: smem as u32,
4049    };
4050    let (ex, se, ro, tb) = (
4051        experts as i32,
4052        selected as i32,
4053        rows as i32,
4054        tok_base as i32,
4055    );
4056    let floor = ROUTE_DENOM_FLOOR;
4057    let mut b = stream.launch_builder(&f);
4058    b.arg(logits)
4059        .arg(&mut *sel)
4060        .arg(&mut *w)
4061        .arg(&tok_raw)
4062        .arg(&ex)
4063        .arg(&se)
4064        .arg(&ro)
4065        .arg(&tb)
4066        .arg(&floor);
4067    unsafe {
4068        b.launch(cfg)?;
4069    }
4070    Ok(())
4071}
4072
4073/// Device route + (MEMRA_Q4E_ROUTER_AUDIT=1) the host-twin cross-check over the SAME
4074/// logits: selection ids order-exact or Err; weights within ROUTE_AUDIT_ULP_BOUND ULP,
4075/// worst observed kept for the gate receipt (`route_audit_stats`).
4076#[allow(clippy::too_many_arguments)]
4077fn route_topk_device(
4078    e: &Engine,
4079    logits: &CudaSlice<f32>,
4080    sel: &mut CudaSlice<i32>,
4081    w: &mut CudaSlice<f32>,
4082    tok: Option<(&mut CudaSlice<i32>, usize)>,
4083    experts: usize,
4084    selected: usize,
4085    rows: usize,
4086    layer: u32,
4087) -> Res<()> {
4088    launch_route_topk(e, logits, sel, w, tok, experts, selected, rows)?;
4089    if !router_audit_on() {
4090        return Ok(());
4091    }
4092    let k = selected.min(experts);
4093    let lg = e.dtoh_view(&logits.slice(0..rows * experts))?;
4094    let sel_h = e.gpu.stream().clone_dtoh(&sel.slice(0..rows * selected))?;
4095    let w_h = e.gpu.stream().clone_dtoh(&w.slice(0..rows * selected))?;
4096    // Emit the shared-format route trace off THIS readback (`trace_moe_routes`, the frozen
4097    // `memra-ep-map-v1` producer). Its own doc comment already promised exactly this — "arming
4098    // MEMRA_Q4E_ROUTER_AUDIT=1 restores a host recompute of every device route and the trace
4099    // rides THAT readback at zero new syncs ... single-card batteries trace with the audit
4100    // armed" — but the call was never made, so the tracer fired ONLY from the TP2 paths and the
4101    // shipped single-card device-routed default emitted nothing at all. The box's traces
4102    // directory was empty for that reason and not for lack of running, and the expert-placement
4103    // lane's only input silently did not exist. Prose describing a wiring that is not there is
4104    // the failure class this lane has hit twice; the wiring is here now.
4105    //
4106    // Traced from the DEVICE arrays, not from the host twin below: the trace must record the
4107    // route that actually ran. The audit's job is to prove the two agree, and it does that on
4108    // the next lines — so if they ever disagree this call has already errored out.
4109    {
4110        let routes: Vec<Vec<(usize, f32)>> = (0..rows)
4111            .map(|row| {
4112                (0..selected)
4113                    .map(|j| {
4114                        (
4115                            sel_h[row * selected + j].max(0) as usize,
4116                            w_h[row * selected + j],
4117                        )
4118                    })
4119                    .collect()
4120            })
4121            .collect();
4122        trace_moe_routes(layer, rows, &routes);
4123    }
4124    let mut worst: u32 = 0;
4125    for row in 0..rows {
4126        let twin = host_route_softmax_topk(&lg[row * experts..(row + 1) * experts], selected);
4127        if twin.len() != k {
4128            return Err("router audit: host twin emitted an unexpected selection width".into());
4129        }
4130        for (j, &(idx, wt)) in twin.iter().enumerate() {
4131            let ds = sel_h[row * selected + j];
4132            let dw = w_h[row * selected + j];
4133            if ds != idx as i32 {
4134                return Err(format!(
4135                    "router audit: selection mismatch at row {row} slot {j}: \
4136                     device {ds} vs host {idx} (host w {wt:e})"
4137                )
4138                .into());
4139            }
4140            let ulp = (dw.to_bits() as i64 - wt.to_bits() as i64).unsigned_abs();
4141            let ulp = u32::try_from(ulp).unwrap_or(u32::MAX);
4142            worst = worst.max(ulp);
4143            if ulp > ROUTE_AUDIT_ULP_BOUND {
4144                return Err(format!(
4145                    "router audit: weight ULP {ulp} > bound {ROUTE_AUDIT_ULP_BOUND} at \
4146                     row {row} slot {j}: device {dw:e} vs host {wt:e}"
4147                )
4148                .into());
4149            }
4150        }
4151    }
4152    ROUTE_AUDIT_ROWS.fetch_add(rows as u64, std::sync::atomic::Ordering::Relaxed);
4153    ROUTE_AUDIT_MAX_ULP.fetch_max(worst, std::sync::atomic::Ordering::Relaxed);
4154    Ok(())
4155}
4156
4157/// The historical mask-producing entry point, now select + render (byte-identical mask;
4158/// the TP2 decode path and the masked-kernel arm consume it).
4159// dead_code: bring-up scaffolding the in-flight qwen4exp lanes still call; not deleted in
4160// the clippy-zero lane (bit-neutral by construction).
4161#[allow(dead_code)]
4162#[allow(clippy::too_many_arguments)]
4163fn indexer_mask_rows(
4164    overlay: &MicroBlockIndexPlan,
4165    rope_base: f32,
4166    yarn: Option<(&[f32], f32)>,
4167    epsilon: f32,
4168    idx_q_norm: &[f32],
4169    idx_k_norm: &[f32],
4170    proj_rows: &[f32],
4171    raw_keys: &IdxRawCache,
4172    pooled_keys: &mut Vec<f32>,
4173    base_pos: usize,
4174    t: usize,
4175    t_kv: usize,
4176    pos_off: usize,
4177) -> Res<Vec<u8>> {
4178    let sels = indexer_select_rows(
4179        overlay,
4180        rope_base,
4181        yarn,
4182        epsilon,
4183        idx_q_norm,
4184        idx_k_norm,
4185        proj_rows,
4186        raw_keys,
4187        pooled_keys,
4188        // TP2 decode + the reference/mask arm keep the host scorer (TP2's selection runs
4189        // on card 0's projection and feeds both halves; its depths are decode-class).
4190        None,
4191        base_pos,
4192        t,
4193        t_kv,
4194        pos_off,
4195    )?;
4196    Ok(rowsel_to_mask(&sels, overlay.block_size as usize, t_kv))
4197}
4198
4199/// memra_reference `shift_right_ignore_eos` twin.
4200fn shift_right_ignore_eos(history: &[i64], shift: usize, eos: i64) -> Vec<i64> {
4201    if shift == 0 {
4202        return history.to_vec();
4203    }
4204    let mut last_eos_inclusive: i64 = -1;
4205    let mut output = Vec::with_capacity(history.len());
4206    for (position, &token) in history.iter().enumerate() {
4207        let previous_eos = last_eos_inclusive;
4208        if token == eos {
4209            last_eos_inclusive = position as i64;
4210        }
4211        let segment_start = previous_eos + 1;
4212        let position_in_segment = position as i64 - segment_start;
4213        let source = position as i64 - shift as i64;
4214        let valid = position_in_segment >= shift as i64 && source >= 0;
4215        output.push(if valid { history[source as usize] } else { eos });
4216    }
4217    output
4218}
4219
4220/// INCREMENTAL twin of `host_ngram_ids` (`plecache` seam, 262k perf lane): extend a cached
4221/// id vector to cover `token_ids` instead of rebuilding it. Returns the last `t` rows'
4222/// worth of ids, i.e. exactly what the caller slices.
4223///
4224/// Bit-identical to `host_ngram_ids` by construction, not by tolerance. Two local facts do
4225/// it. (1) `shift_right_ignore_eos` at position p emits `history[p - shift]` guarded by an
4226/// eos scan that only moves left-to-right, so its value at p depends on `history[..=p]`
4227/// alone. (2) the id loop at `token` reads only `shifted[*][context + token]`. Therefore
4228/// `ids[token]` is a pure function of `token_ids[..=token]` and never changes when a token
4229/// is appended — so appending rows is not an approximation of rebuilding them, it is the
4230/// same arithmetic in the same order on the same inputs.
4231///
4232/// A shrinking or diverging history (spec reject / rewind / a fresh sequence in a reused
4233/// state) is handled by TRUNCATING the cache to the longest common prefix and re-extending.
4234/// The check is a real prefix compare rather than a length compare, because a length-only
4235/// check would silently keep another sequence's hashes — the failure mode would be fluent
4236/// output from the wrong n-gram rows, which is invisible.
4237#[allow(clippy::too_many_arguments)]
4238fn host_ngram_ids_cached(
4239    cache_ids: &mut Vec<i64>,
4240    cache_history: &mut Vec<i64>,
4241    cache_last_eos: &mut i64,
4242    token_ids: &[u32],
4243    multipliers: &[i64],
4244    sizes: &[i64],
4245    offsets: &[i64],
4246    max_ngram: usize,
4247    heads_per_ngram: usize,
4248    eos_token_id: u32,
4249) {
4250    let context = max_ngram - 1;
4251    let eos = eos_token_id as i64;
4252    let total_heads = (max_ngram - 1) * heads_per_ngram;
4253    if cache_history.is_empty() {
4254        cache_history.extend(std::iter::repeat_n(eos, context));
4255        *cache_last_eos = context as i64 - 1; // every prefix row IS an eos
4256        cache_ids.clear();
4257    }
4258    let cached_tokens = (cache_history.len() - context).min(cache_ids.len() / total_heads);
4259    // Longest common prefix of the cached tokens and the requested ones.
4260    let mut keep = cached_tokens.min(token_ids.len());
4261    for i in 0..keep {
4262        if cache_history[context + i] != token_ids[i] as i64 {
4263            keep = i;
4264            break;
4265        }
4266    }
4267    if keep < cached_tokens {
4268        // Rewind: drop the diverged tail and rebuild the eos scan over what survives.
4269        cache_history.truncate(context + keep);
4270        cache_ids.truncate(keep * total_heads);
4271        *cache_last_eos = cache_history
4272            .iter()
4273            .rposition(|&v| v == eos)
4274            .map(|p| p as i64)
4275            .unwrap_or(-1);
4276    }
4277    for &token in &token_ids[keep..] {
4278        let position = cache_history.len();
4279        let value = token as i64;
4280        cache_history.push(value);
4281        // `shift_right_ignore_eos`: `previous_eos` is read BEFORE this position updates it.
4282        let previous_eos = *cache_last_eos;
4283        if value == eos {
4284            *cache_last_eos = position as i64;
4285        }
4286        let segment_start = previous_eos + 1;
4287        let position_in_segment = position as i64 - segment_start;
4288        let shifted_at = |shift: usize| -> i64 {
4289            if shift == 0 {
4290                return cache_history[position];
4291            }
4292            let source = position as i64 - shift as i64;
4293            if position_in_segment >= shift as i64 && source >= 0 {
4294                cache_history[source as usize]
4295            } else {
4296                eos
4297            }
4298        };
4299        // Same op order as the twin: shift 0 multiply, then xor the higher shifts in order.
4300        let mut row = vec![0i64; total_heads];
4301        for ngram in 2..=max_ngram {
4302            let head_start = (ngram - 2) * heads_per_ngram;
4303            let mut mixed = shifted_at(0).wrapping_mul(multipliers[0]);
4304            for shift in 1..ngram {
4305                mixed ^= shifted_at(shift).wrapping_mul(multipliers[shift]);
4306            }
4307            for head in 0..heads_per_ngram {
4308                let index = head_start + head;
4309                row[index] = mixed.rem_euclid(sizes[index]) + offsets[index];
4310            }
4311        }
4312        cache_ids.extend_from_slice(&row);
4313    }
4314    debug_assert_eq!(cache_ids.len(), token_ids.len() * total_heads);
4315    // Returns nothing on purpose: the caller reads the tail of `cache_ids` in place. Handing
4316    // back a `Vec` would clone the whole history's ids on every decode step (19 MB at a
4317    // 150,000-token fill), which is the O(context) cost this seam exists to delete.
4318}
4319
4320/// memra_reference `ngram_ids` twin over the FULL token history (context EOS rows
4321/// prepended); the caller slices the last `t` rows for the current chunk.
4322fn host_ngram_ids(
4323    token_ids: &[u32],
4324    multipliers: &[i64],
4325    sizes: &[i64],
4326    offsets: &[i64],
4327    max_ngram: usize,
4328    heads_per_ngram: usize,
4329    eos_token_id: u32,
4330) -> Vec<i64> {
4331    let context = max_ngram - 1;
4332    let eos = eos_token_id as i64;
4333    let total_heads = (max_ngram - 1) * heads_per_ngram;
4334    let mut history = Vec::with_capacity(context + token_ids.len());
4335    history.extend(std::iter::repeat_n(eos, context));
4336    history.extend(token_ids.iter().map(|&token| token as i64));
4337    let shifted: Vec<Vec<i64>> = (0..max_ngram)
4338        .map(|shift| shift_right_ignore_eos(&history, shift, eos))
4339        .collect();
4340    let tokens = token_ids.len();
4341    let mut ids = vec![0i64; tokens * total_heads];
4342    for ngram in 2..=max_ngram {
4343        let head_start = (ngram - 2) * heads_per_ngram;
4344        for token in 0..tokens {
4345            let position = context + token;
4346            let mut mixed = shifted[0][position].wrapping_mul(multipliers[0]);
4347            for (shift, row) in shifted.iter().enumerate().take(ngram).skip(1) {
4348                mixed ^= row[position].wrapping_mul(multipliers[shift]);
4349            }
4350            for head in 0..heads_per_ngram {
4351                let index = head_start + head;
4352                ids[token * total_heads + index] = mixed.rem_euclid(sizes[index]) + offsets[index];
4353            }
4354        }
4355    }
4356    ids
4357}
4358
4359// ---------------------------------------------------------------- kernel launchers
4360
4361#[allow(clippy::too_many_arguments)]
4362fn launch_sdpa_mask(
4363    e: &Engine,
4364    q: &CudaSlice<f32>,
4365    k: &CudaView<'_, f32>,
4366    v: &CudaView<'_, f32>,
4367    o: &mut CudaSlice<f32>,
4368    mask: &CudaSlice<u8>,
4369    head_dim: usize,
4370    n_head: usize,
4371    n_head_kv: usize,
4372    t: usize,
4373    t_kv: usize,
4374    scale: f32,
4375) -> Res<()> {
4376    if t_kv * 4 > 48 * 1024 {
4377        return Err(
4378            "sdpa_naive_mask_f32: T_kv exceeds the smem bound; the gmem twin is perf-lane work"
4379                .into(),
4380        );
4381    }
4382    let f = e.func("sdpa_naive_mask_f32");
4383    let cfg = LaunchConfig {
4384        grid_dim: (n_head as u32, t as u32, 1),
4385        block_dim: (128, 1, 1),
4386        shared_mem_bytes: (t_kv * 4) as u32,
4387    };
4388    let (hd, nh, nkv, ti, tkvi) = (
4389        head_dim as i32,
4390        n_head as i32,
4391        n_head_kv as i32,
4392        t as i32,
4393        t_kv as i32,
4394    );
4395    let stream = e.gpu.stream();
4396    let mut b = stream.launch_builder(&f);
4397    b.arg(q)
4398        .arg(k)
4399        .arg(v)
4400        .arg(o)
4401        .arg(mask)
4402        .arg(&hd)
4403        .arg(&nh)
4404        .arg(&nkv)
4405        .arg(&ti)
4406        .arg(&tkvi)
4407        .arg(&scale);
4408    unsafe {
4409        b.launch(cfg)?;
4410    }
4411    Ok(())
4412}
4413
4414/// Block-list QSA attention (long-context form): per query row, attend the row's own
4415/// ASCENDING position list (`rowsel_positions`) — smem scales with the bounded per-row
4416/// selection (<= 2052 on real geometry), never with t_kv. BIT-IDENTICAL to
4417/// `sdpa_naive_mask_f32` on the same selection: masked entries there contribute exact
4418/// 0.0 softmax/V terms in the same ascending order (gate arm + kernel oracle).
4419#[allow(clippy::too_many_arguments)]
4420fn launch_sdpa_blocklist(
4421    e: &Engine,
4422    q: &CudaSlice<f32>,
4423    k: &CudaView<'_, f32>,
4424    v: &CudaView<'_, f32>,
4425    o: &mut CudaSlice<f32>,
4426    pos: &CudaSlice<i32>,
4427    meta: &CudaSlice<i32>,
4428    head_dim: usize,
4429    n_head: usize,
4430    n_head_kv: usize,
4431    t: usize,
4432    max_count: usize,
4433    scale: f32,
4434) -> Res<()> {
4435    // positions (i32) + scores (f32) per selected entry. Production rows are bounded by
4436    // budget*block + block = 2052 entries (16.4 KB); 48 KB is the no-attribute smem cap.
4437    let smem = (max_count * 8) as u32;
4438    if smem > 48 * 1024 {
4439        return Err("sdpa_blocklist_f32: selection exceeds the smem budget".into());
4440    }
4441    let f = e.func("sdpa_blocklist_f32");
4442    let cfg = LaunchConfig {
4443        grid_dim: (n_head as u32, t as u32, 1),
4444        block_dim: (128, 1, 1),
4445        shared_mem_bytes: smem,
4446    };
4447    let (hd, nh, nkv, ti, mc) = (
4448        head_dim as i32,
4449        n_head as i32,
4450        n_head_kv as i32,
4451        t as i32,
4452        max_count as i32,
4453    );
4454    let stream = e.gpu.stream();
4455    let mut b = stream.launch_builder(&f);
4456    b.arg(q)
4457        .arg(k)
4458        .arg(v)
4459        .arg(o)
4460        .arg(pos)
4461        .arg(meta)
4462        .arg(&hd)
4463        .arg(&nh)
4464        .arg(&nkv)
4465        .arg(&ti)
4466        .arg(&mc)
4467        .arg(&scale);
4468    unsafe {
4469        b.launch(cfg)?;
4470    }
4471    Ok(())
4472}
4473
4474/// Append-quantize `t` post-RoPE K/V rows into the byte caches at slots
4475/// [base_pos, base_pos + t) (kvq lane; K=q8_0, V=q5_1).
4476#[allow(clippy::too_many_arguments)]
4477fn launch_q4e_kv_append(
4478    e: &Engine,
4479    k_rows: &CudaSlice<f32>,
4480    v_rows: &CudaSlice<f32>,
4481    k: &mut CudaSlice<u8>,
4482    v: &mut CudaSlice<u8>,
4483    base_pos: usize,
4484    t: usize,
4485    kv_dim: usize,
4486) -> Res<()> {
4487    let f = e.func("q4e_kv_append_q8q5_rows");
4488    let blocks = kv_dim.div_ceil(32);
4489    let cfg = LaunchConfig {
4490        grid_dim: (blocks as u32, t as u32, 1),
4491        block_dim: (32, 1, 1),
4492        shared_mem_bytes: 0,
4493    };
4494    let (t0, dk, dv) = (base_pos as i32, kv_dim as i32, kv_dim as i32);
4495    let (ktb, vtb) = (q8_row_bytes(kv_dim) as i64, q5_row_bytes(kv_dim) as i64);
4496    let stream = e.gpu.stream();
4497    let mut b = stream.launch_builder(&f);
4498    b.arg(k_rows)
4499        .arg(v_rows)
4500        .arg(k)
4501        .arg(v)
4502        .arg(&t0)
4503        .arg(&dk)
4504        .arg(&dv)
4505        .arg(&ktb)
4506        .arg(&vtb);
4507    unsafe {
4508        b.launch(cfg)?;
4509    }
4510    Ok(())
4511}
4512
4513/// Dequant cache rows [r0, r0+rows) into f32 buffers (gates + TP2 migration seam).
4514#[allow(clippy::too_many_arguments)]
4515fn launch_q4e_kv_dequant_rows(
4516    e: &Engine,
4517    k: &CudaSlice<u8>,
4518    v: &CudaSlice<u8>,
4519    k_out: &mut CudaSlice<f32>,
4520    v_out: &mut CudaSlice<f32>,
4521    r0: usize,
4522    rows: usize,
4523    kv_dim: usize,
4524) -> Res<()> {
4525    let f = e.func("q4e_kv_dequant_rows");
4526    let blocks = kv_dim.div_ceil(32);
4527    let cfg = LaunchConfig {
4528        grid_dim: (blocks as u32, rows as u32, 1),
4529        block_dim: (32, 1, 1),
4530        shared_mem_bytes: 0,
4531    };
4532    let (r0i, dk, dv) = (r0 as i32, kv_dim as i32, kv_dim as i32);
4533    let (ktb, vtb) = (q8_row_bytes(kv_dim) as i64, q5_row_bytes(kv_dim) as i64);
4534    let stream = e.gpu.stream();
4535    let mut b = stream.launch_builder(&f);
4536    b.arg(k)
4537        .arg(v)
4538        .arg(k_out)
4539        .arg(v_out)
4540        .arg(&r0i)
4541        .arg(&dk)
4542        .arg(&dv)
4543        .arg(&ktb)
4544        .arg(&vtb);
4545    unsafe {
4546        b.launch(cfg)?;
4547    }
4548    Ok(())
4549}
4550
4551/// Block-list QSA attention over the QUANTIZED cache (kvq lane) — the f32 launcher's
4552/// twin with byte-cache K/V and their row strides.
4553#[allow(clippy::too_many_arguments)]
4554fn launch_q4e_sdpa_blocklist_q8q5(
4555    e: &Engine,
4556    q: &CudaSlice<f32>,
4557    k: &CudaSlice<u8>,
4558    v: &CudaSlice<u8>,
4559    o: &mut CudaSlice<f32>,
4560    pos: &CudaSlice<i32>,
4561    meta: &CudaSlice<i32>,
4562    head_dim: usize,
4563    n_head: usize,
4564    n_head_kv: usize,
4565    t: usize,
4566    max_count: usize,
4567    scale: f32,
4568) -> Res<()> {
4569    let smem = (max_count * 8) as u32;
4570    if smem > 48 * 1024 {
4571        return Err("q4e_sdpa_blocklist_q8q5: selection exceeds the smem budget".into());
4572    }
4573    // `kvhoist`: the scale-hoisted twin, bit-identical, selected by seam (see KV_HOIST_DEFAULT).
4574    let f = e.func(if kv_hoist_on() {
4575        "q4e_sdpa_blocklist_q8q5_hoist"
4576    } else {
4577        "q4e_sdpa_blocklist_q8q5"
4578    });
4579    let cfg = LaunchConfig {
4580        grid_dim: (n_head as u32, t as u32, 1),
4581        block_dim: (128, 1, 1),
4582        shared_mem_bytes: smem,
4583    };
4584    let kv_dim = n_head_kv * head_dim;
4585    let (hd, nh, nkv, ti, mc) = (
4586        head_dim as i32,
4587        n_head as i32,
4588        n_head_kv as i32,
4589        t as i32,
4590        max_count as i32,
4591    );
4592    let (ktb, vtb) = (q8_row_bytes(kv_dim) as i64, q5_row_bytes(kv_dim) as i64);
4593    let stream = e.gpu.stream();
4594    let mut b = stream.launch_builder(&f);
4595    b.arg(q)
4596        .arg(k)
4597        .arg(v)
4598        .arg(o)
4599        .arg(pos)
4600        .arg(meta)
4601        .arg(&hd)
4602        .arg(&nh)
4603        .arg(&nkv)
4604        .arg(&ti)
4605        .arg(&mc)
4606        .arg(&scale)
4607        .arg(&ktb)
4608        .arg(&vtb);
4609    unsafe {
4610        b.launch(cfg)?;
4611    }
4612    Ok(())
4613}
4614
4615/// Quantize-append the k-part columns of `rows` idx_proj rows into the q8_0 device
4616/// raw-key cache (idxq=q8 x idxcache).
4617#[allow(clippy::too_many_arguments)]
4618fn launch_q4e_idx_append_q8(
4619    e: &Engine,
4620    src: &CudaSlice<f32>,
4621    dst: &mut CudaSlice<u8>,
4622    rows: usize,
4623    width: usize,
4624    src_stride: usize,
4625    src_col: usize,
4626    dst_row: usize,
4627) -> Res<()> {
4628    let f = e.func("q4e_idx_append_q8");
4629    let cfg = LaunchConfig {
4630        grid_dim: (width.div_ceil(32) as u32, rows as u32, 1),
4631        block_dim: (32, 1, 1),
4632        shared_mem_bytes: 0,
4633    };
4634    let (r, w) = (rows as i32, width as i32);
4635    let (ss, sc, dr) = (src_stride as i64, src_col as i64, dst_row as i64);
4636    let stream = e.gpu.stream();
4637    let mut b = stream.launch_builder(&f);
4638    b.arg(src)
4639        .arg(dst)
4640        .arg(&r)
4641        .arg(&w)
4642        .arg(&ss)
4643        .arg(&sc)
4644        .arg(&dr);
4645    unsafe {
4646        b.launch(cfg)?;
4647    }
4648    Ok(())
4649}
4650
4651/// Convert-append (bf16 RNE) the k-part columns into the bf16 device raw-key cache.
4652#[allow(clippy::too_many_arguments)]
4653fn launch_q4e_idx_append_bf16(
4654    e: &Engine,
4655    src: &CudaSlice<f32>,
4656    dst: &mut CudaSlice<u16>,
4657    rows: usize,
4658    width: usize,
4659    src_stride: usize,
4660    src_col: usize,
4661    dst_row: usize,
4662) -> Res<()> {
4663    let f = e.func("q4e_idx_append_bf16");
4664    let total = rows * width;
4665    let cfg = LaunchConfig {
4666        grid_dim: (total.div_ceil(256) as u32, 1, 1),
4667        block_dim: (256, 1, 1),
4668        shared_mem_bytes: 0,
4669    };
4670    let (r, w) = (rows as i32, width as i32);
4671    let (ss, sc, dr) = (src_stride as i64, src_col as i64, dst_row as i64);
4672    let stream = e.gpu.stream();
4673    let mut b = stream.launch_builder(&f);
4674    b.arg(src)
4675        .arg(dst)
4676        .arg(&r)
4677        .arg(&w)
4678        .arg(&ss)
4679        .arg(&sc)
4680        .arg(&dr);
4681    unsafe {
4682        b.launch(cfg)?;
4683    }
4684    Ok(())
4685}
4686
4687#[allow(clippy::too_many_arguments)]
4688fn launch_gdn_scan(
4689    e: &Engine,
4690    qkv: &CudaSlice<f32>,
4691    g_log: &CudaSlice<f32>,
4692    beta_raw: &CudaSlice<f32>,
4693    state: &mut CudaSlice<f32>,
4694    o: &mut CudaSlice<f32>,
4695    nk: usize,
4696    nv: usize,
4697    hk: usize,
4698    hv: usize,
4699    t: usize,
4700    scale: f32,
4701    eps: f32,
4702) -> Res<()> {
4703    if hk > 128 {
4704        return Err("gdn_scan_naive_f32: hk > 128".into());
4705    }
4706    let f = e.func("gdn_scan_naive_f32");
4707    let cfg = LaunchConfig {
4708        grid_dim: (nv as u32, 1, 1),
4709        block_dim: (hv as u32, 1, 1),
4710        shared_mem_bytes: ((2 * hk + 2) * 4) as u32,
4711    };
4712    let (nki, nvi, hki, hvi, ti) = (nk as i32, nv as i32, hk as i32, hv as i32, t as i32);
4713    let stream = e.gpu.stream();
4714    let mut b = stream.launch_builder(&f);
4715    b.arg(qkv)
4716        .arg(g_log)
4717        .arg(beta_raw)
4718        .arg(state)
4719        .arg(o)
4720        .arg(&nki)
4721        .arg(&nvi)
4722        .arg(&hki)
4723        .arg(&hvi)
4724        .arg(&ti)
4725        .arg(&scale)
4726        .arg(&eps);
4727    unsafe {
4728        b.launch(cfg)?;
4729    }
4730    Ok(())
4731}
4732
4733/// One launch of the decode-step scan twin (`gdn_scan_step_f32`, t == 1): grid
4734/// (nv, hv), block hk — one state element per thread (see the kernel doc; the
4735/// accumulation class vs the naive kernel's sequential row sums).
4736#[allow(clippy::too_many_arguments)]
4737fn launch_gdn_scan_step(
4738    e: &Engine,
4739    qkv: &CudaSlice<f32>,
4740    g_log: &CudaSlice<f32>,
4741    beta_raw: &CudaSlice<f32>,
4742    state: &mut CudaSlice<f32>,
4743    o: &mut CudaSlice<f32>,
4744    nk: usize,
4745    nv: usize,
4746    hk: usize,
4747    hv: usize,
4748    scale: f32,
4749    eps: f32,
4750) -> Res<()> {
4751    if hk % 32 != 0 || hk > 1024 {
4752        return Err("gdn_scan_step_f32: hk must be a multiple of 32 and <= 1024".into());
4753    }
4754    let f = e.func("gdn_scan_step_f32");
4755    let cfg = LaunchConfig {
4756        grid_dim: (nv as u32, hv as u32, 1),
4757        block_dim: (hk as u32, 1, 1),
4758        shared_mem_bytes: 0,
4759    };
4760    let (nki, nvi, hki, hvi) = (nk as i32, nv as i32, hk as i32, hv as i32);
4761    let stream = e.gpu.stream();
4762    let mut b = stream.launch_builder(&f);
4763    b.arg(qkv)
4764        .arg(g_log)
4765        .arg(beta_raw)
4766        .arg(state)
4767        .arg(o)
4768        .arg(&nki)
4769        .arg(&nvi)
4770        .arg(&hki)
4771        .arg(&hvi)
4772        .arg(&scale)
4773        .arg(&eps);
4774    unsafe {
4775        b.launch(cfg)?;
4776    }
4777    Ok(())
4778}
4779
4780/// Per-token step-scan launch at COLUMN `tok` of a chunk (verify-exact rows): views of
4781/// the token's post-conv row / g_log / beta / output row, the SAME kernel and grid as
4782/// the decode step — each column is bit-identical to the t == 1 decode launch.
4783#[allow(clippy::too_many_arguments)]
4784fn launch_gdn_scan_step_at(
4785    e: &Engine,
4786    conv_out: &CudaSlice<f32>,
4787    g_log: &CudaSlice<f32>,
4788    beta_raw: &CudaSlice<f32>,
4789    state: &mut CudaSlice<f32>,
4790    o: &mut CudaSlice<f32>,
4791    tok: usize,
4792    nk: usize,
4793    nv: usize,
4794    hk: usize,
4795    hv: usize,
4796    scale: f32,
4797    eps: f32,
4798) -> Res<()> {
4799    if hk % 32 != 0 || hk > 1024 {
4800        return Err("gdn_scan_step_f32: hk must be a multiple of 32 and <= 1024".into());
4801    }
4802    let conv_dim = 2 * nk * hk + nv * hv;
4803    let qv = conv_out.slice(tok * conv_dim..(tok + 1) * conv_dim);
4804    let gv = g_log.slice(tok * nv..(tok + 1) * nv);
4805    let bv = beta_raw.slice(tok * nv..(tok + 1) * nv);
4806    let mut ov = o.slice_mut(tok * nv * hv..(tok + 1) * nv * hv);
4807    let f = e.func("gdn_scan_step_f32");
4808    let cfg = LaunchConfig {
4809        grid_dim: (nv as u32, hv as u32, 1),
4810        block_dim: (hk as u32, 1, 1),
4811        shared_mem_bytes: 0,
4812    };
4813    let (nki, nvi, hki, hvi) = (nk as i32, nv as i32, hk as i32, hv as i32);
4814    let stream = e.gpu.stream();
4815    let mut b = stream.launch_builder(&f);
4816    b.arg(&qv)
4817        .arg(&gv)
4818        .arg(&bv)
4819        .arg(&mut *state)
4820        .arg(&mut ov)
4821        .arg(&nki)
4822        .arg(&nvi)
4823        .arg(&hki)
4824        .arg(&hvi)
4825        .arg(&scale)
4826        .arg(&eps);
4827    unsafe {
4828        b.launch(cfg)?;
4829    }
4830    Ok(())
4831}
4832
4833/// Per-token NAIVE-scan launch at column `tok` (t == 1 views) — the exact-verify twin
4834/// for geometries the step kernel refuses (tiny hk): identical to the t == 1 decode
4835/// dispatch on those plans.
4836#[allow(clippy::too_many_arguments)]
4837fn launch_gdn_scan_at(
4838    e: &Engine,
4839    conv_out: &CudaSlice<f32>,
4840    g_log: &CudaSlice<f32>,
4841    beta_raw: &CudaSlice<f32>,
4842    state: &mut CudaSlice<f32>,
4843    o: &mut CudaSlice<f32>,
4844    tok: usize,
4845    nk: usize,
4846    nv: usize,
4847    hk: usize,
4848    hv: usize,
4849    scale: f32,
4850    eps: f32,
4851) -> Res<()> {
4852    if hk > 128 {
4853        return Err("gdn_scan_naive_f32: hk > 128".into());
4854    }
4855    let conv_dim = 2 * nk * hk + nv * hv;
4856    let qv = conv_out.slice(tok * conv_dim..(tok + 1) * conv_dim);
4857    let gv = g_log.slice(tok * nv..(tok + 1) * nv);
4858    let bv = beta_raw.slice(tok * nv..(tok + 1) * nv);
4859    let mut ov = o.slice_mut(tok * nv * hv..(tok + 1) * nv * hv);
4860    let f = e.func("gdn_scan_naive_f32");
4861    let cfg = LaunchConfig {
4862        grid_dim: (nv as u32, 1, 1),
4863        block_dim: (hv as u32, 1, 1),
4864        shared_mem_bytes: ((2 * hk + 2) * 4) as u32,
4865    };
4866    let (nki, nvi, hki, hvi, ti) = (nk as i32, nv as i32, hk as i32, hv as i32, 1i32);
4867    let stream = e.gpu.stream();
4868    let mut b = stream.launch_builder(&f);
4869    b.arg(&qv)
4870        .arg(&gv)
4871        .arg(&bv)
4872        .arg(&mut *state)
4873        .arg(&mut ov)
4874        .arg(&nki)
4875        .arg(&nvi)
4876        .arg(&hki)
4877        .arg(&hvi)
4878        .arg(&ti)
4879        .arg(&scale)
4880        .arg(&eps);
4881    unsafe {
4882        b.launch(cfg)?;
4883    }
4884    Ok(())
4885}
4886
4887/// One launch of the fused GDN norm+gate (`rms_sigmul_f32`): dst = rms_norm(x, w) *
4888/// sigmoid(z) over `nrows` rows of `ncols` — bit-identical to the rms_norm + sigmoid +
4889/// mul chain (kernel doc).
4890#[allow(clippy::too_many_arguments)]
4891fn launch_rms_sigmul(
4892    e: &Engine,
4893    x: &CudaSlice<f32>,
4894    w: &CudaSlice<f32>,
4895    z: &CudaSlice<f32>,
4896    dst: &mut CudaSlice<f32>,
4897    ncols: usize,
4898    nrows: usize,
4899    eps: f32,
4900) -> Res<()> {
4901    let f = e.func("rms_sigmul_f32");
4902    let cfg = LaunchConfig {
4903        grid_dim: (nrows as u32, 1, 1),
4904        block_dim: (crate::rms_block(), 1, 1),
4905        shared_mem_bytes: 0,
4906    };
4907    let (nc, ep) = (ncols as i32, eps);
4908    let stream = e.gpu.stream();
4909    let mut b = stream.launch_builder(&f);
4910    b.arg(x).arg(w).arg(z).arg(dst).arg(&nc).arg(&ep);
4911    unsafe {
4912        b.launch(cfg)?;
4913    }
4914    Ok(())
4915}
4916
4917#[allow(clippy::too_many_arguments)]
4918fn launch_dwconv(
4919    e: &Engine,
4920    x: &CudaSlice<f32>,
4921    hist: &CudaSlice<f32>,
4922    w: &CudaSlice<f32>,
4923    y: &mut CudaSlice<f32>,
4924    t: usize,
4925    th: usize,
4926    c: usize,
4927    k: usize,
4928    dilation: usize,
4929    mode: i32,
4930) -> Res<()> {
4931    let f = e.func("dwconv_causal_f32");
4932    let cfg = LaunchConfig::for_num_elems((t * c) as u32);
4933    let (ti, thi, ci, ki, di) = (t as i32, th as i32, c as i32, k as i32, dilation as i32);
4934    let stream = e.gpu.stream();
4935    let mut b = stream.launch_builder(&f);
4936    b.arg(x)
4937        .arg(hist)
4938        .arg(w)
4939        .arg(y)
4940        .arg(&ti)
4941        .arg(&thi)
4942        .arg(&ci)
4943        .arg(&ki)
4944        .arg(&di)
4945        .arg(&mode);
4946    unsafe {
4947        b.launch(cfg)?;
4948    }
4949    Ok(())
4950}
4951
4952/// One routed expert's SwiGLU: gate/up GEMMs on the gathered token rows, silu_mul, down.
4953#[allow(clippy::too_many_arguments)]
4954fn run_routed_expert(
4955    e: &Engine,
4956    xg: &CudaSlice<f32>,
4957    gate: &CudaView<'_, f32>,
4958    up: &CudaView<'_, f32>,
4959    down: &CudaView<'_, f32>,
4960    m_e: usize,
4961    hidden: usize,
4962    ff: usize,
4963) -> Res<CudaSlice<f32>> {
4964    let xg_view = xg.slice(0..m_e * hidden);
4965    let mut gate_out = e.uninit(m_e * ff)?;
4966    e.linear_device_into(&xg_view, gate, &mut gate_out, m_e, hidden, ff)?;
4967    let mut up_out = e.uninit(m_e * ff)?;
4968    e.linear_device_into(&xg_view, up, &mut up_out, m_e, hidden, ff)?;
4969    let mut act = e.uninit(m_e * ff)?;
4970    e.silu_mul(&gate_out, &up_out, &mut act, m_e * ff)?;
4971    let mut down_out = e.uninit(m_e * hidden)?;
4972    e.linear_device_into(
4973        &act.slice(0..m_e * ff),
4974        down,
4975        &mut down_out,
4976        m_e,
4977        ff,
4978        hidden,
4979    )?;
4980    Ok(down_out)
4981}
4982
4983/// View-destination twin of `Engine::rms_norm` — same kernel, same block size, same args,
4984/// so BIT-IDENTICAL; it exists only so the gate can normalize into one contiguous
4985/// stream-major buffer instead of `streams` separate allocations (the fused gate kernels
4986/// need every stream in one launch). PDL is skipped: dependent launch changes scheduling,
4987/// not arithmetic.
4988fn launch_rms_norm_into_view(
4989    e: &Engine,
4990    x: &CudaSlice<f32>,
4991    w: &CudaSlice<f32>,
4992    dst: &mut cudarc::driver::CudaViewMut<'_, f32>,
4993    ncols: usize,
4994    nrows: usize,
4995    eps: f32,
4996) -> Res<()> {
4997    let kname = if Engine::norm_ilp_on() {
4998        "rms_norm_f32_v2"
4999    } else {
5000        "rms_norm_f32"
5001    };
5002    let f = e.func(kname);
5003    let cfg = LaunchConfig {
5004        grid_dim: (nrows as u32, 1, 1),
5005        block_dim: (crate::rms_block(), 1, 1),
5006        shared_mem_bytes: 0,
5007    };
5008    let (nc, ep) = (ncols as i32, eps);
5009    let stream = e.gpu.stream();
5010    let mut b = stream.launch_builder(&f);
5011    b.arg(x).arg(w).arg(dst).arg(&nc).arg(&ep);
5012    unsafe {
5013        b.launch(cfg)?;
5014    }
5015    Ok(())
5016}
5017
5018/// `hc_lowrank_reduce_f32`: low_act[t, rank] = silu(inv_streams · Σ_s parts[s, t, rank]).
5019fn launch_hc_lowrank_reduce(
5020    e: &Engine,
5021    parts: &CudaSlice<f32>,
5022    low_act: &mut CudaSlice<f32>,
5023    streams: usize,
5024    t: usize,
5025    rank: usize,
5026) -> Res<()> {
5027    let f = e.func("hc_lowrank_reduce_f32");
5028    let cfg = LaunchConfig::for_num_elems((t * rank) as u32);
5029    let (si, ti, ri) = (streams as i32, t as i32, rank as i32);
5030    let inv = 1.0f32 / streams as f32;
5031    let stream = e.gpu.stream();
5032    let mut b = stream.launch_builder(&f);
5033    b.arg(parts)
5034        .arg(low_act)
5035        .arg(&si)
5036        .arg(&ti)
5037        .arg(&ri)
5038        .arg(&inv);
5039    unsafe {
5040        b.launch(cfg)?;
5041    }
5042    Ok(())
5043}
5044
5045/// `hc_mix_epilogue_f32`: mixed = inv_streams · Σ_s sigmoid(gates_s) ⊙ normed_s.
5046fn launch_hc_mix_epilogue(
5047    e: &Engine,
5048    gates: &CudaSlice<f32>,
5049    normed: &CudaSlice<f32>,
5050    mixed: &mut CudaSlice<f32>,
5051    streams: usize,
5052    t: usize,
5053    hidden: usize,
5054) -> Res<()> {
5055    let f = e.func("hc_mix_epilogue_f32");
5056    let cfg = LaunchConfig::for_num_elems((t * hidden) as u32);
5057    let (si, ti, hi) = (streams as i32, t as i32, hidden as i32);
5058    let inv = 1.0f32 / streams as f32;
5059    let stream = e.gpu.stream();
5060    let mut b = stream.launch_builder(&f);
5061    b.arg(gates)
5062        .arg(normed)
5063        .arg(mixed)
5064        .arg(&si)
5065        .arg(&ti)
5066        .arg(&hi)
5067        .arg(&inv);
5068    unsafe {
5069        b.launch(cfg)?;
5070    }
5071    Ok(())
5072}
5073
5074/// `hc_inject_gates_f32`: out[s, t] = 2·sigmoid(inv_streams · ⟨w_s, wide_normed_t⟩).
5075fn launch_hc_inject_gates(
5076    e: &Engine,
5077    normed: &CudaSlice<f32>,
5078    w: &CudaSlice<f32>,
5079    out: &mut CudaSlice<f32>,
5080    streams: usize,
5081    t: usize,
5082    hidden: usize,
5083) -> Res<()> {
5084    let f = e.func("hc_inject_gates_f32");
5085    let cfg = LaunchConfig {
5086        grid_dim: (streams as u32, t as u32, 1),
5087        block_dim: (256, 1, 1),
5088        shared_mem_bytes: 0,
5089    };
5090    let (si, ti, hi) = (streams as i32, t as i32, hidden as i32);
5091    let inv = 1.0f32 / streams as f32;
5092    let stream = e.gpu.stream();
5093    let mut b = stream.launch_builder(&f);
5094    b.arg(normed)
5095        .arg(w)
5096        .arg(out)
5097        .arg(&si)
5098        .arg(&ti)
5099        .arg(&hi)
5100        .arg(&inv);
5101    unsafe {
5102        b.launch(cfg)?;
5103    }
5104    Ok(())
5105}
5106
5107/// Inject scalars as either per-stream rows (the item-1-era plumbing, hcmicro OFF and
5108/// the legacy gate) or the [streams, t] slab straight out of the two-stage inject
5109/// (hcmicro ON — no per-stream d2d copies; `gate_write` consumes it in one launch).
5110enum InjectOut {
5111    Rows(Vec<CudaSlice<f32>>),
5112    Slab(CudaSlice<f32>),
5113}
5114
5115/// Park an inject result back into its slots (the form is flag-determined, so takes and
5116/// puts pair up step over step).
5117fn put_inject(ws: &mut StepPool, inject: InjectOut) {
5118    match inject {
5119        InjectOut::Rows(rows) => {
5120            for (s, row) in rows.into_iter().enumerate() {
5121                ws.put_f32(INJECT_SLOTS[s], row);
5122            }
5123        }
5124        InjectOut::Slab(slab) => ws.put_f32("hc.inj_all", slab),
5125    }
5126}
5127
5128/// Take the parked inject scalars in the form the current seams produce (graph driver's
5129/// MoE tail — the mlp read gate parked them in the interior segment).
5130fn take_inject(e: &Engine, ws: &mut StepPool, streams: usize, t: usize) -> Res<InjectOut> {
5131    // The diet emits the Slab form and requires micro_inj at dispatch, so this predicate
5132    // stays in lockstep with what gate_read parked.
5133    if micro_inj_on() && hc_fused_gate_on() {
5134        Ok(InjectOut::Slab(ws.take_f32(
5135            e,
5136            "hc.inj_all",
5137            streams * t,
5138            0,
5139        )?))
5140    } else {
5141        let mut rows = Vec::with_capacity(streams);
5142        for s in 0..streams {
5143            rows.push(ws.take_f32(e, INJECT_SLOTS[s], t, 0)?);
5144        }
5145        Ok(InjectOut::Rows(rows))
5146    }
5147}
5148
5149/// `hc_norm_planes_f32`: per-(stream, token) RMSNorm over the plane pointer table into
5150/// the stream-major normed slab — one launch for all streams (hcmicro seam).
5151#[allow(clippy::too_many_arguments)]
5152fn launch_hc_norm_planes(
5153    e: &Engine,
5154    ptrs: &CudaSlice<u64>,
5155    w_stack: &CudaSlice<f32>,
5156    dst: &mut CudaSlice<f32>,
5157    hidden: usize,
5158    t: usize,
5159    streams: usize,
5160    eps: f32,
5161) -> Res<()> {
5162    let f = e.func("hc_norm_planes_f32");
5163    let cfg = LaunchConfig {
5164        grid_dim: (t as u32, streams as u32, 1),
5165        block_dim: (256, 1, 1),
5166        shared_mem_bytes: 0,
5167    };
5168    let (hi, ti) = (hidden as i32, t as i32);
5169    let stream = e.gpu.stream();
5170    let mut b = stream.launch_builder(&f);
5171    b.arg(ptrs)
5172        .arg(w_stack)
5173        .arg(dst)
5174        .arg(&hi)
5175        .arg(&ti)
5176        .arg(&eps);
5177    unsafe {
5178        b.launch(cfg)?;
5179    }
5180    Ok(())
5181}
5182
5183/// Two-stage inject (hcmicro seam): chunked partial dots (fills the card; the
5184/// single-stage kernel ran `streams` blocks) then a sequential-order reduce + sigmoid.
5185/// Deterministic — no atomics (greedy replays must stay byte-stable).
5186#[allow(clippy::too_many_arguments)]
5187fn launch_hc_inject_two_stage(
5188    e: &Engine,
5189    normed: &CudaSlice<f32>,
5190    w_f32: &CudaSlice<f32>,
5191    w_b16: Option<&CudaSlice<u8>>,
5192    partials: &mut CudaSlice<f32>,
5193    out: &mut CudaSlice<f32>,
5194    streams: usize,
5195    t: usize,
5196    hidden: usize,
5197    chunks: usize,
5198) -> Res<()> {
5199    let cfg = LaunchConfig {
5200        grid_dim: (streams as u32, t as u32, chunks as u32),
5201        block_dim: (256, 1, 1),
5202        shared_mem_bytes: 0,
5203    };
5204    let (si, ti, hi, ci) = (streams as i32, t as i32, hidden as i32, chunks as i32);
5205    let stream = e.gpu.stream();
5206    if let Some(w) = w_b16 {
5207        let f = e.func("hc_inject_partials_bf16w_f32");
5208        let mut b = stream.launch_builder(&f);
5209        b.arg(normed)
5210            .arg(w)
5211            .arg(&mut *partials)
5212            .arg(&si)
5213            .arg(&ti)
5214            .arg(&hi)
5215            .arg(&ci);
5216        unsafe {
5217            b.launch(cfg)?;
5218        }
5219    } else {
5220        let f = e.func("hc_inject_partials_f32");
5221        let mut b = stream.launch_builder(&f);
5222        b.arg(normed)
5223            .arg(w_f32)
5224            .arg(&mut *partials)
5225            .arg(&si)
5226            .arg(&ti)
5227            .arg(&hi)
5228            .arg(&ci);
5229        unsafe {
5230            b.launch(cfg)?;
5231        }
5232    }
5233    let rows = (streams * t) as i32;
5234    let inv = 1.0f32 / streams as f32;
5235    let f = e.func("hc_inject_reduce_f32");
5236    let cfg = LaunchConfig::for_num_elems((streams * t) as u32);
5237    let mut b = stream.launch_builder(&f);
5238    b.arg(&*partials).arg(out).arg(&rows).arg(&ci).arg(&inv);
5239    unsafe {
5240        b.launch(cfg)?;
5241    }
5242    Ok(())
5243}
5244
5245/// hc-diet stage 1 (`hc_diet_stage1_f32`): per (row-chunk, stream) block — RMS recompute
5246/// from the raw plane, normed row in smem, this chunk's down rows + inject partial rows.
5247/// Emits parts [S, rank], inj_parts [n_inj, S], inv [S].
5248#[allow(clippy::too_many_arguments)]
5249fn launch_hc_diet_stage1(
5250    e: &Engine,
5251    ptrs: &CudaSlice<u64>,
5252    nw_stack: &CudaSlice<f32>,
5253    wdown_b16: &CudaSlice<u8>,
5254    winj_b16: Option<&CudaSlice<u8>>,
5255    parts: &mut CudaSlice<f32>,
5256    inj_parts: &mut CudaSlice<f32>,
5257    inv_out: &mut CudaSlice<f32>,
5258    hidden: usize,
5259    rank: usize,
5260    streams: usize,
5261    t: usize,
5262    eps: f32,
5263) -> Res<()> {
5264    if hidden % 8 != 0 {
5265        return Err("hc_diet_stage1_f32: hidden % 8 != 0".into());
5266    }
5267    let n_inj = if winj_b16.is_some() { streams } else { 0 };
5268    const ROWS_PB: usize = 4;
5269    let total_rows = rank + n_inj;
5270    if parts.len() < t * streams * rank
5271        || (n_inj > 0 && inj_parts.len() < t * n_inj * streams)
5272        || inv_out.len() < t * streams
5273    {
5274        return Err("hc_diet_stage1_f32: output buffers too short".into());
5275    }
5276    let f = e.func("hc_diet_stage1_f32");
5277    let cfg = LaunchConfig {
5278        grid_dim: (
5279            total_rows.div_ceil(ROWS_PB) as u32,
5280            t as u32,
5281            streams as u32,
5282        ),
5283        block_dim: (256, 1, 1),
5284        shared_mem_bytes: (hidden * 4) as u32,
5285    };
5286    let (hi, ri, si, nji, rpb) = (
5287        hidden as i32,
5288        rank as i32,
5289        streams as i32,
5290        n_inj as i32,
5291        ROWS_PB as i32,
5292    );
5293    let winj = winj_b16.unwrap_or(wdown_b16); // unread when n_inj == 0
5294    let stream = e.gpu.stream();
5295    let mut b = stream.launch_builder(&f);
5296    b.arg(ptrs)
5297        .arg(nw_stack)
5298        .arg(wdown_b16)
5299        .arg(winj)
5300        .arg(&mut *parts)
5301        .arg(&mut *inj_parts)
5302        .arg(&mut *inv_out)
5303        .arg(&hi)
5304        .arg(&ri)
5305        .arg(&si)
5306        .arg(&nji)
5307        .arg(&rpb)
5308        .arg(&eps);
5309    unsafe {
5310        b.launch(cfg)?;
5311    }
5312    Ok(())
5313}
5314
5315/// hc-diet stage 2 (`hc_diet_stage2_f32`): low_act = silu(mean_s parts) (the
5316/// hc_lowrank_reduce association verbatim) + inj = 2*sigmoid(mean_s2 inj_parts).
5317#[allow(clippy::too_many_arguments)]
5318fn launch_hc_diet_stage2(
5319    e: &Engine,
5320    parts: &CudaSlice<f32>,
5321    inj_parts: &CudaSlice<f32>,
5322    low_act: &mut CudaSlice<f32>,
5323    inj_all: &mut CudaSlice<f32>,
5324    rank: usize,
5325    streams: usize,
5326    t: usize,
5327    with_inject: bool,
5328) -> Res<()> {
5329    let n_inj = if with_inject { streams } else { 0 };
5330    if low_act.len() < t * rank || (n_inj > 0 && inj_all.len() < n_inj * t) {
5331        return Err("hc_diet_stage2_f32: output buffers too short".into());
5332    }
5333    let f = e.func("hc_diet_stage2_f32");
5334    let cfg = LaunchConfig {
5335        grid_dim: (((rank + n_inj) as u32).div_ceil(256), t as u32, 1),
5336        block_dim: (256, 1, 1),
5337        shared_mem_bytes: 0,
5338    };
5339    let (ri, si, nji, ti) = (rank as i32, streams as i32, n_inj as i32, t as i32);
5340    let inv = 1.0f32 / streams as f32;
5341    let stream = e.gpu.stream();
5342    let mut b = stream.launch_builder(&f);
5343    b.arg(parts)
5344        .arg(inj_parts)
5345        .arg(&mut *low_act)
5346        .arg(&mut *inj_all)
5347        .arg(&ri)
5348        .arg(&si)
5349        .arg(&nji)
5350        .arg(&ti)
5351        .arg(&inv);
5352    unsafe {
5353        b.launch(cfg)?;
5354    }
5355    Ok(())
5356}
5357
5358/// hc-diet stage 3 (`hc_diet_stage3_f32`): per dim-chunk block — the up dots for all
5359/// streams from a smem low_act copy, then the mix epilogue from the stage-1 inv scalars.
5360#[allow(clippy::too_many_arguments)]
5361fn launch_hc_diet_stage3(
5362    e: &Engine,
5363    ptrs: &CudaSlice<u64>,
5364    nw_stack: &CudaSlice<f32>,
5365    inv_in: &CudaSlice<f32>,
5366    wup_b16: &CudaSlice<u8>,
5367    low_act: &CudaSlice<f32>,
5368    mixed: &mut CudaSlice<f32>,
5369    hidden: usize,
5370    rank: usize,
5371    streams: usize,
5372    t: usize,
5373) -> Res<()> {
5374    const DIMS_PB: usize = 8;
5375    if mixed.len() < t * hidden {
5376        return Err("hc_diet_stage3_f32: output buffer too short".into());
5377    }
5378    let f = e.func("hc_diet_stage3_f32");
5379    let cfg = LaunchConfig {
5380        grid_dim: (hidden.div_ceil(DIMS_PB) as u32, t as u32, 1),
5381        block_dim: (256, 1, 1),
5382        shared_mem_bytes: ((rank + DIMS_PB * streams) * 4) as u32,
5383    };
5384    let (hi, ri, si, dpb) = (hidden as i32, rank as i32, streams as i32, DIMS_PB as i32);
5385    let inv_streams = 1.0f32 / streams as f32;
5386    let stream = e.gpu.stream();
5387    let mut b = stream.launch_builder(&f);
5388    b.arg(ptrs)
5389        .arg(nw_stack)
5390        .arg(inv_in)
5391        .arg(wup_b16)
5392        .arg(low_act)
5393        .arg(&mut *mixed)
5394        .arg(&hi)
5395        .arg(&ri)
5396        .arg(&si)
5397        .arg(&dpb)
5398        .arg(&inv_streams);
5399    unsafe {
5400        b.launch(cfg)?;
5401    }
5402    Ok(())
5403}
5404
5405/// hc-diet MT stage 0 (`hc_diet_stage0_mt_f32`): the stage-1 RMS reduce EXACTLY, per
5406/// (token, stream) — bit-equal inv scalars for the weight-shared stages.
5407fn launch_hc_diet_stage0_mt(
5408    e: &Engine,
5409    ptrs: &CudaSlice<u64>,
5410    inv_out: &mut CudaSlice<f32>,
5411    hidden: usize,
5412    streams: usize,
5413    t: usize,
5414    eps: f32,
5415) -> Res<()> {
5416    if inv_out.len() < t * streams {
5417        return Err("hc_diet_stage0_mt_f32: inv buffer too short".into());
5418    }
5419    let f = e.func("hc_diet_stage0_mt_f32");
5420    let cfg = LaunchConfig {
5421        grid_dim: (t as u32, streams as u32, 1),
5422        block_dim: (256, 1, 1),
5423        shared_mem_bytes: 0,
5424    };
5425    let (hi, si, ti) = (hidden as i32, streams as i32, t as i32);
5426    let stream = e.gpu.stream();
5427    let mut b = stream.launch_builder(&f);
5428    b.arg(ptrs)
5429        .arg(&mut *inv_out)
5430        .arg(&hi)
5431        .arg(&si)
5432        .arg(&ti)
5433        .arg(&eps);
5434    unsafe {
5435        b.launch(cfg)?;
5436    }
5437    Ok(())
5438}
5439
5440/// hc-diet MT stage 1: weight rows read ONCE, tokens iterated inside with inline
5441/// normalization — per-(row, token) chains VERBATIM vs the token-grid stage 1.
5442#[allow(clippy::too_many_arguments)]
5443fn launch_hc_diet_stage1_mt(
5444    e: &Engine,
5445    ptrs: &CudaSlice<u64>,
5446    nw_stack: &CudaSlice<f32>,
5447    inv_in: &CudaSlice<f32>,
5448    wdown_b16: &CudaSlice<u8>,
5449    winj_b16: Option<&CudaSlice<u8>>,
5450    parts: &mut CudaSlice<f32>,
5451    inj_parts: &mut CudaSlice<f32>,
5452    hidden: usize,
5453    rank: usize,
5454    streams: usize,
5455    t: usize,
5456) -> Res<()> {
5457    if hidden % 8 != 0 || !(2..=12).contains(&t) {
5458        return Err("hc_diet_stage1_mt_f32: geometry".into());
5459    }
5460    let n_inj = if winj_b16.is_some() { streams } else { 0 };
5461    const ROWS_PB: usize = 4;
5462    let total_rows = rank + n_inj;
5463    if parts.len() < t * streams * rank || (n_inj > 0 && inj_parts.len() < t * n_inj * streams) {
5464        return Err("hc_diet_stage1_mt_f32: output buffers too short".into());
5465    }
5466    let f = e.func("hc_diet_stage1_mt_f32");
5467    let cfg = LaunchConfig {
5468        grid_dim: (total_rows.div_ceil(ROWS_PB) as u32, 1, streams as u32),
5469        block_dim: (256, 1, 1),
5470        shared_mem_bytes: 0,
5471    };
5472    let (hi, ri, si, nji, rpb, ti) = (
5473        hidden as i32,
5474        rank as i32,
5475        streams as i32,
5476        n_inj as i32,
5477        ROWS_PB as i32,
5478        t as i32,
5479    );
5480    let winj = winj_b16.unwrap_or(wdown_b16);
5481    let stream = e.gpu.stream();
5482    let mut b = stream.launch_builder(&f);
5483    b.arg(ptrs)
5484        .arg(nw_stack)
5485        .arg(inv_in)
5486        .arg(wdown_b16)
5487        .arg(winj)
5488        .arg(&mut *parts)
5489        .arg(&mut *inj_parts)
5490        .arg(&hi)
5491        .arg(&ri)
5492        .arg(&si)
5493        .arg(&nji)
5494        .arg(&rpb)
5495        .arg(&ti);
5496    unsafe {
5497        b.launch(cfg)?;
5498    }
5499    Ok(())
5500}
5501
5502/// hc-diet MT stage 3: up rows read once, all T low_act rows resident in smem.
5503#[allow(clippy::too_many_arguments)]
5504fn launch_hc_diet_stage3_mt(
5505    e: &Engine,
5506    ptrs: &CudaSlice<u64>,
5507    nw_stack: &CudaSlice<f32>,
5508    inv_in: &CudaSlice<f32>,
5509    wup_b16: &CudaSlice<u8>,
5510    low_act: &CudaSlice<f32>,
5511    mixed: &mut CudaSlice<f32>,
5512    hidden: usize,
5513    rank: usize,
5514    streams: usize,
5515    t: usize,
5516) -> Res<()> {
5517    const DIMS_PB: usize = 8;
5518    if !(2..=12).contains(&t) || mixed.len() < t * hidden {
5519        return Err("hc_diet_stage3_mt_f32: geometry".into());
5520    }
5521    let smem = ((t * rank + DIMS_PB * streams * t) * 4) as u32;
5522    if smem > 96 * 1024 {
5523        return Err("hc_diet_stage3_mt_f32: smem over budget".into());
5524    }
5525    let f = e.func("hc_diet_stage3_mt_f32");
5526    let cfg = LaunchConfig {
5527        grid_dim: (hidden.div_ceil(DIMS_PB) as u32, 1, 1),
5528        block_dim: (256, 1, 1),
5529        shared_mem_bytes: smem,
5530    };
5531    let (hi, ri, si, dpb, ti) = (
5532        hidden as i32,
5533        rank as i32,
5534        streams as i32,
5535        DIMS_PB as i32,
5536        t as i32,
5537    );
5538    let inv_streams = 1.0f32 / streams as f32;
5539    let stream = e.gpu.stream();
5540    let mut b = stream.launch_builder(&f);
5541    b.arg(ptrs)
5542        .arg(nw_stack)
5543        .arg(inv_in)
5544        .arg(wup_b16)
5545        .arg(low_act)
5546        .arg(&mut *mixed)
5547        .arg(&hi)
5548        .arg(&ri)
5549        .arg(&si)
5550        .arg(&dpb)
5551        .arg(&ti)
5552        .arg(&inv_streams);
5553    unsafe {
5554        b.launch(cfg)?;
5555    }
5556    Ok(())
5557}
5558
5559/// `hc_write_planes_f32`: plane_s += block_out ⊗ inj[s] for every stream in one launch
5560/// over the plane pointer table (hcmicro seam).
5561fn launch_hc_write_planes(
5562    e: &Engine,
5563    ptrs: &CudaSlice<u64>,
5564    block_out: &CudaSlice<f32>,
5565    inj: &CudaSlice<f32>,
5566    hidden: usize,
5567    t: usize,
5568    streams: usize,
5569) -> Res<()> {
5570    let f = e.func("hc_write_planes_f32");
5571    let n = (t * hidden) as u32;
5572    let cfg = LaunchConfig {
5573        grid_dim: (n.div_ceil(256), streams as u32, 1),
5574        block_dim: (256, 1, 1),
5575        shared_mem_bytes: 0,
5576    };
5577    let (hi, ti) = (hidden as i32, t as i32);
5578    let stream = e.gpu.stream();
5579    let mut b = stream.launch_builder(&f);
5580    b.arg(ptrs).arg(block_out).arg(inj).arg(&hi).arg(&ti);
5581    unsafe {
5582        b.launch(cfg)?;
5583    }
5584    Ok(())
5585}
5586
5587/// `hc_inject_gates_bf16w_f32`: the bf16-weight twin of `launch_hc_inject_gates` — same
5588/// grid, same loop order, same reduction tree, exact bf16→f32 widening, so BIT-IDENTICAL
5589/// to the f32 arm when the resident bytes match (the `bf16_twin` representability guard).
5590fn launch_hc_inject_gates_b16(
5591    e: &Engine,
5592    normed: &CudaSlice<f32>,
5593    w: &CudaSlice<u8>,
5594    out: &mut CudaSlice<f32>,
5595    streams: usize,
5596    t: usize,
5597    hidden: usize,
5598) -> Res<()> {
5599    let f = e.func("hc_inject_gates_bf16w_f32");
5600    let cfg = LaunchConfig {
5601        grid_dim: (streams as u32, t as u32, 1),
5602        block_dim: (256, 1, 1),
5603        shared_mem_bytes: 0,
5604    };
5605    let (si, ti, hi) = (streams as i32, t as i32, hidden as i32);
5606    let inv = 1.0f32 / streams as f32;
5607    let stream = e.gpu.stream();
5608    let mut b = stream.launch_builder(&f);
5609    b.arg(normed)
5610        .arg(w)
5611        .arg(out)
5612        .arg(&si)
5613        .arg(&ti)
5614        .arg(&hi)
5615        .arg(&inv);
5616    unsafe {
5617        b.launch(cfg)?;
5618    }
5619    Ok(())
5620}
5621
5622/// bf16 trunk-residency twin builder (load time). Returns the packed bf16 device bytes
5623/// iff BOTH guards pass: in_f % 8 == 0 (the kernel's uint4 vector width — geometry, not
5624/// policy) and every value is exactly bf16-representable (low 16 mantissa bits zero —
5625/// true whenever the checkpoint row was BF16, since dequant is an exact widening; the
5626/// f32 tiny fixture fails this and keeps its f32-only residency).
5627fn bf16_twin(e: &Engine, data: &[f32], in_f: usize) -> Res<Option<CudaSlice<u8>>> {
5628    if in_f % 8 != 0 {
5629        return Ok(None);
5630    }
5631    let mut bytes = Vec::with_capacity(data.len() * 2);
5632    for &v in data {
5633        let bits = v.to_bits();
5634        if bits & 0xFFFF != 0 {
5635            return Ok(None);
5636        }
5637        bytes.extend_from_slice(&((bits >> 16) as u16).to_le_bytes());
5638    }
5639    Ok(Some(e.htod_bytes(&bytes)?))
5640}
5641
5642/// One launch of `qmatvec_bf16w_f32`: y[b, tok, :out_f] = W_b(bf16) @ x_{b,tok}, f32
5643/// accumulate. Strides in ELEMENTS; `x_bstride == 0` shares one activation across the
5644/// batch (the read gate's up projection). Products are exact (bf16→f32 widening); only
5645/// the reduction tree differs from cuBLASLt — the accumulation class.
5646#[allow(clippy::too_many_arguments)]
5647fn launch_qmatvec_bf16w(
5648    e: &Engine,
5649    w: &CudaSlice<u8>,
5650    x: &CudaSlice<f32>,
5651    y: &mut CudaSlice<f32>,
5652    in_f: usize,
5653    out_f: usize,
5654    t: usize,
5655    batch: usize,
5656    w_bstride: usize,
5657    x_bstride: usize,
5658    x_tstride: usize,
5659    y_bstride: usize,
5660) -> Res<()> {
5661    if in_f % 8 != 0 || x_bstride % 8 != 0 || x_tstride % 8 != 0 {
5662        return Err("qmatvec_bf16w_f32: stride breaks the uint4/float4 vector width".into());
5663    }
5664    if y.len() < (batch - 1) * y_bstride + t * out_f {
5665        return Err("qmatvec_bf16w_f32: output buffer too short".into());
5666    }
5667    let f = e.func("qmatvec_bf16w_f32");
5668    let cfg = LaunchConfig {
5669        grid_dim: (out_f as u32, t as u32, batch as u32),
5670        block_dim: (128, 1, 1),
5671        shared_mem_bytes: 0,
5672    };
5673    let (inf, outf, ti) = (in_f as i32, out_f as i32, t as i32);
5674    let (wb, xb, xt, yb) = (
5675        w_bstride as i64,
5676        x_bstride as i64,
5677        x_tstride as i64,
5678        y_bstride as i64,
5679    );
5680    let stream = e.gpu.stream();
5681    let mut b = stream.launch_builder(&f);
5682    b.arg(w)
5683        .arg(x)
5684        .arg(y)
5685        .arg(&inf)
5686        .arg(&outf)
5687        .arg(&ti)
5688        .arg(&wb)
5689        .arg(&xb)
5690        .arg(&xt)
5691        .arg(&yb);
5692    unsafe {
5693        b.launch(cfg)?;
5694    }
5695    Ok(())
5696}
5697
5698/// Stacked bf16 twin over several same-in_f projections (the proj-stack seam): concat
5699/// the host f32 rows and build one packed twin. `None` under the same guards as
5700/// `bf16_twin` (in_f % 8, exact representability of EVERY part). The stack REPLACES the
5701/// per-mat twins (VRAM-neutral): the per-mat arm launches against row-offset VIEWS of
5702/// the stack — same bytes, same kernel, bit-identical to separate residency.
5703fn bf16_stack_twin(e: &Engine, parts: &[&[f32]], in_f: usize) -> Res<Option<CudaSlice<u8>>> {
5704    let mut cat: Vec<f32> = Vec::with_capacity(parts.iter().map(|p| p.len()).sum());
5705    for p in parts {
5706        cat.extend_from_slice(p);
5707    }
5708    bf16_twin(e, &cat, in_f)
5709}
5710
5711/// Required-stack twin (the TP2 `need_twin` posture).
5712fn need_stack_twin(e: &Engine, parts: &[&[f32]], in_f: usize, what: &str) -> Res<CudaSlice<u8>> {
5713    bf16_stack_twin(e, parts, in_f)?.ok_or_else(|| {
5714        format!("qwen4exp_gpu tp2: {what} has no exact bf16 stack twin (in_f {in_f})").into()
5715    })
5716}
5717
5718/// One `qmatvec_bf16w_f32` launch against a ROW-OFFSET VIEW of a stacked twin (the
5719/// per-mat arm of the proj-stack seam): W = stack rows [row_off, row_off+out_f), batch 1.
5720/// Identical kernel, grid, and bytes as a separately-resident twin => bit-identical.
5721#[allow(clippy::too_many_arguments)]
5722fn launch_qmatvec_bf16w_off(
5723    e: &Engine,
5724    w_stack: &CudaSlice<u8>,
5725    row_off: usize,
5726    x: &CudaSlice<f32>,
5727    y: &mut CudaSlice<f32>,
5728    in_f: usize,
5729    out_f: usize,
5730    t: usize,
5731) -> Res<()> {
5732    if in_f % 8 != 0 {
5733        return Err("qmatvec_bf16w_f32: stride breaks the uint4/float4 vector width".into());
5734    }
5735    if y.len() < t * out_f {
5736        return Err("qmatvec_bf16w_f32: output buffer too short".into());
5737    }
5738    let byte_off = row_off * in_f * 2;
5739    if w_stack.len() < byte_off + out_f * in_f * 2 {
5740        return Err("qmatvec_bf16w_f32: stacked twin shorter than the row window".into());
5741    }
5742    let wv = w_stack.slice(byte_off..w_stack.len());
5743    let f = e.func("qmatvec_bf16w_f32");
5744    let cfg = LaunchConfig {
5745        grid_dim: (out_f as u32, t as u32, 1),
5746        block_dim: (128, 1, 1),
5747        shared_mem_bytes: 0,
5748    };
5749    let (inf, outf, ti) = (in_f as i32, out_f as i32, t as i32);
5750    let (wb, xb, xt, yb) = (0i64, 0i64, in_f as i64, 0i64);
5751    let stream = e.gpu.stream();
5752    let mut b = stream.launch_builder(&f);
5753    b.arg(&wv)
5754        .arg(x)
5755        .arg(y)
5756        .arg(&inf)
5757        .arg(&outf)
5758        .arg(&ti)
5759        .arg(&wb)
5760        .arg(&xb)
5761        .arg(&xt)
5762        .arg(&yb);
5763    unsafe {
5764        b.launch(cfg)?;
5765    }
5766    Ok(())
5767}
5768
5769/// `qmatvec_bf16w_f32` against row-offset W, x, and y VIEWS (t == 1): the per-selected-
5770/// expert arm of the DeviceBf16 draft bank (mtp-spec lane) — expert `e`'s projection is
5771/// rows [w_row_off, w_row_off+out_f) of the resident [E*out_f, in_f] bf16 stack. Same
5772/// kernel and per-row program as every other qmatvec_bf16w launch (exact-widening
5773/// products, block-128 reduce) => rows are bit-identical to a separately-resident twin.
5774#[allow(clippy::too_many_arguments)]
5775fn launch_qmatvec_bf16w_off_into(
5776    e: &Engine,
5777    w_stack: &CudaSlice<u8>,
5778    w_row_off: usize,
5779    x: &CudaSlice<f32>,
5780    x_off: usize,
5781    y: &mut CudaSlice<f32>,
5782    y_off: usize,
5783    in_f: usize,
5784    out_f: usize,
5785) -> Res<()> {
5786    if in_f % 8 != 0 {
5787        return Err("qmatvec_bf16w_f32: stride breaks the uint4/float4 vector width".into());
5788    }
5789    let byte_off = w_row_off * in_f * 2;
5790    if w_stack.len() < byte_off + out_f * in_f * 2 {
5791        return Err("qmatvec_bf16w_f32: bank shorter than the expert row window".into());
5792    }
5793    if x.len() < x_off + in_f || y.len() < y_off + out_f {
5794        return Err("qmatvec_bf16w_f32: operand views out of range".into());
5795    }
5796    let wv = w_stack.slice(byte_off..w_stack.len());
5797    let xv = x.slice(x_off..x_off + in_f);
5798    let mut yv = y.slice_mut(y_off..y_off + out_f);
5799    let f = e.func("qmatvec_bf16w_f32");
5800    let cfg = LaunchConfig {
5801        grid_dim: (out_f as u32, 1, 1),
5802        block_dim: (128, 1, 1),
5803        shared_mem_bytes: 0,
5804    };
5805    let (inf, outf, ti) = (in_f as i32, out_f as i32, 1i32);
5806    let (wb, xb, xt, yb) = (0i64, 0i64, in_f as i64, 0i64);
5807    let stream = e.gpu.stream();
5808    let mut b = stream.launch_builder(&f);
5809    b.arg(&wv)
5810        .arg(&xv)
5811        .arg(&mut yv)
5812        .arg(&inf)
5813        .arg(&outf)
5814        .arg(&ti)
5815        .arg(&wb)
5816        .arg(&xb)
5817        .arg(&xt)
5818        .arg(&yb);
5819    unsafe {
5820        b.launch(cfg)?;
5821    }
5822    Ok(())
5823}
5824
5825/// Device-selected expert launch over a DeviceBf16 bank (`qmatvec_bf16w_sel_f32`,
5826/// devtwin lane): one launch per projection covers every routed expert — slot s reads
5827/// its expert id from the DEVICE `sel` array at `sel_off + s` and writes y at s*out_f.
5828/// Per-row program qmatvec_bf16w_f32 VERBATIM => bit-identical to the per-slot
5829/// `launch_qmatvec_bf16w_off_into` chain (asserted by the bf16 oracle's sel mode).
5830#[allow(clippy::too_many_arguments)]
5831fn launch_qmatvec_bf16w_sel(
5832    e: &Engine,
5833    bank: &CudaSlice<u8>,
5834    sel: &CudaSlice<i32>,
5835    sel_off: usize,
5836    x: &CudaSlice<f32>,
5837    x_off: usize,
5838    // Per-slot activation stride in elements: 0 = shared row (gate/up), in_f = each
5839    // slot its own row (down over the act slab).
5840    x_sstride: usize,
5841    y: &mut CudaSlice<f32>,
5842    n_sel: usize,
5843    in_f: usize,
5844    out_f: usize,
5845) -> Res<()> {
5846    if in_f % 8 != 0 {
5847        return Err("qmatvec_bf16w_sel_f32: stride breaks the uint4/float4 vector width".into());
5848    }
5849    if sel.len() < sel_off + n_sel
5850        || x.len() < x_off + (n_sel - 1) * x_sstride + in_f
5851        || y.len() < n_sel * out_f
5852        || n_sel == 0
5853    {
5854        return Err("qmatvec_bf16w_sel_f32: operand views out of range".into());
5855    }
5856    let sv = sel.slice(sel_off..sel_off + n_sel);
5857    let xv = x.slice(x_off..x.len());
5858    let f = e.func("qmatvec_bf16w_sel_f32");
5859    let cfg = LaunchConfig {
5860        grid_dim: (out_f as u32, 1, n_sel as u32),
5861        block_dim: (128, 1, 1),
5862        shared_mem_bytes: 0,
5863    };
5864    let (inf, outf, ns) = (in_f as i32, out_f as i32, n_sel as i32);
5865    let xs = x_sstride as i64;
5866    let stream = e.gpu.stream();
5867    let mut b = stream.launch_builder(&f);
5868    b.arg(bank)
5869        .arg(&sv)
5870        .arg(&xv)
5871        .arg(&mut *y)
5872        .arg(&inf)
5873        .arg(&outf)
5874        .arg(&ns)
5875        .arg(&xs);
5876    unsafe {
5877        b.launch(cfg)?;
5878    }
5879    Ok(())
5880}
5881
5882/// Multi-token weight-shared launch (`qmatvec_bf16w_mt_f32`, mtp-spec verify): one
5883/// block per output row reads W once and fills EVERY token's output — per (row, token)
5884/// bit-identical to the per-token grid (kernel doc). 2 <= t <= 12; `w_row_off` selects
5885/// a row window of a stacked twin.
5886#[allow(clippy::too_many_arguments)]
5887fn launch_qmatvec_bf16w_mt(
5888    e: &Engine,
5889    w_stack: &CudaSlice<u8>,
5890    w_row_off: usize,
5891    x: &CudaSlice<f32>,
5892    y: &mut CudaSlice<f32>,
5893    in_f: usize,
5894    out_f: usize,
5895    t: usize,
5896) -> Res<()> {
5897    if in_f % 8 != 0 {
5898        return Err("qmatvec_bf16w_mt_f32: in_f % 8 != 0".into());
5899    }
5900    if !(2..=12).contains(&t) {
5901        return Err("qmatvec_bf16w_mt_f32: t out of range (2..=12)".into());
5902    }
5903    let byte_off = w_row_off * in_f * 2;
5904    if w_stack.len() < byte_off + out_f * in_f * 2 || y.len() < t * out_f || x.len() < t * in_f {
5905        return Err("qmatvec_bf16w_mt_f32: operands out of range".into());
5906    }
5907    let wv = w_stack.slice(byte_off..w_stack.len());
5908    let f = e.func("qmatvec_bf16w_mt_f32");
5909    let cfg = LaunchConfig {
5910        grid_dim: (out_f as u32, 1, 1),
5911        block_dim: (128, 1, 1),
5912        shared_mem_bytes: 0,
5913    };
5914    let (inf, outf, ti) = (in_f as i32, out_f as i32, t as i32);
5915    let (wb, xb, xt, yb) = (0i64, 0i64, in_f as i64, 0i64);
5916    let stream = e.gpu.stream();
5917    let mut b = stream.launch_builder(&f);
5918    b.arg(&wv)
5919        .arg(x)
5920        .arg(y)
5921        .arg(&inf)
5922        .arg(&outf)
5923        .arg(&ti)
5924        .arg(&wb)
5925        .arg(&xb)
5926        .arg(&xt)
5927        .arg(&yb);
5928    unsafe {
5929        b.launch(cfg)?;
5930    }
5931    Ok(())
5932}
5933
5934/// Trunk dense linear off a STACKED bf16 twin (proj-stack residency): the bf16 arm is a
5935/// row-offset view launch when the twin exists and the trunk seam is on, else the f32
5936/// cuBLASLt path.
5937#[allow(clippy::too_many_arguments)]
5938fn linear_trunk_stacked_into(
5939    e: &Engine,
5940    w_f32: &CudaSlice<f32>,
5941    stack_b16: &Option<CudaSlice<u8>>,
5942    row_off: usize,
5943    x: &CudaSlice<f32>,
5944    y: &mut CudaSlice<f32>,
5945    t: usize,
5946    in_f: usize,
5947    out_f: usize,
5948) -> Res<()> {
5949    if trunk_bf16_on() {
5950        if let Some(w) = stack_b16 {
5951            if (2..=12).contains(&t) && verify_mt_on() {
5952                return launch_qmatvec_bf16w_mt(e, w, row_off, x, y, in_f, out_f, t);
5953            }
5954            return launch_qmatvec_bf16w_off(e, w, row_off, x, y, in_f, out_f, t);
5955        }
5956    }
5957    if w_f32.len() < in_f * out_f {
5958        return Err(
5959            "qwen4exp_gpu: trunk f32 original dropped (trunk_f32_diet) — the bf16 \
5960                    twin path is required (keep trunk seams ON)"
5961                .into(),
5962        );
5963    }
5964    e.linear_device_into(x, w_f32, y, t, in_f, out_f)
5965}
5966
5967/// One launch of `qmatvec_bf16w_multi4_f32`: the row-stacked twin against ONE t==1
5968/// activation, each output row routed into its original destination buffer by row range
5969/// (raw device pointers — no copies). Per-row math is qmatvec_bf16w_f32 VERBATIM, so
5970/// outputs are BIT-IDENTICAL to the per-mat launches this replaces.
5971fn launch_qmatvec_bf16w_multi4(
5972    e: &Engine,
5973    w_stack: &CudaSlice<u8>,
5974    x: &CudaSlice<f32>,
5975    parts: &[(&CudaSlice<f32>, usize)],
5976    in_f: usize,
5977) -> Res<()> {
5978    if in_f % 8 != 0 {
5979        return Err("qmatvec_bf16w_multi4_f32: in_f % 8 != 0".into());
5980    }
5981    if parts.is_empty() || parts.len() > 4 {
5982        return Err("qmatvec_bf16w_multi4_f32: 1..=4 parts".into());
5983    }
5984    let total: usize = parts.iter().map(|&(_, r)| r).sum();
5985    if w_stack.len() < total * in_f * 2 {
5986        return Err("qmatvec_bf16w_multi4_f32: stacked twin shorter than the row plan".into());
5987    }
5988    let stream = e.gpu.stream();
5989    let mut ptrs = [0u64; 4];
5990    let mut rows = [0i32; 4];
5991    for (i, &(buf, r)) in parts.iter().enumerate() {
5992        if buf.len() < r {
5993            return Err("qmatvec_bf16w_multi4_f32: destination shorter than its rows".into());
5994        }
5995        ptrs[i] = buf.device_ptr(&stream).0;
5996        rows[i] = r as i32;
5997    }
5998    let f = e.func("qmatvec_bf16w_multi4_f32");
5999    let cfg = LaunchConfig {
6000        grid_dim: (total as u32, 1, 1),
6001        block_dim: (128, 1, 1),
6002        shared_mem_bytes: 0,
6003    };
6004    let inf = in_f as i32;
6005    let mut b = stream.launch_builder(&f);
6006    b.arg(w_stack)
6007        .arg(x)
6008        .arg(&ptrs[0])
6009        .arg(&rows[0])
6010        .arg(&ptrs[1])
6011        .arg(&rows[1])
6012        .arg(&ptrs[2])
6013        .arg(&rows[2])
6014        .arg(&ptrs[3])
6015        .arg(&rows[3])
6016        .arg(&inf);
6017    unsafe {
6018        b.launch(cfg)?;
6019    }
6020    Ok(())
6021}
6022
6023/// Trunk dense linear into a caller-provided buffer: the bf16 twin (one
6024/// `qmatvec_bf16w_f32` launch) when resident and the seam is on, else the f32
6025/// cuBLASLt path — the A/B twin (the step-workspace form, item 2a).
6026#[allow(clippy::too_many_arguments)]
6027fn linear_trunk_into(
6028    e: &Engine,
6029    w_f32: &CudaSlice<f32>,
6030    w_b16: &Option<CudaSlice<u8>>,
6031    x: &CudaSlice<f32>,
6032    y: &mut CudaSlice<f32>,
6033    t: usize,
6034    in_f: usize,
6035    out_f: usize,
6036) -> Res<()> {
6037    if trunk_bf16_on() {
6038        if let Some(w) = w_b16 {
6039            if (2..=12).contains(&t) && verify_mt_on() {
6040                return launch_qmatvec_bf16w_mt(e, w, 0, x, y, in_f, out_f, t);
6041            }
6042            return launch_qmatvec_bf16w(e, w, x, y, in_f, out_f, t, 1, 0, 0, in_f, 0);
6043        }
6044    }
6045    if w_f32.len() < in_f * out_f {
6046        return Err(
6047            "qwen4exp_gpu: trunk f32 original dropped (trunk_f32_diet) — the bf16 \
6048                    twin path is required (keep trunk seams ON)"
6049                .into(),
6050        );
6051    }
6052    e.linear_device_into(x, w_f32, y, t, in_f, out_f)
6053}
6054
6055/// One launch of the grouped selected-experts matvec: y[slot, :out_f] =
6056/// macros[sel[slot]] × (W_{sel[slot]} @ x_slot) over the AS-STORED modelopt bank (no
6057/// repack). `x_stride` = 0 shares one activation row across slots (gate/up); = in_f
6058/// reads per-slot rows (down). Dispatches the v2 kernel (uint4 code loads + 2 rows per
6059/// warp — perf lane item 3) when the seam is on and the geometry admits it
6060/// (in_f % 32 == 0, out_f % 2 == 0); v1 is the fallback and the A/B twin. Round 3 adds
6061/// the v3 kernel (4 rows/warp, `set_sel_v3`, out_f % 4 == 0) ahead of v2 in the chain.
6062#[allow(clippy::too_many_arguments)]
6063fn launch_nvfp4_sel_matvec(
6064    e: &Engine,
6065    codes: &CudaSlice<u8>,
6066    scales: &CudaSlice<u8>,
6067    macros_dev: &CudaSlice<f32>,
6068    sel: &CudaSlice<i32>,
6069    x: &CudaSlice<f32>,
6070    y: &mut CudaSlice<f32>,
6071    n_sel: usize,
6072    in_f: usize,
6073    out_f: usize,
6074    x_stride: usize,
6075) -> Res<()> {
6076    if in_f % 16 != 0 {
6077        return Err("qmatvec_nvfp4_modelopt_sel_f32: in_f % 16 != 0".into());
6078    }
6079    if y.len() < n_sel * out_f {
6080        return Err("qmatvec_nvfp4_modelopt_sel_f32: output shorter than n_sel*out_f".into());
6081    }
6082    // Sub-warp pair groups (`selgroup`, default AUTO since 2026-09-02) take precedence over the v3/v2/v1
6083    // chain when the geometry tiles exactly; `(g=32, rows=4)` reproduces v3's bits.
6084    let grp = sel_group_resolve(sel_group_dn(), in_f, out_f);
6085    let v3 = grp.is_none() && sel_v3_on() && in_f % 32 == 0 && out_f % 4 == 0;
6086    let v2 = grp.is_none() && !v3 && sel_v2_on() && in_f % 32 == 0 && out_f % 2 == 0;
6087    let f = e.func(if grp.is_some() {
6088        "qmatvec_nvfp4_modelopt_sel_g_f32"
6089    } else if v3 {
6090        "qmatvec_nvfp4_modelopt_sel_f32_v3"
6091    } else if v2 {
6092        "qmatvec_nvfp4_modelopt_sel_f32_v2"
6093    } else {
6094        "qmatvec_nvfp4_modelopt_sel_f32"
6095    });
6096    // Warp packing (4 warps/block) was tried here and REVERTED: measured NEGATIVE on
6097    // decode (plain arm 14.38 -> 15.13 ms) and flat on verify sel (mtp6 battery,
6098    // spec/mtp6) — the sel slice is not SM-block-slot-limited. The kernels keep the
6099    // lane-based indexing (identical at block 32); launch stays one warp per block. The
6100    // `selgroup` kernels honour `blockDim.x >> 5` too, but this lane deliberately leaves
6101    // block 32 alone so the A/B attributes ONE change (the lane partition) — a warps-per-
6102    // block knob would re-open the reverted measurement as a second free variable.
6103    let grid_x = match grp {
6104        Some((g, rows)) => out_f / ((32 / g) * rows),
6105        None if v3 => out_f / 4,
6106        None if v2 => out_f / 2,
6107        None => out_f,
6108    };
6109    let cfg = LaunchConfig {
6110        grid_dim: (grid_x as u32, n_sel as u32, 1),
6111        block_dim: (32, 1, 1),
6112        shared_mem_bytes: 0,
6113    };
6114    let (inf, outf) = (in_f as i32, out_f as i32);
6115    let xs = x_stride as i64;
6116    let (gi, ri) = grp.map_or((0i32, 0i32), |(g, rows)| (g as i32, rows as i32));
6117    let stream = e.gpu.stream();
6118    let mut b = stream.launch_builder(&f);
6119    b.arg(codes)
6120        .arg(scales)
6121        .arg(macros_dev)
6122        .arg(sel)
6123        .arg(x)
6124        .arg(y)
6125        .arg(&inf)
6126        .arg(&outf)
6127        .arg(&xs);
6128    if grp.is_some() {
6129        b.arg(&gi).arg(&ri);
6130    }
6131    unsafe {
6132        b.launch(cfg)?;
6133    }
6134    Ok(())
6135}
6136
6137/// One launch of the fused gate+up+silu sel matvec
6138/// (`qmatvec_nvfp4_modelopt_sel_gu_silu_f32`): act[slot, :ff] = silu(gate) * up over
6139/// the shared activation row. `sel`/`pack_raw` pick the addressing mode (host sel
6140/// array vs the TP2 count-gated pack blob). Bit-identical to the v3 gate + v3 up +
6141/// silu_mul chain (kernel doc).
6142#[allow(clippy::too_many_arguments)]
6143fn launch_nvfp4_sel_gu_silu(
6144    e: &Engine,
6145    gate: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
6146    up: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
6147    sel: Option<&CudaSlice<i32>>,
6148    pack_raw: u64,
6149    n_sel: usize,
6150    x: &CudaSlice<f32>,
6151    act: &mut CudaSlice<f32>,
6152    in_f: usize,
6153    ff: usize,
6154    // (slot -> token map, x token stride): ONE launch over every verify column's
6155    // routed experts (per-slot program unchanged — bit-identical). None = shared x.
6156    tok: Option<(&CudaSlice<i32>, usize)>,
6157) -> Res<()> {
6158    if in_f % 32 != 0 || ff % 4 != 0 {
6159        return Err("qmatvec_nvfp4_modelopt_sel_gu_silu_f32: geometry".into());
6160    }
6161    if act.len() < n_sel * ff {
6162        return Err("qmatvec_nvfp4_modelopt_sel_gu_silu_f32: act buffer too short".into());
6163    }
6164    if sel.is_none() == (pack_raw == 0) {
6165        return Err("qmatvec_nvfp4_modelopt_sel_gu_silu_f32: exactly one of sel/pack".into());
6166    }
6167    // Sub-warp pair groups (`selgroup`, default AUTO since 2026-09-02); `(g=32, rows=4)` reproduces the
6168    // shipped kernel's bits, pack and tok_map modes included.
6169    let grp = sel_group_resolve(sel_group_gu(), in_f, ff);
6170    let f = e.func(if grp.is_some() {
6171        "qmatvec_nvfp4_modelopt_sel_gu_silu_g_f32"
6172    } else {
6173        "qmatvec_nvfp4_modelopt_sel_gu_silu_f32"
6174    });
6175    // Warp packing reverted (see launch_nvfp4_sel_matvec): one warp per block.
6176    let grid_x = match grp {
6177        Some((g, rows)) => ff / ((32 / g) * rows),
6178        None => ff / 4,
6179    };
6180    let cfg = LaunchConfig {
6181        grid_dim: (grid_x as u32, n_sel as u32, 1),
6182        block_dim: (32, 1, 1),
6183        shared_mem_bytes: 0,
6184    };
6185    let (inf, ffi, ms) = (in_f as i32, ff as i32, n_sel as i32);
6186    let (gi, ri) = grp.map_or((0i32, 0i32), |(g, rows)| (g as i32, rows as i32));
6187    let stream = e.gpu.stream();
6188    let mut b = stream.launch_builder(&f);
6189    b.arg(gate.0)
6190        .arg(gate.1)
6191        .arg(gate.2)
6192        .arg(up.0)
6193        .arg(up.1)
6194        .arg(up.2);
6195    match sel {
6196        Some(s) => {
6197            b.arg(s);
6198        }
6199        None => {
6200            // unread in pack mode; any live device pointer keeps the arg slot filled
6201            b.arg(gate.2);
6202        }
6203    }
6204    let stream2 = e.gpu.stream();
6205    let (tok_raw, x_tstride) = match tok {
6206        Some((tm, stride)) => (tm.device_ptr(&stream2).0, stride as i64),
6207        None => (0u64, 0i64),
6208    };
6209    b.arg(&pack_raw)
6210        .arg(&ms)
6211        .arg(x)
6212        .arg(&mut *act)
6213        .arg(&inf)
6214        .arg(&ffi)
6215        .arg(&tok_raw)
6216        .arg(&x_tstride);
6217    if grp.is_some() {
6218        b.arg(&gi).arg(&ri);
6219    }
6220    unsafe {
6221        b.launch(cfg)?;
6222    }
6223    Ok(())
6224}
6225
6226/// One row of the MoE routed-union cost probe (`moeu` lane, mtp13).
6227#[derive(Debug, Clone, Copy)]
6228pub struct MoeUnionRow {
6229    /// Verify columns fed (t). 1 = the plain-decode reference shape.
6230    pub t: usize,
6231    /// (token, expert) pairs dispatched = the grid.y extent of both launches.
6232    pub slots: usize,
6233    /// DISTINCT experts among those slots — the only quantity a union gather changes.
6234    pub union_size: usize,
6235    /// Median us/launch of the fused gate+up+silu sel matvec.
6236    pub gu_us: f64,
6237    /// Median us/launch of the down sel matvec.
6238    pub down_us: f64,
6239    /// (max-min)/median over the arm's reps. Reported so a reader can see whether an arm's
6240    /// delta against another arm is inside its own noise; LAW:interleaved-ab wants every arm
6241    /// to report its spread, and at realistic union sizes this lever's delta is smaller than
6242    /// this column.
6243    pub gu_spread_rel: f64,
6244    pub down_spread_rel: f64,
6245}
6246
6247/// COST INSTRUMENT for the MoE routed-union lever (`moeu`), and the reason it exists
6248/// instead of a kernel: the union gather changes exactly ONE thing about the MoE verify
6249/// section — how many DISTINCT experts' NVFP4 bytes the chunk reads — while leaving the
6250/// per-slot arithmetic, the slot count and the launch geometry alone. So the lever can be
6251/// priced WITHOUT writing it, by running the shipped kernels at a fixed slot count and
6252/// varying only the number of distinct experts those slots name.
6253///
6254/// The three-point decomposition each sweep yields, at t verify columns and k selected:
6255///
6256/// - `slots = t*k, union = t*k` — TODAY. Every slot reads its expert's bytes; duplicates
6257///   across tokens re-read (the kernel doc says so in as many words: "the weight banks are
6258///   read once per selected slot either way — the launch count is what drops").
6259/// - `slots = t*k, union = U` — the IDEALISED union gather: same arithmetic, same slots,
6260///   only `U` experts' bytes touched. A real union-major kernel cannot beat this by much
6261///   and cannot be slower on traffic, so this row is the lever's payoff, measured.
6262/// - `slots = k, union = k` — the t=1 plain reference, for the round arithmetic.
6263///
6264/// If the middle row does not beat the first, the section's cost is not the duplicated
6265/// bytes and the lever has no surface REGARDLESS of what the routed union sizes turn out
6266/// to be — the card's 128 MiB L2 is large enough to hold a whole chunk's routed working
6267/// set at this geometry (60 slots x 1.76 MiB gate+up = 105.5 MiB), so the hardware may
6268/// already be deduplicating what the kernel re-reads.
6269///
6270/// SYNTHETIC BANKS, stated because a probe that looks like a gate is how a wrong number
6271/// gets quoted later. This loads NO checkpoint: it allocates a bank of the serving
6272/// geometry (`experts` x `ff` x `hidden` gate + up, `experts` x `hidden` x `ff` down) and
6273/// fills it with deterministic pseudo-random bytes. That is sound for a TRAFFIC and
6274/// LATENCY probe and for nothing else: the NVFP4 lane program is branch-free and
6275/// data-independent (LUT extract, fixed shfl tree), so bytes decide addresses and never
6276/// control flow. Scale bytes are held in a modest ue4m3 range so the f32 chain stays in
6277/// normal range; no output of this probe is a correctness claim and none is compared to an
6278/// oracle. Expert ids are SPREAD across the bank by a fixed stride, because a clustered
6279/// id set would make the sweep measure address locality instead of distinct-byte count.
6280///
6281/// Numbers from this probe are per-LAUNCH; the section cost is per LAYER (one gu + one
6282/// down launch each) times the model's MoE layer count.
6283pub fn moe_union_cost_probe(
6284    e: &Engine,
6285    experts: usize,
6286    hidden: usize,
6287    ff: usize,
6288    selected: usize,
6289    t: usize,
6290    reps: usize,
6291) -> Res<Vec<MoeUnionRow>> {
6292    if hidden % 32 != 0 || ff % 4 != 0 {
6293        return Err("moe_union_cost_probe: needs the gufuse geometry (hidden%32, ff%4)".into());
6294    }
6295    if selected == 0 || t == 0 || reps == 0 {
6296        return Err("moe_union_cost_probe: selected/t/reps must be non-zero".into());
6297    }
6298    // Deterministic byte fill. Codes index a 16-entry LUT so every byte is legal; scale
6299    // bytes are confined to a mid ue4m3 range so no product leaves normal f32 range.
6300    let code_byte = |i: usize| -> u8 { (i.wrapping_mul(2_654_435_761) >> 13) as u8 };
6301    let scale_byte = |i: usize| -> u8 { 0x38 | ((i.wrapping_mul(40_503) >> 7) & 0x07) as u8 };
6302    let mk = |n: usize, f: &dyn Fn(usize) -> u8| -> Res<CudaSlice<u8>> {
6303        let host: Vec<u8> = (0..n).map(f).collect();
6304        let d = e.htod_bytes(&host)?;
6305        drop(host);
6306        Ok(d)
6307    };
6308    // gate/up: [experts, ff, hidden]; down: [experts, hidden, ff]. Gate and up get
6309    // SEPARATE allocations on purpose — aliasing them would halve the distinct bytes and
6310    // silently turn the sweep into a cache-hit measurement.
6311    let gu_codes_n = experts * ff * (hidden / 2);
6312    let gu_scales_n = experts * ff * (hidden / 16);
6313    let dn_codes_n = experts * hidden * (ff / 2);
6314    let dn_scales_n = experts * hidden * (ff / 16);
6315    let gc = mk(gu_codes_n, &code_byte)?;
6316    let gs = mk(gu_scales_n, &scale_byte)?;
6317    let uc = mk(gu_codes_n, &|i| code_byte(i ^ 0x5A5A_5A5A))?;
6318    let us = mk(gu_scales_n, &|i| scale_byte(i ^ 0x3C3C_3C3C))?;
6319    let dc = mk(dn_codes_n, &|i| code_byte(i ^ 0x0F0F_0F0F))?;
6320    let ds = mk(dn_scales_n, &|i| scale_byte(i ^ 0x1111_1111))?;
6321    let gm = e.htod(&vec![1.0f32; experts])?;
6322    let um = e.htod(&vec![1.0f32; experts])?;
6323    let dm = e.htod(&vec![1.0f32; experts])?;
6324    // Activations: small normal values, one row per verify column.
6325    let mixed_h: Vec<f32> = (0..t * hidden)
6326        .map(|i| ((i.wrapping_mul(40_503) % 1000) as f32) / 4000.0 - 0.125)
6327        .collect();
6328    let mixed = e.htod(&mixed_h)?;
6329
6330    // Spread candidate expert ids over the whole bank by a fixed stride.
6331    let pool: Vec<i32> = {
6332        let stride = (experts / (t * selected).max(1)).max(1);
6333        (0..t * selected)
6334            .map(|i| ((i * stride) % experts) as i32)
6335            .collect()
6336    };
6337
6338    let mut rows: Vec<MoeUnionRow> = Vec::new();
6339    // (t, union target). `new` fresh experts per extra column: union = k + (t-1)*new.
6340    let mut cells: Vec<(usize, usize)> = vec![(1, selected)];
6341    for new in 0..=selected {
6342        cells.push((t, selected + (t - 1) * new));
6343    }
6344    // Build EVERY cell's device state first, then interleave the arms rep by rep.
6345    //
6346    // WHY THE ARMS ARE INTERLEAVED AND NOT SWEPT (LAW:interleaved-ab): the union sizes are
6347    // arms of a perf A/B, and a contiguous block per arm ordered monotonically in union size
6348    // lets any clock/thermal drift over the run masquerade as a union effect -- in this
6349    // sweep's natural order (small union first) drift would INFLATE the apparent payoff,
6350    // which is the direction that would have made a dead lever look alive. Interleaving puts
6351    // every arm at every point of the drift curve.
6352    struct Cell {
6353        t: usize,
6354        slots: usize,
6355        union_size: usize,
6356        sel: CudaSlice<i32>,
6357        tokm: CudaSlice<i32>,
6358        act: CudaSlice<f32>,
6359        partial: CudaSlice<f32>,
6360        gu: Vec<f64>,
6361        dn: Vec<f64>,
6362    }
6363    let mut built: Vec<Cell> = Vec::with_capacity(cells.len());
6364    for (cells_t, want_union) in cells {
6365        let slots = cells_t * selected;
6366        // Build the slot->expert map: column 0 takes the first k of the pool; each later
6367        // column re-uses `shared` of column 0's experts and takes `new` fresh ones. Within
6368        // a column the ids stay DISTINCT, which is what top-k routing guarantees.
6369        let new = if cells_t > 1 {
6370            (want_union - selected) / (cells_t - 1)
6371        } else {
6372            0
6373        };
6374        let shared = selected - new;
6375        let mut sel_h: Vec<i32> = Vec::with_capacity(slots);
6376        let mut tok_h: Vec<i32> = Vec::with_capacity(slots);
6377        let mut fresh = selected;
6378        for col in 0..cells_t {
6379            if col == 0 {
6380                sel_h.extend_from_slice(&pool[0..selected]);
6381            } else {
6382                sel_h.extend_from_slice(&pool[0..shared]);
6383                for _ in 0..new {
6384                    sel_h.push(pool[fresh % pool.len()]);
6385                    fresh += 1;
6386                }
6387            }
6388            for _ in 0..selected {
6389                tok_h.push(col as i32);
6390            }
6391        }
6392        let union_size = {
6393            let mut u: Vec<i32> = sel_h.clone();
6394            u.sort_unstable();
6395            u.dedup();
6396            u.len()
6397        };
6398        built.push(Cell {
6399            t: cells_t,
6400            slots,
6401            union_size,
6402            sel: e.htod_i32(&sel_h)?,
6403            tokm: e.htod_i32(&tok_h)?,
6404            act: e.zeros(slots * ff)?,
6405            partial: e.zeros(slots * hidden)?,
6406            gu: Vec::with_capacity(reps),
6407            dn: Vec::with_capacity(reps),
6408        });
6409    }
6410    // Rep 0 is a warmed throwaway for EVERY arm: the first launch of a width pays workspace
6411    // allocation and a cold instruction cache (the scan_warm lesson).
6412    for rep in 0..(reps + 1) {
6413        for c in built.iter_mut() {
6414            let tok_arg = if c.t > 1 {
6415                Some((&c.tokm, hidden))
6416            } else {
6417                None
6418            };
6419            e.stream().synchronize()?;
6420            let t0 = std::time::Instant::now();
6421            launch_nvfp4_sel_gu_silu(
6422                e,
6423                (&gc, &gs, &gm),
6424                (&uc, &us, &um),
6425                Some(&c.sel),
6426                0,
6427                c.slots,
6428                &mixed,
6429                &mut c.act,
6430                hidden,
6431                ff,
6432                tok_arg,
6433            )?;
6434            e.stream().synchronize()?;
6435            let t1 = std::time::Instant::now();
6436            launch_nvfp4_sel_matvec(
6437                e,
6438                &dc,
6439                &ds,
6440                &dm,
6441                &c.sel,
6442                &c.act,
6443                &mut c.partial,
6444                c.slots,
6445                ff,
6446                hidden,
6447                ff,
6448            )?;
6449            e.stream().synchronize()?;
6450            let t2 = std::time::Instant::now();
6451            if rep > 0 {
6452                c.gu.push(t1.duration_since(t0).as_secs_f64() * 1e6);
6453                c.dn.push(t2.duration_since(t1).as_secs_f64() * 1e6);
6454            }
6455        }
6456    }
6457    let stat = |v: &[f64]| -> (f64, f64) {
6458        let mut s = v.to_vec();
6459        s.sort_by(|a, b| a.partial_cmp(b).unwrap());
6460        let med = s[s.len() / 2];
6461        // Spread of the decision statistic, so a reader can see whether an arm's delta is
6462        // inside its own noise (the escalation rule's input).
6463        let spread = if med > 0.0 {
6464            (s[s.len() - 1] - s[0]) / med
6465        } else {
6466            0.0
6467        };
6468        (med, spread)
6469    };
6470    for c in &built {
6471        let (gu_us, gu_spread) = stat(&c.gu);
6472        let (down_us, down_spread) = stat(&c.dn);
6473        rows.push(MoeUnionRow {
6474            t: c.t,
6475            slots: c.slots,
6476            union_size: c.union_size,
6477            gu_us,
6478            down_us,
6479            gu_spread_rel: gu_spread,
6480            down_spread_rel: down_spread,
6481        });
6482    }
6483    Ok(rows)
6484}
6485
6486/// One row of the sel-kernel SHAPE cost probe (`downsel` lane, mtp14).
6487#[derive(Debug, Clone)]
6488pub struct SelShapeRow {
6489    /// Verify columns fed (t). 1 = the plain-decode shape.
6490    pub t: usize,
6491    /// (token, expert) slots = grid.y of both launches.
6492    pub slots: usize,
6493    /// The `selgroup` spec this arm ran (`off` = the shipped v3 / gufuse kernels).
6494    pub arm: String,
6495    /// Resolved (g, rows) per family, and the grid.x each launch used — the whole point of
6496    /// the table is that a shape trades lane occupancy against warp count, so both have to
6497    /// be readable next to the time.
6498    pub gu_shape: String,
6499    pub dn_shape: String,
6500    pub gu_grid_x: usize,
6501    pub dn_grid_x: usize,
6502    pub gu_us: f64,
6503    pub down_us: f64,
6504    pub gu_spread_rel: f64,
6505    pub down_spread_rel: f64,
6506}
6507
6508/// Cost probe for the sel matvecs' SUB-WARP pair-group shapes (`downsel` lane, mtp14),
6509/// on synthetic banks of the serving geometry with NO checkpoint (~1.3 GiB, ~30 s) — so it
6510/// interleaves between any other lane's cells the way the `moeu` probe does.
6511///
6512/// WHAT IT MEASURES. `moe_union_probe` established that this section is per-slot-work bound
6513/// (KNEE:q4e-sel-slots-not-bytes). Per-slot work is what an idle lane wastes, and at this
6514/// artifact's geometry the pair loop leaves 37.5% of the down launch's lanes and 16.7% of
6515/// the gate+up launch's lane-slots empty. This probe runs the SAME slots, the SAME distinct
6516/// experts and the SAME banks through each candidate lane partition, so the only thing
6517/// varying between arms is the shape.
6518///
6519/// TWO CONTROLS BUILT IN, because a shape table without them is unreadable:
6520///
6521/// 1. **`off` vs `dn:32:4+gu:32:4`.** The second arm is the sub-warp kernel at the shape
6522///    where it degenerates to the shipped program — bit-identical output (gated by
6523///    `gate_nvfp4_sel_group`). It went in as a noise floor (LAW:ab-arm-identity applied to a
6524///    perf table: an arm running the same program must measure the same) and it EARNED its
6525///    place by not being one — it reproducibly measures a few percent faster than `off`,
6526///    because the source restructure changes nvcc's scheduling for identical bits. So
6527///    `arm / off` mixes two effects and only `arm / control` is the shape's. Anyone reading
6528///    this table for a shape claim reads the control-relative column.
6529/// 2. **Per-arm spread**, reported per arm, never averaged away.
6530///
6531/// Arms are interleaved REP BY REP (LAW:interleaved-ab / TRAP:monotone-sweep-inflates-the-
6532/// lever): a shape ladder run as contiguous blocks would let clock/thermal drift over the
6533/// run read as a shape effect, and the natural order (baseline first) inflates the payoff.
6534/// Rep 0 of every arm is a warmed throwaway (the `scan_warm` lesson).
6535///
6536/// TIMING ARM: hold `flock -x` around the WHOLE invocation, and never quote a row measured
6537/// on the rig (LAW:rig-gpu-exactness-only — the rig is for the exactness arms above).
6538#[allow(clippy::too_many_arguments)]
6539pub fn sel_shape_cost_probe(
6540    e: &Engine,
6541    experts: usize,
6542    hidden: usize,
6543    ff: usize,
6544    selected: usize,
6545    t: usize,
6546    reps: usize,
6547    arms: &[String],
6548) -> Res<Vec<SelShapeRow>> {
6549    if hidden % 32 != 0 || ff % 4 != 0 {
6550        return Err("sel_shape_cost_probe: needs the gufuse geometry (hidden%32, ff%4)".into());
6551    }
6552    if selected == 0 || t == 0 || reps == 0 || arms.is_empty() {
6553        return Err("sel_shape_cost_probe: selected/t/reps/arms must be non-empty".into());
6554    }
6555    let saved = sel_group_spec();
6556    let out = sel_shape_cost_probe_inner(e, experts, hidden, ff, selected, t, reps, arms);
6557    set_sel_group(&saved);
6558    out
6559}
6560
6561#[allow(clippy::too_many_arguments)]
6562fn sel_shape_cost_probe_inner(
6563    e: &Engine,
6564    experts: usize,
6565    hidden: usize,
6566    ff: usize,
6567    selected: usize,
6568    t: usize,
6569    reps: usize,
6570    arms: &[String],
6571) -> Res<Vec<SelShapeRow>> {
6572    // Bank fill and the honesty notes are `moe_union_cost_probe`'s, deliberately: codes
6573    // index a 16-entry LUT so every byte is legal, scale bytes sit in a mid ue4m3 range so
6574    // no product leaves normal f32 range, and gate/up get SEPARATE allocations (aliasing
6575    // them would halve the distinct bytes). No output is compared to an oracle here — that
6576    // is `gate_nvfp4_sel_group`'s job; this is a latency arm only.
6577    let code_byte = |i: usize| -> u8 { (i.wrapping_mul(2_654_435_761) >> 13) as u8 };
6578    let scale_byte = |i: usize| -> u8 { 0x38 | ((i.wrapping_mul(40_503) >> 7) & 0x07) as u8 };
6579    let mk = |n: usize, f: &dyn Fn(usize) -> u8| -> Res<CudaSlice<u8>> {
6580        let host: Vec<u8> = (0..n).map(f).collect();
6581        let d = e.htod_bytes(&host)?;
6582        drop(host);
6583        Ok(d)
6584    };
6585    let gc = mk(experts * ff * (hidden / 2), &code_byte)?;
6586    let gs = mk(experts * ff * (hidden / 16), &scale_byte)?;
6587    let uc = mk(experts * ff * (hidden / 2), &|i| code_byte(i ^ 0x5A5A_5A5A))?;
6588    let us = mk(experts * ff * (hidden / 16), &|i| {
6589        scale_byte(i ^ 0x3C3C_3C3C)
6590    })?;
6591    let dc = mk(experts * hidden * (ff / 2), &|i| code_byte(i ^ 0x0F0F_0F0F))?;
6592    let ds = mk(experts * hidden * (ff / 16), &|i| {
6593        scale_byte(i ^ 0x1111_1111)
6594    })?;
6595    let gm = e.htod(&vec![1.0f32; experts])?;
6596    let um = e.htod(&vec![1.0f32; experts])?;
6597    let dm = e.htod(&vec![1.0f32; experts])?;
6598    let mixed_h: Vec<f32> = (0..t * hidden)
6599        .map(|i| ((i.wrapping_mul(40_503) % 1000) as f32) / 4000.0 - 0.125)
6600        .collect();
6601    let mixed = e.htod(&mixed_h)?;
6602
6603    // ONE routing shape for every arm: `slots` distinct experts spread across the bank by a
6604    // fixed stride. Distinct, because a shape change must not be read through a cache-hit
6605    // difference — the union axis is `moe_union_probe`'s and it is already priced dead.
6606    let slots = t * selected;
6607    let stride = (experts / slots.max(1)).max(1);
6608    let sel_h: Vec<i32> = (0..slots)
6609        .map(|i| ((i * stride) % experts) as i32)
6610        .collect();
6611    let tok_h: Vec<i32> = (0..slots).map(|i| (i / selected) as i32).collect();
6612    let sel = e.htod_i32(&sel_h)?;
6613    let tokm = e.htod_i32(&tok_h)?;
6614    let mut act = e.zeros(slots * ff)?;
6615    let mut partial = e.zeros(slots * hidden)?;
6616
6617    struct Arm {
6618        spec: String,
6619        gu_shape: String,
6620        dn_shape: String,
6621        gu_grid_x: usize,
6622        dn_grid_x: usize,
6623        gu: Vec<f64>,
6624        dn: Vec<f64>,
6625    }
6626    let describe = |code: u32, in_f: usize, out_f: usize| -> (String, usize) {
6627        match sel_group_resolve(code, in_f, out_f) {
6628            Some((g, rows)) => {
6629                let rpw = (32 / g) * rows;
6630                (format!("g{g}r{rows}/rpw{rpw}"), out_f / rpw)
6631            }
6632            None => ("shipped".to_string(), out_f / 4),
6633        }
6634    };
6635    let mut built: Vec<Arm> = Vec::with_capacity(arms.len());
6636    for spec in arms {
6637        if !set_sel_group(spec) {
6638            return Err(format!("sel_shape_cost_probe: bad arm spec {spec:?}").into());
6639        }
6640        let (gu_shape, gu_grid_x) = describe(sel_group_gu(), hidden, ff);
6641        let (dn_shape, dn_grid_x) = describe(sel_group_dn(), ff, hidden);
6642        built.push(Arm {
6643            spec: spec.clone(),
6644            gu_shape,
6645            dn_shape,
6646            gu_grid_x,
6647            dn_grid_x,
6648            gu: Vec::with_capacity(reps),
6649            dn: Vec::with_capacity(reps),
6650        });
6651    }
6652    let tok_arg = if t > 1 { Some((&tokm, hidden)) } else { None };
6653    for rep in 0..(reps + 1) {
6654        for a in built.iter_mut() {
6655            // Arm identity is re-asserted every rep, not set once outside the loop: the
6656            // interleave is the whole point, and a seam left over from the previous arm
6657            // would silently measure it twice.
6658            set_sel_group(&a.spec);
6659            e.stream().synchronize()?;
6660            let t0 = std::time::Instant::now();
6661            launch_nvfp4_sel_gu_silu(
6662                e,
6663                (&gc, &gs, &gm),
6664                (&uc, &us, &um),
6665                Some(&sel),
6666                0,
6667                slots,
6668                &mixed,
6669                &mut act,
6670                hidden,
6671                ff,
6672                tok_arg,
6673            )?;
6674            e.stream().synchronize()?;
6675            let t1 = std::time::Instant::now();
6676            launch_nvfp4_sel_matvec(
6677                e,
6678                &dc,
6679                &ds,
6680                &dm,
6681                &sel,
6682                &act,
6683                &mut partial,
6684                slots,
6685                ff,
6686                hidden,
6687                ff,
6688            )?;
6689            e.stream().synchronize()?;
6690            let t2 = std::time::Instant::now();
6691            if rep > 0 {
6692                a.gu.push(t1.duration_since(t0).as_secs_f64() * 1e6);
6693                a.dn.push(t2.duration_since(t1).as_secs_f64() * 1e6);
6694            }
6695        }
6696    }
6697    let stat = |v: &[f64]| -> (f64, f64) {
6698        let mut s = v.to_vec();
6699        s.sort_by(|a, b| a.partial_cmp(b).unwrap());
6700        let med = s[s.len() / 2];
6701        let spread = if med > 0.0 {
6702            (s[s.len() - 1] - s[0]) / med
6703        } else {
6704            0.0
6705        };
6706        (med, spread)
6707    };
6708    Ok(built
6709        .iter()
6710        .map(|a| {
6711            let (gu_us, gu_spread_rel) = stat(&a.gu);
6712            let (down_us, down_spread_rel) = stat(&a.dn);
6713            SelShapeRow {
6714                t,
6715                slots,
6716                arm: a.spec.clone(),
6717                gu_shape: a.gu_shape.clone(),
6718                dn_shape: a.dn_shape.clone(),
6719                gu_grid_x: a.gu_grid_x,
6720                dn_grid_x: a.dn_grid_x,
6721                gu_us,
6722                down_us,
6723                gu_spread_rel,
6724                down_spread_rel,
6725            }
6726        })
6727        .collect())
6728}
6729
6730/// Sequential slot-combine over a WINDOW of a taller partial slab (mtp-spec verify):
6731/// rows [x_row0, x_row0+n_rows) x weights [w_off..] into y row `y_row` — the
6732/// axpy_rows_seq_f32 chain VERBATIM over that window (per-token combine order equals
6733/// the decode combine).
6734#[allow(clippy::too_many_arguments)]
6735fn launch_axpy_rows_seq_at(
6736    e: &Engine,
6737    x: &CudaSlice<f32>,
6738    x_row0: usize,
6739    w: &CudaSlice<f32>,
6740    w_off: usize,
6741    y: &mut CudaSlice<f32>,
6742    y_row: usize,
6743    width: usize,
6744    n_rows: usize,
6745) -> Res<()> {
6746    if x.len() < (x_row0 + n_rows) * width
6747        || w.len() < w_off + n_rows
6748        || y.len() < (y_row + 1) * width
6749    {
6750        return Err("axpy_rows_seq_f32: window out of range".into());
6751    }
6752    let xv = x.slice(x_row0 * width..(x_row0 + n_rows) * width);
6753    let wv = w.slice(w_off..w_off + n_rows);
6754    let mut yv = y.slice_mut(y_row * width..(y_row + 1) * width);
6755    let f = e.func("axpy_rows_seq_f32");
6756    let cfg = LaunchConfig::for_num_elems(width as u32);
6757    let (wi, nr) = (width as i32, n_rows as i32);
6758    let stream = e.gpu.stream();
6759    let mut b = stream.launch_builder(&f);
6760    b.arg(&xv).arg(&wv).arg(&mut yv).arg(&wi).arg(&nr);
6761    unsafe {
6762        b.launch(cfg)?;
6763    }
6764    Ok(())
6765}
6766
6767/// Kernel-vs-host oracle for the grouped decode kernel (`qmatvec_nvfp4_modelopt_sel_f32`).
6768/// The tiny four-arm gate cannot reach that kernel (the tiny down projection is BF16 by
6769/// geometry, so the grouped path never engages there); this synthetic arm gates the
6770/// kernel directly against the host decoder chain (`dsv4::dequant_nvfp4_expert` + host
6771/// f32 matvec): deterministic codes/scales including planted NaN scale bytes (modelopt
6772/// NaN -> 0.0) , mixed pow2/non-pow2 macros (the real mint's class), duplicate slots in
6773/// `sel`, and BOTH x_stride modes (shared gate/up row, per-slot down rows). Products are
6774/// exact; only summation order differs from the host chain — tolerance 1e-5 rel.
6775pub fn gate_nvfp4_sel_matvec(e: &Engine) -> Res<String> {
6776    let mut lcg = 0x2545_f491_u64;
6777    let mut next_u32 = move || -> u32 {
6778        lcg = lcg
6779            .wrapping_mul(6364136223846793005)
6780            .wrapping_add(1442695040888963407);
6781        (lcg >> 33) as u32
6782    };
6783    let macros = [
6784        1.0f32,
6785        0.5,
6786        5.9945243e-5, // the measured non-pow2 mint class
6787        2.0,
6788        0.25,
6789        3.7e-3,
6790        1.0,
6791        8.0,
6792    ];
6793    let sel_host: Vec<i32> = vec![3, 5, 3, 0]; // duplicate slot on purpose
6794    let n_sel = sel_host.len();
6795    let mut worst = (0.0f32, 0.0f32); // (max_abs, max_rel)
6796    // Shapes + per-mode seam forcing pick the dispatched kernel: v3 modes force the
6797    // 4-row kernel (its guard is out_f % 4 == 0, which the v2 shapes also satisfy, so
6798    // the seam is toggled per mode and restored to the shipped default after); v2
6799    // shapes take the 2-row kernel with v3 off; in_f 48 and the odd out_f take the v1
6800    // fallback — all three kernels and every geometry guard are gated in one pass.
6801    for (mode, out_f, in_f) in [
6802        ("gate_up_v1", 16usize, 48usize),
6803        ("down_v1", 32, 16),
6804        ("gate_up_v1_oddrows", 7, 64),
6805        ("gate_up_v2", 16, 64),
6806        ("down_v2", 32, 32),
6807        ("gate_up_v3", 16, 64),
6808        ("down_v3", 32, 32),
6809        ("gate_up_v3_v2rows", 6, 64), // out_f % 4 != 0 falls v3 -> v2 under the v3 seam
6810    ] {
6811        set_sel_v3(mode.contains("v3"));
6812        let n_expert = macros.len();
6813        let mut codes = vec![0u8; n_expert * out_f * in_f / 2];
6814        for byte in &mut codes {
6815            *byte = next_u32() as u8;
6816        }
6817        let mut scales = vec![0u8; n_expert * out_f * in_f / 16];
6818        for byte in &mut scales {
6819            *byte = (next_u32() as u8) & 0xBF; // mag < 0x40 keeps magnitudes tame
6820        }
6821        scales[0] = 0x7F; // NaN code -> 0.0 (modelopt convention), pinned here
6822        scales[3] = 0xFF; // signed NaN code -> 0.0 too
6823        let x_stride = if mode.starts_with("down") { in_f } else { 0 };
6824        let x_rows = if x_stride == 0 { 1 } else { n_sel };
6825        let x_host: Vec<f32> = (0..x_rows * in_f)
6826            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
6827            .collect();
6828        let codes_dev = e.htod_bytes(&codes)?;
6829        let scales_dev = e.htod_bytes(&scales)?;
6830        let macros_dev = e.htod(&macros)?;
6831        let sel_dev = e.htod_i32(&sel_host)?;
6832        let x_dev = e.htod(&x_host)?;
6833        let mut y_dev = e.uninit(n_sel * out_f)?;
6834        launch_nvfp4_sel_matvec(
6835            e,
6836            &codes_dev,
6837            &scales_dev,
6838            &macros_dev,
6839            &sel_dev,
6840            &x_dev,
6841            &mut y_dev,
6842            n_sel,
6843            in_f,
6844            out_f,
6845            x_stride,
6846        )?;
6847        let y = e.dtoh(&y_dev)?;
6848        let wbytes = out_f * in_f / 2;
6849        let sbytes = out_f * in_f / 16;
6850        for (slot, &expert) in sel_host.iter().enumerate() {
6851            let expert = expert as usize;
6852            let w = memra_gguf::dsv4::dequant_nvfp4_expert(
6853                &codes[expert * wbytes..(expert + 1) * wbytes],
6854                &scales[expert * sbytes..(expert + 1) * sbytes],
6855                macros[expert],
6856                out_f,
6857                in_f,
6858            );
6859            let xrow = &x_host[slot * x_stride..slot * x_stride + in_f];
6860            for o in 0..out_f {
6861                let mut want = 0.0f32;
6862                for i in 0..in_f {
6863                    want += w[o * in_f + i] * xrow[i];
6864                }
6865                let got = y[slot * out_f + o];
6866                let abs = (want - got).abs();
6867                let rel = abs / want.abs().max(1.0);
6868                if abs > worst.0 {
6869                    worst.0 = abs;
6870                }
6871                if rel > worst.1 {
6872                    worst.1 = rel;
6873                }
6874                if rel > 1e-5 {
6875                    return Err(format!(
6876                        "nvfp4-sel-matvec oracle: {mode} slot {slot} row {o}: want {want} \
6877                         got {got} (rel {rel:.3e})"
6878                    )
6879                    .into());
6880                }
6881            }
6882        }
6883    }
6884    set_sel_v3(SEL_V3_DEFAULT);
6885
6886    // gufuse mode: the fused gate+up+silu kernel must be BIT-IDENTICAL to the
6887    // v3 gate launch + v3 up launch + silu_mul chain (same per-row arithmetic, same
6888    // epilogue element form — kernel doc). Byte-compare, plus the count-gated pack
6889    // twin's dead-slot sentinel.
6890    {
6891        set_sel_v3(true);
6892        let (ff, in_f) = (16usize, 64usize);
6893        let n_expert = macros.len();
6894        let mut mk = |seed: u8| -> (Vec<u8>, Vec<u8>) {
6895            let mut codes = vec![0u8; n_expert * ff * in_f / 2];
6896            for byte in &mut codes {
6897                *byte = (next_u32() as u8) ^ seed;
6898            }
6899            let mut scales = vec![0u8; n_expert * ff * in_f / 16];
6900            for byte in &mut scales {
6901                *byte = (next_u32() as u8) & 0xBF;
6902            }
6903            scales[1] = 0x7F; // NaN scale byte -> 0.0
6904            (codes, scales)
6905        };
6906        let (g_codes, g_scales) = mk(0x00);
6907        let (u_codes, u_scales) = mk(0x5A);
6908        let gmac: Vec<f32> = macros.to_vec();
6909        let umac: Vec<f32> = macros.iter().map(|m| m * 0.5).collect();
6910        let x_host: Vec<f32> = (0..in_f)
6911            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
6912            .collect();
6913        let gc = e.htod_bytes(&g_codes)?;
6914        let gs = e.htod_bytes(&g_scales)?;
6915        let gm = e.htod(&gmac)?;
6916        let uc = e.htod_bytes(&u_codes)?;
6917        let us = e.htod_bytes(&u_scales)?;
6918        let um = e.htod(&umac)?;
6919        let sel_dev = e.htod_i32(&sel_host)?;
6920        let x_dev = e.htod(&x_host)?;
6921        // Chain arm: v3 gate + v3 up + silu_mul.
6922        let mut yg = e.uninit(n_sel * ff)?;
6923        let mut yu = e.uninit(n_sel * ff)?;
6924        launch_nvfp4_sel_matvec(
6925            e, &gc, &gs, &gm, &sel_dev, &x_dev, &mut yg, n_sel, in_f, ff, 0,
6926        )?;
6927        launch_nvfp4_sel_matvec(
6928            e, &uc, &us, &um, &sel_dev, &x_dev, &mut yu, n_sel, in_f, ff, 0,
6929        )?;
6930        let mut act_chain = e.zeros(n_sel * ff)?;
6931        e.silu_mul(&yg, &yu, &mut act_chain, n_sel * ff)?;
6932        // Fused arm.
6933        let mut act_fused = e.zeros(n_sel * ff)?;
6934        launch_nvfp4_sel_gu_silu(
6935            e,
6936            (&gc, &gs, &gm),
6937            (&uc, &us, &um),
6938            Some(&sel_dev),
6939            0,
6940            n_sel,
6941            &x_dev,
6942            &mut act_fused,
6943            in_f,
6944            ff,
6945            None,
6946        )?;
6947        let a = e.dtoh(&act_chain)?;
6948        let b = e.dtoh(&act_fused)?;
6949        for (i, (&x1, &x2)) in a.iter().zip(&b).enumerate() {
6950            if x1.to_bits() != x2.to_bits() {
6951                return Err(format!(
6952                    "nvfp4-sel-matvec oracle: gufuse idx {i} not bit-identical \
6953                     (chain {x1} fused {x2})"
6954                )
6955                .into());
6956            }
6957        }
6958        // Pack twin: live count 2 of 4 — live slots bit-match, dead slots keep the
6959        // sentinel.
6960        let pack_bytes = tp2_pack_bytes(&sel_host[..2], &[0.5, 0.25], n_sel);
6961        let pack = e.htod_bytes(&pack_bytes)?;
6962        let pack_raw = {
6963            let stream = e.gpu.stream();
6964            pack.device_ptr(&stream).0
6965        };
6966        let sentinel = vec![-777.0f32; n_sel * ff];
6967        let mut act_pack = e.htod(&sentinel)?;
6968        launch_nvfp4_sel_gu_silu(
6969            e,
6970            (&gc, &gs, &gm),
6971            (&uc, &us, &um),
6972            None,
6973            pack_raw,
6974            n_sel,
6975            &x_dev,
6976            &mut act_pack,
6977            in_f,
6978            ff,
6979            None,
6980        )?;
6981        let c = e.dtoh(&act_pack)?;
6982        for slot in 0..n_sel {
6983            for o in 0..ff {
6984                let got = c[slot * ff + o];
6985                if slot < 2 {
6986                    if got.to_bits() != a[slot * ff + o].to_bits() {
6987                        return Err(format!(
6988                            "nvfp4-sel-matvec oracle: gufuse pack slot {slot} o {o} \
6989                             not bit-identical"
6990                        )
6991                        .into());
6992                    }
6993                } else if got != -777.0 {
6994                    return Err(format!(
6995                        "nvfp4-sel-matvec oracle: gufuse pack dead slot {slot} written"
6996                    )
6997                    .into());
6998                }
6999            }
7000        }
7001        // tok_map twin (mtp-spec verify merge): TWO tokens' slots in ONE launch via the
7002        // slot->token map must bit-match per-token launches over each token's x row.
7003        {
7004            let t2 = 2usize;
7005            let x2_host: Vec<f32> = (0..t2 * in_f)
7006                .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7007                .collect();
7008            let x2 = e.htod(&x2_host)?;
7009            let tok_host: Vec<i32> = (0..n_sel).map(|s| (s % t2) as i32).collect();
7010            let tokm = e.htod_i32(&tok_host)?;
7011            let mut act_map = e.zeros(n_sel * ff)?;
7012            launch_nvfp4_sel_gu_silu(
7013                e,
7014                (&gc, &gs, &gm),
7015                (&uc, &us, &um),
7016                Some(&sel_dev),
7017                0,
7018                n_sel,
7019                &x2,
7020                &mut act_map,
7021                in_f,
7022                ff,
7023                Some((&tokm, in_f)),
7024            )?;
7025            let got = e.dtoh(&act_map)?;
7026            for tok in 0..t2 {
7027                let slots: Vec<usize> = (0..n_sel).filter(|s| s % t2 == tok).collect();
7028                let sel_tok: Vec<i32> = slots.iter().map(|&s| sel_host[s]).collect();
7029                let sel_tok_dev = e.htod_i32(&sel_tok)?;
7030                let xrow = e.htod(&x2_host[tok * in_f..(tok + 1) * in_f])?;
7031                let mut act_tok = e.zeros(sel_tok.len() * ff)?;
7032                launch_nvfp4_sel_gu_silu(
7033                    e,
7034                    (&gc, &gs, &gm),
7035                    (&uc, &us, &um),
7036                    Some(&sel_tok_dev),
7037                    0,
7038                    sel_tok.len(),
7039                    &xrow,
7040                    &mut act_tok,
7041                    in_f,
7042                    ff,
7043                    None,
7044                )?;
7045                let want = e.dtoh(&act_tok)?;
7046                for (local, &slot) in slots.iter().enumerate() {
7047                    for o in 0..ff {
7048                        let a = got[slot * ff + o];
7049                        let b = want[local * ff + o];
7050                        if a.to_bits() != b.to_bits() {
7051                            return Err(format!(
7052                                "nvfp4-sel-matvec oracle: gufuse tok_map slot {slot} o {o} \
7053                                 not bit-identical (map {a} per-token {b})"
7054                            )
7055                            .into());
7056                        }
7057                    }
7058                }
7059            }
7060        }
7061        set_sel_v3(SEL_V3_DEFAULT);
7062    }
7063    Ok(format!(
7064        "nvfp4-sel-matvec kernel oracle: worst abs {:.3e} rel {:.3e} over gate_up+down \
7065         v1/v2/v3 modes, NaN scales + non-pow2 macros + duplicate slots; gufuse \
7066         BIT-IDENTICAL to the v3+silu chain incl. the count-gated pack twin + the \
7067         tok_map verify merge",
7068        worst.0, worst.1
7069    ))
7070}
7071
7072/// Kernel oracle for the SUB-WARP pair-group sel matvecs (`selgroup`, downsel lane mtp14),
7073/// at the artifact's REAL MoE geometry — which is the whole point of the arm: the defect
7074/// being fixed is a property of `pairs = in_f/32` against a 32-lane loop, so it only exists
7075/// at `in_f = 640` (pairs 20, lanes 20-31 idle) and `in_f = 2560` (pairs 80, 3-vs-2 tail).
7076/// A tiny fixture has `pairs` 1 or 2 and cannot reach either shape; both are gated here.
7077///
7078/// Three claims, in ascending strength:
7079///
7080/// 1. **`(g=32, rows=4)` is BIT-IDENTICAL to the shipped v3 / gufuse kernels.** The
7081///    sub-warp form degenerates to their exact program at that shape (same per-lane pair
7082///    set, same 5-step tree, same write lane), so this is a byte compare, not a tolerance.
7083///    It is what makes the seam a rollback rather than a rewrite, and it is the arm that
7084///    would catch a per-row expression drift introduced while restructuring.
7085/// 2. **Every other shape is within the sel oracle's accumulation-class tolerance
7086///    (1e-5 rel) of the HOST DECODER CHAIN** (`dsv4::dequant_nvfp4_expert` + host f32
7087///    matvec), the same reference and the same bound `gate_nvfp4_sel_matvec` holds v1/v2/v3
7088///    to. Those shapes DO change the order the pairs are summed in — a lane chains several
7089///    pairs and the tree is shallower — so bit-identity is not the right claim and asserting
7090///    it would be a lie that happened to pass at some shapes.
7091/// 3. **The fusion property survives the reshape:** `gu_g` is bit-identical to
7092///    `sel_g` gate + `sel_g` up + `silu_mul` at the SAME `(g, rows)`, with the count-gated
7093///    pack twin and the slot->token verify merge included.
7094///
7095/// Same hostile inputs as the shipped arm: planted modelopt NaN scale bytes (0x7F/0xFF ->
7096/// 0.0), mixed pow2 / non-pow2 (the real mint's amax class) macros, a DUPLICATE expert in
7097/// `sel`, and both `x_stride` modes (shared gate/up row, per-slot down rows).
7098pub fn gate_nvfp4_sel_group(e: &Engine) -> Res<String> {
7099    let saved = sel_group_spec();
7100    let out = gate_nvfp4_sel_group_inner(e);
7101    // Restore on BOTH paths: a gate arm that leaks a seam leaves every later arm measuring
7102    // a shape nobody asked for (the seam_state save/restore lesson).
7103    set_sel_group(&saved);
7104    set_sel_v3(SEL_V3_DEFAULT);
7105    out
7106}
7107
7108fn gate_nvfp4_sel_group_inner(e: &Engine) -> Res<String> {
7109    let mut lcg = 0x2545_f491_u64; // the shipped sel arm's seed, deliberately
7110    let mut next_u32 = move || -> u32 {
7111        lcg = lcg
7112            .wrapping_mul(6364136223846793005)
7113            .wrapping_add(1442695040888963407);
7114        (lcg >> 33) as u32
7115    };
7116    let macros = [
7117        1.0f32,
7118        0.5,
7119        5.9945243e-5, // the measured non-pow2 mint class
7120        2.0,
7121        0.25,
7122        3.7e-3,
7123        1.0,
7124        8.0,
7125    ];
7126    let n_expert = macros.len();
7127    let sel_host: Vec<i32> = vec![3, 5, 3, 0]; // duplicate slot on purpose
7128    let n_sel = sel_host.len();
7129    let mut worst = (0.0f32, 0.0f32);
7130    let mut shapes_checked = 0usize;
7131    let mut bits_checked = 0usize;
7132    let mut calib: Vec<String> = Vec::new();
7133
7134    // ---- single-bank family (down projection AND the unfused gate/up shape) -------------
7135    // (label, out_f, in_f, per-slot x rows). The two REAL rows are the launches the verify
7136    // chunk actually dispatches: down out_f=hidden 2560 / in_f=ff 640, and the gate/up
7137    // shape out_f=ff 640 / in_f=hidden 2560 (SEMANTICS.md "MoE (L510-527)": experts fused
7138    // gate_up [512,1280,2560], down [512,2560,640]).
7139    for (geom, out_f, in_f, per_slot_x) in [
7140        ("down_real", 2560usize, 640usize, true),
7141        ("gateup_real", 640, 2560, false),
7142        ("down_tiny", 32, 32, true),
7143        ("gateup_tiny", 16, 64, false),
7144    ] {
7145        let mut codes = vec![0u8; n_expert * out_f * in_f / 2];
7146        for byte in &mut codes {
7147            *byte = next_u32() as u8;
7148        }
7149        let mut scales = vec![0u8; n_expert * out_f * in_f / 16];
7150        for byte in &mut scales {
7151            *byte = (next_u32() as u8) & 0xBF; // mag < 0x40 keeps magnitudes tame
7152        }
7153        scales[0] = 0x7F; // modelopt NaN code -> 0.0
7154        scales[3] = 0xFF; // signed NaN code -> 0.0 too
7155        let x_stride = if per_slot_x { in_f } else { 0 };
7156        let x_rows = if per_slot_x { n_sel } else { 1 };
7157        let x_host: Vec<f32> = (0..x_rows * in_f)
7158            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7159            .collect();
7160        let codes_dev = e.htod_bytes(&codes)?;
7161        let scales_dev = e.htod_bytes(&scales)?;
7162        let macros_dev = e.htod(&macros)?;
7163        let sel_dev = e.htod_i32(&sel_host)?;
7164        let x_dev = e.htod(&x_host)?;
7165        let run = |spec: &str| -> Res<Vec<f32>> {
7166            set_sel_group(spec);
7167            let mut y = e.uninit(n_sel * out_f)?;
7168            launch_nvfp4_sel_matvec(
7169                e,
7170                &codes_dev,
7171                &scales_dev,
7172                &macros_dev,
7173                &sel_dev,
7174                &x_dev,
7175                &mut y,
7176                n_sel,
7177                in_f,
7178                out_f,
7179                x_stride,
7180            )?;
7181            e.dtoh(&y)
7182        };
7183        // The shipped arm (seam OFF) and the host reference, built once per geometry. The
7184        // shipped arm is not just a bit-identity control: its OWN deviation from the host
7185        // chain is this geometry's calibration (see `class_tol` below). PIN sel_v3 rather
7186        // than inheriting ambient seam state (revuto, PR #27): under `selv3=0` in
7187        // MEMRA_Q4E_SEAMS the "shipped" control would silently become the v2 kernel and
7188        // the calibration would be measured against the wrong program — mirror the fused
7189        // family, which pins its control the same way.
7190        set_sel_v3(true);
7191        let shipped = run("off")?;
7192        let wbytes = out_f * in_f / 2;
7193        let sbytes = out_f * in_f / 16;
7194        let mut want = vec![0.0f32; n_sel * out_f];
7195        for (slot, &expert) in sel_host.iter().enumerate() {
7196            let expert = expert as usize;
7197            let w = memra_gguf::dsv4::dequant_nvfp4_expert(
7198                &codes[expert * wbytes..(expert + 1) * wbytes],
7199                &scales[expert * sbytes..(expert + 1) * sbytes],
7200                macros[expert],
7201                out_f,
7202                in_f,
7203            );
7204            let xrow = &x_host[slot * x_stride..slot * x_stride + in_f];
7205            for o in 0..out_f {
7206                let mut acc = 0.0f32;
7207                for i in 0..in_f {
7208                    acc += w[o * in_f + i] * xrow[i];
7209                }
7210                want[slot * out_f + o] = acc;
7211            }
7212        }
7213        // The SHIPPED kernel's own worst deviation from the host chain, at THIS width. This
7214        // is the arm's calibration, and measuring it is load-bearing rather than tidy:
7215        // `gate_nvfp4_sel_matvec`'s 1e-5 rel bound was set on TINY shapes (in_f 16-64) and
7216        // does NOT transfer to the real MoE widths — a length-`in_f` f32 reduction has an
7217        // order-dependent error that grows with the sum, and at in_f=640 the SHIPPED v3
7218        // kernel already measures ~2.7e-5 against the exact host chain. Holding a reshaped
7219        // twin to 1e-5 there would fail it for being a different (equally valid) summation
7220        // order of a sum the shipped kernel cannot hold to 1e-5 either.
7221        let ship_vs_host = want
7222            .iter()
7223            .zip(&shipped)
7224            .map(|(&w, &s)| (w - s).abs() / w.abs().max(1.0))
7225            .fold(0.0f32, f32::max);
7226        // Same-accumulation-class bound: no worse than 4x what the kernel we ship already
7227        // deviates by, with a floor so the tiny geometries (where the shipped kernel can be
7228        // near-exact) do not set an unreachable bar.
7229        let class_tol = (4.0 * ship_vs_host).max(1e-5);
7230        calib.push(format!(
7231            "{geom} ship_vs_host={ship_vs_host:.3e} tol={class_tol:.3e}"
7232        ));
7233        // Every shape the ladder can pin at this geometry, plus AUTO and the control.
7234        // `dn:1:1` is the extreme: one output row per LANE, no shfl reduce at all — kept in
7235        // the oracle because it is the arm most likely to expose an indexing error, even
7236        // though its coalescing makes it a poor perf candidate.
7237        for spec in [
7238            "dn:32:4", "dn:auto", "dn:16:4", "dn:16:2", "dn:8:4", "dn:8:2", "dn:8:1", "dn:4:4",
7239            "dn:4:2", "dn:4:1", "dn:2:4", "dn:2:2", "dn:2:1", "dn:1:1",
7240        ] {
7241            let Some((g, rows)) = sel_group_resolve(
7242                match spec {
7243                    "dn:auto" => SEL_GROUP_AUTO,
7244                    _ => {
7245                        let (gs, rs) = spec.trim_start_matches("dn:").split_once(':').unwrap();
7246                        (gs.parse::<u32>().unwrap() << 8) | rs.parse::<u32>().unwrap()
7247                    }
7248                },
7249                in_f,
7250                out_f,
7251            ) else {
7252                continue; // geometry cannot tile this shape — the launcher takes v3
7253            };
7254            let got = run(spec)?;
7255            shapes_checked += 1;
7256            if (g, rows) == (32, 4) {
7257                // Claim 1: the degenerate shape IS v3.
7258                for (i, (&a, &b)) in shipped.iter().zip(&got).enumerate() {
7259                    if a.to_bits() != b.to_bits() {
7260                        return Err(format!(
7261                            "sel-group oracle: {geom} g=32 rows=4 idx {i} NOT bit-identical to \
7262                             the shipped v3 kernel (v3 {a} group {b}) — the sub-warp form must \
7263                             degenerate to v3 exactly"
7264                        )
7265                        .into());
7266                    }
7267                }
7268                bits_checked += shipped.len();
7269            }
7270            // Claim 2: same accumulation class as the kernel we ship. Checked BOTH ways —
7271            // against the exact host chain, and against the shipped kernel's own output.
7272            // The second is the one that would catch a reshape that drifted while staying
7273            // coincidentally close to the reference.
7274            for (i, (&w, &got)) in want.iter().zip(&got).enumerate() {
7275                let abs = (w - got).abs();
7276                let rel = abs / w.abs().max(1.0);
7277                worst.0 = worst.0.max(abs);
7278                worst.1 = worst.1.max(rel);
7279                if rel > class_tol {
7280                    return Err(format!(
7281                        "sel-group oracle: {geom} {spec} (g={g} rows={rows}) idx {i} vs HOST \
7282                         chain: want {w} got {got} (rel {rel:.3e} > tol {class_tol:.3e}, \
7283                         shipped v3 itself is {ship_vs_host:.3e})"
7284                    )
7285                    .into());
7286                }
7287            }
7288            for (i, (&s, &got)) in shipped.iter().zip(&got).enumerate() {
7289                let rel = (s - got).abs() / s.abs().max(1.0);
7290                if rel > class_tol {
7291                    return Err(format!(
7292                        "sel-group oracle: {geom} {spec} (g={g} rows={rows}) idx {i} vs SHIPPED \
7293                         v3: v3 {s} group {got} (rel {rel:.3e} > tol {class_tol:.3e})"
7294                    )
7295                    .into());
7296                }
7297            }
7298        }
7299        set_sel_group("off");
7300    }
7301
7302    // ---- fused gate+up+silu family -----------------------------------------------------
7303    // Claim 3: the fusion survives the reshape. The chain arm runs the SAME (g, rows) on
7304    // the single-bank kernel, so a mismatch is the fusion breaking, not the shape.
7305    for (geom, ff, in_f) in [("gu_real", 640usize, 2560usize), ("gu_tiny", 16, 64)] {
7306        let mut mk = |seed: u8| -> (Vec<u8>, Vec<u8>) {
7307            let mut codes = vec![0u8; n_expert * ff * in_f / 2];
7308            for byte in &mut codes {
7309                *byte = (next_u32() as u8) ^ seed;
7310            }
7311            let mut scales = vec![0u8; n_expert * ff * in_f / 16];
7312            for byte in &mut scales {
7313                *byte = (next_u32() as u8) & 0xBF;
7314            }
7315            scales[1] = 0x7F; // NaN scale byte -> 0.0
7316            (codes, scales)
7317        };
7318        let (g_codes, g_scales) = mk(0x00);
7319        let (u_codes, u_scales) = mk(0x5A);
7320        let gmac: Vec<f32> = macros.to_vec();
7321        let umac: Vec<f32> = macros.iter().map(|m| m * 0.5).collect();
7322        let x_host: Vec<f32> = (0..in_f)
7323            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7324            .collect();
7325        let gc = e.htod_bytes(&g_codes)?;
7326        let gs = e.htod_bytes(&g_scales)?;
7327        let gm = e.htod(&gmac)?;
7328        let uc = e.htod_bytes(&u_codes)?;
7329        let us = e.htod_bytes(&u_scales)?;
7330        let um = e.htod(&umac)?;
7331        let sel_dev = e.htod_i32(&sel_host)?;
7332        let x_dev = e.htod(&x_host)?;
7333        set_sel_group("off");
7334        set_sel_v3(true);
7335        let shipped_fused = {
7336            let mut act = e.zeros(n_sel * ff)?;
7337            launch_nvfp4_sel_gu_silu(
7338                e,
7339                (&gc, &gs, &gm),
7340                (&uc, &us, &um),
7341                Some(&sel_dev),
7342                0,
7343                n_sel,
7344                &x_dev,
7345                &mut act,
7346                in_f,
7347                ff,
7348                None,
7349            )?;
7350            e.dtoh(&act)?
7351        };
7352        for spec in ["32:4", "auto", "16:4", "16:2", "8:4", "8:1", "4:4"] {
7353            let Some((g, rows)) = sel_group_resolve(
7354                match spec {
7355                    "auto" => SEL_GROUP_AUTO,
7356                    _ => {
7357                        let (gs, rs) = spec.split_once(':').unwrap();
7358                        (gs.parse::<u32>().unwrap() << 8) | rs.parse::<u32>().unwrap()
7359                    }
7360                },
7361                in_f,
7362                ff,
7363            ) else {
7364                continue;
7365            };
7366            // Chain arm at the same shape: sel_g(gate) + sel_g(up) + silu_mul.
7367            set_sel_group(&format!("dn:{spec}+gu:off"));
7368            let mut yg = e.uninit(n_sel * ff)?;
7369            let mut yu = e.uninit(n_sel * ff)?;
7370            launch_nvfp4_sel_matvec(
7371                e, &gc, &gs, &gm, &sel_dev, &x_dev, &mut yg, n_sel, in_f, ff, 0,
7372            )?;
7373            launch_nvfp4_sel_matvec(
7374                e, &uc, &us, &um, &sel_dev, &x_dev, &mut yu, n_sel, in_f, ff, 0,
7375            )?;
7376            let mut act_chain = e.zeros(n_sel * ff)?;
7377            e.silu_mul(&yg, &yu, &mut act_chain, n_sel * ff)?;
7378            let chain = e.dtoh(&act_chain)?;
7379            // Fused arm at the same shape.
7380            set_sel_group(&format!("dn:off+gu:{spec}"));
7381            let mut act_fused = e.zeros(n_sel * ff)?;
7382            launch_nvfp4_sel_gu_silu(
7383                e,
7384                (&gc, &gs, &gm),
7385                (&uc, &us, &um),
7386                Some(&sel_dev),
7387                0,
7388                n_sel,
7389                &x_dev,
7390                &mut act_fused,
7391                in_f,
7392                ff,
7393                None,
7394            )?;
7395            let fused = e.dtoh(&act_fused)?;
7396            for (i, (&a, &b)) in chain.iter().zip(&fused).enumerate() {
7397                if a.to_bits() != b.to_bits() {
7398                    return Err(format!(
7399                        "sel-group oracle: {geom} gu {spec} (g={g} rows={rows}) idx {i} fused \
7400                         NOT bit-identical to the same-shape chain (chain {a} fused {b})"
7401                    )
7402                    .into());
7403                }
7404            }
7405            bits_checked += chain.len();
7406            shapes_checked += 1;
7407            if (g, rows) == (32, 4) {
7408                for (i, (&a, &b)) in shipped_fused.iter().zip(&fused).enumerate() {
7409                    if a.to_bits() != b.to_bits() {
7410                        return Err(format!(
7411                            "sel-group oracle: {geom} gu g=32 rows=4 idx {i} NOT bit-identical \
7412                             to the shipped gufuse kernel (gufuse {a} group {b})"
7413                        )
7414                        .into());
7415                    }
7416                }
7417                bits_checked += shipped_fused.len();
7418            }
7419        }
7420        // Count-gated pack twin and the slot->token verify merge, under AUTO — the two
7421        // addressing modes the serving path uses that the plain arm above does not reach.
7422        set_sel_group("dn:off+gu:auto");
7423        if sel_group_resolve(SEL_GROUP_AUTO, in_f, ff).is_some() {
7424            let auto_plain = {
7425                let mut act = e.zeros(n_sel * ff)?;
7426                launch_nvfp4_sel_gu_silu(
7427                    e,
7428                    (&gc, &gs, &gm),
7429                    (&uc, &us, &um),
7430                    Some(&sel_dev),
7431                    0,
7432                    n_sel,
7433                    &x_dev,
7434                    &mut act,
7435                    in_f,
7436                    ff,
7437                    None,
7438                )?;
7439                e.dtoh(&act)?
7440            };
7441            let pack_bytes = tp2_pack_bytes(&sel_host[..2], &[0.5, 0.25], n_sel);
7442            let pack = e.htod_bytes(&pack_bytes)?;
7443            let pack_raw = {
7444                let stream = e.gpu.stream();
7445                pack.device_ptr(&stream).0
7446            };
7447            let sentinel = vec![-777.0f32; n_sel * ff];
7448            let mut act_pack = e.htod(&sentinel)?;
7449            launch_nvfp4_sel_gu_silu(
7450                e,
7451                (&gc, &gs, &gm),
7452                (&uc, &us, &um),
7453                None,
7454                pack_raw,
7455                n_sel,
7456                &x_dev,
7457                &mut act_pack,
7458                in_f,
7459                ff,
7460                None,
7461            )?;
7462            let packed = e.dtoh(&act_pack)?;
7463            for slot in 0..n_sel {
7464                for o in 0..ff {
7465                    let got = packed[slot * ff + o];
7466                    if slot < 2 {
7467                        if got.to_bits() != auto_plain[slot * ff + o].to_bits() {
7468                            return Err(format!(
7469                                "sel-group oracle: {geom} gu auto pack slot {slot} o {o} not \
7470                                 bit-identical to the sel-array arm"
7471                            )
7472                            .into());
7473                        }
7474                    } else if got != -777.0 {
7475                        return Err(format!(
7476                            "sel-group oracle: {geom} gu auto pack dead slot {slot} written"
7477                        )
7478                        .into());
7479                    }
7480                }
7481            }
7482            // tok_map: two tokens' slots in ONE launch must bit-match per-token launches.
7483            let t2 = 2usize;
7484            let x2_host: Vec<f32> = (0..t2 * in_f)
7485                .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7486                .collect();
7487            let x2 = e.htod(&x2_host)?;
7488            let tok_host: Vec<i32> = (0..n_sel).map(|s| (s % t2) as i32).collect();
7489            let tokm = e.htod_i32(&tok_host)?;
7490            let mut act_map = e.zeros(n_sel * ff)?;
7491            launch_nvfp4_sel_gu_silu(
7492                e,
7493                (&gc, &gs, &gm),
7494                (&uc, &us, &um),
7495                Some(&sel_dev),
7496                0,
7497                n_sel,
7498                &x2,
7499                &mut act_map,
7500                in_f,
7501                ff,
7502                Some((&tokm, in_f)),
7503            )?;
7504            let mapped = e.dtoh(&act_map)?;
7505            for tok in 0..t2 {
7506                let slots: Vec<usize> = (0..n_sel).filter(|s| s % t2 == tok).collect();
7507                let sel_tok: Vec<i32> = slots.iter().map(|&s| sel_host[s]).collect();
7508                let sel_tok_dev = e.htod_i32(&sel_tok)?;
7509                let xrow = e.htod(&x2_host[tok * in_f..(tok + 1) * in_f])?;
7510                let mut act_tok = e.zeros(sel_tok.len() * ff)?;
7511                launch_nvfp4_sel_gu_silu(
7512                    e,
7513                    (&gc, &gs, &gm),
7514                    (&uc, &us, &um),
7515                    Some(&sel_tok_dev),
7516                    0,
7517                    sel_tok.len(),
7518                    &xrow,
7519                    &mut act_tok,
7520                    in_f,
7521                    ff,
7522                    None,
7523                )?;
7524                let want = e.dtoh(&act_tok)?;
7525                for (local, &slot) in slots.iter().enumerate() {
7526                    for o in 0..ff {
7527                        let a = mapped[slot * ff + o];
7528                        let b = want[local * ff + o];
7529                        if a.to_bits() != b.to_bits() {
7530                            return Err(format!(
7531                                "sel-group oracle: {geom} gu auto tok_map slot {slot} o {o} not \
7532                                 bit-identical (map {a} per-token {b})"
7533                            )
7534                            .into());
7535                        }
7536                    }
7537                }
7538            }
7539            bits_checked += auto_plain.len() + mapped.len();
7540        }
7541        set_sel_group("off");
7542    }
7543
7544    Ok(format!(
7545        "nvfp4-sel-GROUP kernel oracle: {shapes_checked} (geometry, shape) cells over REAL \
7546         MoE geometry (down 2560x640 pairs=20, gate_up 640x2560 pairs=80) + tiny, worst abs \
7547         {:.3e} rel {:.3e} vs the host decoder chain; (g=32,rows=4) BIT-IDENTICAL to the \
7548         shipped v3 and gufuse kernels and every shape's fused arm BIT-IDENTICAL to its \
7549         same-shape chain ({bits_checked} f32 byte-compared), incl. the count-gated pack \
7550         twin + the tok_map verify merge; NaN scales + non-pow2 macros + duplicate slots; \
7551         per-geometry class calibration [{}]",
7552        worst.0,
7553        worst.1,
7554        calib.join("; ")
7555    ))
7556}
7557
7558/// REAL-GEOMETRY oracle for the round-4 hyper-gate diet (the tiny plan's rank 4 fails
7559/// the %8 geometry guard, so the tiny arms never reach these kernels): the THREE-launch
7560/// diet chain (stage 1/2/3) vs the classic fused chain (hc_norm_planes + batched bf16w
7561/// down + lowrank reduce + batched bf16w up + mix epilogue + two-stage inject) on
7562/// IDENTICAL bf16 weights at streams 4, hidden 2560, rank 320, t 1. Tolerance class
7563/// (new reduce widths; 1e-4 rel, worst reported) over low_act, the inject slab, and
7564/// mixed.
7565pub fn gate_hc_diet_kernels(e: &Engine) -> Res<String> {
7566    let (streams, hidden, rank, t) = (4usize, 2560usize, 320usize, 1usize);
7567    let wide = streams * hidden;
7568    let mut lcg = 0x8badf00d_u64;
7569    let mut next_f32 = move || -> f32 {
7570        lcg = lcg
7571            .wrapping_mul(6364136223846793005)
7572            .wrapping_add(1442695040888963407);
7573        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
7574    };
7575    let mut rand_vec = |n: usize| -> Vec<f32> { (0..n).map(|_| next_f32()).collect() };
7576    // bf16-representable weights (truncate the low mantissa bits) so bf16_twin builds.
7577    let to_b16_vals = |v: Vec<f32>| -> Vec<f32> {
7578        v.into_iter()
7579            .map(|x| f32::from_bits(x.to_bits() & 0xFFFF_0000))
7580            .collect()
7581    };
7582    let planes_host: Vec<Vec<f32>> = (0..streams).map(|_| rand_vec(t * hidden)).collect();
7583    let planes: Vec<CudaSlice<f32>> = planes_host
7584        .iter()
7585        .map(|v| e.htod(v))
7586        .collect::<Result<_, _>>()?;
7587    let ptr_vals: Vec<u64> = {
7588        let stream = e.gpu.stream();
7589        planes.iter().map(|p| p.device_ptr(&stream).0).collect()
7590    };
7591    let ptrs = e.htod_u64(&ptr_vals)?;
7592    let norm_stack_host = rand_vec(wide);
7593    let norm_stack = e.htod(&norm_stack_host)?;
7594    let down_host = to_b16_vals(rand_vec(streams * rank * hidden));
7595    let up_host = to_b16_vals(rand_vec(streams * hidden * rank));
7596    let inj_host = to_b16_vals(rand_vec(streams * wide));
7597    let down_b16 = bf16_twin(e, &down_host, hidden)?.ok_or("hc-diet oracle: down twin")?;
7598    let up_b16 = bf16_twin(e, &up_host, rank)?.ok_or("hc-diet oracle: up twin")?;
7599    let inj_b16 = bf16_twin(e, &inj_host, hidden)?.ok_or("hc-diet oracle: inject twin")?;
7600    let inj_f32 = e.htod(&inj_host)?;
7601    let eps = 1e-6f32;
7602
7603    // Classic fused chain (the current default path) on the same operands.
7604    let mut normed = e.zeros(streams * t * hidden)?;
7605    launch_hc_norm_planes(e, &ptrs, &norm_stack, &mut normed, hidden, t, streams, eps)?;
7606    let mut parts_c = e.zeros(streams * t * rank)?;
7607    launch_qmatvec_bf16w(
7608        e,
7609        &down_b16,
7610        &normed,
7611        &mut parts_c,
7612        hidden,
7613        rank,
7614        t,
7615        streams,
7616        rank * hidden,
7617        t * hidden,
7618        hidden,
7619        t * rank,
7620    )?;
7621    let mut low_c = e.zeros(t * rank)?;
7622    launch_hc_lowrank_reduce(e, &parts_c, &mut low_c, streams, t, rank)?;
7623    let mut gates_c = e.zeros(streams * t * hidden)?;
7624    launch_qmatvec_bf16w(
7625        e,
7626        &up_b16,
7627        &low_c,
7628        &mut gates_c,
7629        rank,
7630        hidden,
7631        t,
7632        streams,
7633        hidden * rank,
7634        0,
7635        rank,
7636        t * hidden,
7637    )?;
7638    let mut mixed_c = e.zeros(t * hidden)?;
7639    launch_hc_mix_epilogue(e, &gates_c, &normed, &mut mixed_c, streams, t, hidden)?;
7640    let mut partials_c = e.zeros(streams * t * 16)?;
7641    let mut all_c = e.zeros(streams * t)?;
7642    launch_hc_inject_two_stage(
7643        e,
7644        &normed,
7645        &inj_f32,
7646        Some(&inj_b16),
7647        &mut partials_c,
7648        &mut all_c,
7649        streams,
7650        t,
7651        hidden,
7652        16,
7653    )?;
7654
7655    // Diet chain.
7656    let mut parts_d = e.zeros(streams * rank)?;
7657    let mut injp_d = e.zeros(streams * streams)?;
7658    let mut inv_d = e.zeros(streams)?;
7659    launch_hc_diet_stage1(
7660        e,
7661        &ptrs,
7662        &norm_stack,
7663        &down_b16,
7664        Some(&inj_b16),
7665        &mut parts_d,
7666        &mut injp_d,
7667        &mut inv_d,
7668        hidden,
7669        rank,
7670        streams,
7671        1,
7672        eps,
7673    )?;
7674    let mut low_d = e.zeros(rank)?;
7675    let mut all_d = e.zeros(streams)?;
7676    launch_hc_diet_stage2(
7677        e, &parts_d, &injp_d, &mut low_d, &mut all_d, rank, streams, 1, true,
7678    )?;
7679    let mut mixed_d = e.zeros(hidden)?;
7680    launch_hc_diet_stage3(
7681        e,
7682        &ptrs,
7683        &norm_stack,
7684        &inv_d,
7685        &up_b16,
7686        &low_d,
7687        &mut mixed_d,
7688        hidden,
7689        rank,
7690        streams,
7691        1,
7692    )?;
7693
7694    let mut worst = 0.0f32;
7695    let check = |name: &str, a: &[f32], b: &[f32], worst: &mut f32| -> Res<()> {
7696        for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
7697            let rel = (x - y).abs() / y.abs().max(1.0);
7698            if rel > *worst {
7699                *worst = rel;
7700            }
7701            if rel > 1e-4 {
7702                return Err(format!(
7703                    "hc-diet oracle: {name} idx {i}: diet {x} classic {y} (rel {rel:.3e})"
7704                )
7705                .into());
7706            }
7707        }
7708        Ok(())
7709    };
7710    check("low_act", &e.dtoh(&low_d)?, &e.dtoh(&low_c)?, &mut worst)?;
7711    check("inject", &e.dtoh(&all_d)?, &e.dtoh(&all_c)?, &mut worst)?;
7712    check("mixed", &e.dtoh(&mixed_d)?, &e.dtoh(&mixed_c)?, &mut worst)?;
7713
7714    // Token-dim extension (mtp-spec verify chunks): the SAME kernels at t = 3 must
7715    // produce per-token rows BIT-IDENTICAL to three t = 1 launches at plane offsets —
7716    // the spec byte-identity contract for the read gates.
7717    {
7718        let t3 = 3usize;
7719        let planes3_host: Vec<Vec<f32>> = (0..streams).map(|_| rand_vec(t3 * hidden)).collect();
7720        let planes3: Vec<CudaSlice<f32>> = planes3_host
7721            .iter()
7722            .map(|v| e.htod(v))
7723            .collect::<Result<_, _>>()?;
7724        let ptr_vals3: Vec<u64> = {
7725            let stream = e.gpu.stream();
7726            planes3.iter().map(|p| p.device_ptr(&stream).0).collect()
7727        };
7728        let ptrs3 = e.htod_u64(&ptr_vals3)?;
7729        let mut parts3 = e.zeros(t3 * streams * rank)?;
7730        let mut injp3 = e.zeros(t3 * streams * streams)?;
7731        let mut inv3 = e.zeros(t3 * streams)?;
7732        launch_hc_diet_stage1(
7733            e,
7734            &ptrs3,
7735            &norm_stack,
7736            &down_b16,
7737            Some(&inj_b16),
7738            &mut parts3,
7739            &mut injp3,
7740            &mut inv3,
7741            hidden,
7742            rank,
7743            streams,
7744            t3,
7745            eps,
7746        )?;
7747        let mut low3 = e.zeros(t3 * rank)?;
7748        let mut all3 = e.zeros(streams * t3)?;
7749        launch_hc_diet_stage2(
7750            e, &parts3, &injp3, &mut low3, &mut all3, rank, streams, t3, true,
7751        )?;
7752        let mut mixed3 = e.zeros(t3 * hidden)?;
7753        launch_hc_diet_stage3(
7754            e,
7755            &ptrs3,
7756            &norm_stack,
7757            &inv3,
7758            &up_b16,
7759            &low3,
7760            &mut mixed3,
7761            hidden,
7762            rank,
7763            streams,
7764            t3,
7765        )?;
7766        let low3_h = e.dtoh(&low3)?;
7767        let all3_h = e.dtoh(&all3)?;
7768        let mixed3_h = e.dtoh(&mixed3)?;
7769        // MT weight-shared stages (set_verify_mt): stage0 inv + stage1_mt parts +
7770        // stage3_mt mixed must be BIT-IDENTICAL to the token-grid stages above.
7771        {
7772            let mut inv_mt = e.zeros(t3 * streams)?;
7773            launch_hc_diet_stage0_mt(e, &ptrs3, &mut inv_mt, hidden, streams, t3, eps)?;
7774            let mut parts_mt = e.zeros(t3 * streams * rank)?;
7775            let mut injp_mt = e.zeros(t3 * streams * streams)?;
7776            launch_hc_diet_stage1_mt(
7777                e,
7778                &ptrs3,
7779                &norm_stack,
7780                &inv_mt,
7781                &down_b16,
7782                Some(&inj_b16),
7783                &mut parts_mt,
7784                &mut injp_mt,
7785                hidden,
7786                rank,
7787                streams,
7788                t3,
7789            )?;
7790            let mut low_mt = e.zeros(t3 * rank)?;
7791            let mut all_mt = e.zeros(streams * t3)?;
7792            launch_hc_diet_stage2(
7793                e,
7794                &parts_mt,
7795                &injp_mt,
7796                &mut low_mt,
7797                &mut all_mt,
7798                rank,
7799                streams,
7800                t3,
7801                true,
7802            )?;
7803            let mut mixed_mt = e.zeros(t3 * hidden)?;
7804            launch_hc_diet_stage3_mt(
7805                e,
7806                &ptrs3,
7807                &norm_stack,
7808                &inv_mt,
7809                &up_b16,
7810                &low_mt,
7811                &mut mixed_mt,
7812                hidden,
7813                rank,
7814                streams,
7815                t3,
7816            )?;
7817            let bit_check_mt = |name: &str, a: &[f32], b: &[f32]| -> Res<()> {
7818                for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
7819                    if x.to_bits() != y.to_bits() {
7820                        return Err(format!(
7821                            "hc-diet mt oracle: {name} idx {i}: mt {x} vs grid {y} NOT \
7822                             bit-identical"
7823                        )
7824                        .into());
7825                    }
7826                }
7827                Ok(())
7828            };
7829            bit_check_mt("inv", &e.dtoh(&inv_mt)?, &e.dtoh(&inv3)?)?;
7830            bit_check_mt("low_act", &e.dtoh(&low_mt)?, &low3_h)?;
7831            bit_check_mt("inject", &e.dtoh(&all_mt)?, &all3_h)?;
7832            bit_check_mt("mixed", &e.dtoh(&mixed_mt)?, &mixed3_h)?;
7833        }
7834        let bit_check = |name: &str, a: &[f32], b: &[f32]| -> Res<()> {
7835            for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
7836                if x.to_bits() != y.to_bits() {
7837                    return Err(format!(
7838                        "hc-diet t-ext oracle: {name} idx {i}: t3 {x} vs t1 {y} NOT bit-identical"
7839                    )
7840                    .into());
7841                }
7842            }
7843            Ok(())
7844        };
7845        for tok in 0..t3 {
7846            let ptr_tok: Vec<u64> = ptr_vals3
7847                .iter()
7848                .map(|&base| base + (tok * hidden * 4) as u64)
7849                .collect();
7850            let ptrs_tok = e.htod_u64(&ptr_tok)?;
7851            let mut parts1 = e.zeros(streams * rank)?;
7852            let mut injp1 = e.zeros(streams * streams)?;
7853            let mut inv1 = e.zeros(streams)?;
7854            launch_hc_diet_stage1(
7855                e,
7856                &ptrs_tok,
7857                &norm_stack,
7858                &down_b16,
7859                Some(&inj_b16),
7860                &mut parts1,
7861                &mut injp1,
7862                &mut inv1,
7863                hidden,
7864                rank,
7865                streams,
7866                1,
7867                eps,
7868            )?;
7869            let mut low1 = e.zeros(rank)?;
7870            let mut all1 = e.zeros(streams)?;
7871            launch_hc_diet_stage2(
7872                e, &parts1, &injp1, &mut low1, &mut all1, rank, streams, 1, true,
7873            )?;
7874            let mut mixed1 = e.zeros(hidden)?;
7875            launch_hc_diet_stage3(
7876                e,
7877                &ptrs_tok,
7878                &norm_stack,
7879                &inv1,
7880                &up_b16,
7881                &low1,
7882                &mut mixed1,
7883                hidden,
7884                rank,
7885                streams,
7886                1,
7887            )?;
7888            bit_check(
7889                "low_act",
7890                &low3_h[tok * rank..(tok + 1) * rank],
7891                &e.dtoh(&low1)?,
7892            )?;
7893            let all1_h = e.dtoh(&all1)?;
7894            let col: Vec<f32> = (0..streams).map(|s| all3_h[s * t3 + tok]).collect();
7895            bit_check("inject", &col, &all1_h)?;
7896            bit_check(
7897                "mixed",
7898                &mixed3_h[tok * hidden..(tok + 1) * hidden],
7899                &e.dtoh(&mixed1)?,
7900            )?;
7901        }
7902    }
7903    Ok(format!(
7904        "hc-diet real-geometry oracle: streams 4 hidden 2560 rank 320, worst rel \
7905         {worst:.3e} vs the classic fused chain at t 1; t 3 token-dim AND the mt \
7906         weight-shared stages BIT-IDENTICAL to per-token t 1 launches"
7907    ))
7908}
7909
7910/// Kernel-vs-host oracle for the bf16 trunk matvec (`qmatvec_bf16w_f32`). The tiny
7911/// four-arm gate's FIXTURE weights are random f32 (never bf16-representable), so its
7912/// bf16 twins are skipped by the value guard there and only the dir arms exercise the
7913/// path end to end; this synthetic arm gates the kernel directly against a host f32
7914/// matvec over identical bf16-widened weights: batch > 1, BOTH x_bstride modes (shared
7915/// plane like the up projection, per-batch planes like down), t > 1, negative/denormal
7916/// bf16 values, and a non-multiple-of-blockDim group count. Products are exact; only
7917/// summation order differs from the sequential host chain — tolerance 1e-5 rel.
7918/// REAL-GEOMETRY oracle for the hcmicro kernels (streams 4, hidden 2560, t 10 — the
7919/// artifact's read-gate shape, which the tiny plan (streams 2, hidden 16) cannot
7920/// reach). Each micro kernel runs against the classic composition it replaces on the
7921/// same random inputs: batched plane norms vs per-stream rms_norm, the two-stage inject
7922/// vs the single-stage kernel, the slab write vs the add_scaled_rows chain. Born from
7923/// the perf7 incident: the bundle shipped tiny-green and broke real prefill at layer 0.
7924pub fn gate_hc_micro_kernels(e: &Engine) -> Res<String> {
7925    let (streams, hidden, t) = (4usize, 2560usize, 10usize);
7926    let wide = streams * hidden;
7927    let mut lcg = 0x1357_9bdf_u64;
7928    let mut next_f32 = move || -> f32 {
7929        lcg = lcg
7930            .wrapping_mul(6364136223846793005)
7931            .wrapping_add(1442695040888963407);
7932        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
7933    };
7934    let mut rand_vec = |n: usize| -> Vec<f32> { (0..n).map(|_| next_f32()).collect() };
7935    let planes_host: Vec<Vec<f32>> = (0..streams).map(|_| rand_vec(t * hidden)).collect();
7936    let planes: Vec<CudaSlice<f32>> = planes_host
7937        .iter()
7938        .map(|v| e.htod(v))
7939        .collect::<Result<_, _>>()?;
7940    let ptr_vals: Vec<u64> = {
7941        let stream = e.gpu.stream();
7942        planes.iter().map(|p| p.device_ptr(&stream).0).collect()
7943    };
7944    let ptrs = e.htod_u64(&ptr_vals)?;
7945    let mut worst = 0.0f32;
7946    let check = |name: &str, a: &[f32], b: &[f32], worst: &mut f32| -> Res<()> {
7947        for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
7948            let rel = (x - y).abs() / y.abs().max(1.0);
7949            if rel > *worst {
7950                *worst = rel;
7951            }
7952            if rel > 1e-4 {
7953                return Err(format!(
7954                    "hc-micro oracle: {name} idx {i}: micro {x} classic {y} (rel {rel:.3e})"
7955                )
7956                .into());
7957            }
7958        }
7959        Ok(())
7960    };
7961
7962    // (a) batched plane norms vs per-stream rms_norm_into_view.
7963    let norm_stack_host = rand_vec(wide);
7964    let norm_stack = e.htod(&norm_stack_host)?;
7965    let eps = 1e-6f32;
7966    let mut normed_a = e.zeros(streams * t * hidden)?;
7967    launch_hc_norm_planes(
7968        e,
7969        &ptrs,
7970        &norm_stack,
7971        &mut normed_a,
7972        hidden,
7973        t,
7974        streams,
7975        eps,
7976    )?;
7977    let mut normed_b = e.zeros(streams * t * hidden)?;
7978    for s in 0..streams {
7979        let w = e.htod(&norm_stack_host[s * hidden..(s + 1) * hidden])?;
7980        let mut dst = normed_b.slice_mut(s * t * hidden..(s + 1) * t * hidden);
7981        launch_rms_norm_into_view(e, &planes[s], &w, &mut dst, hidden, t, eps)?;
7982    }
7983    check("norm", &e.dtoh(&normed_a)?, &e.dtoh(&normed_b)?, &mut worst)?;
7984
7985    // (b) two-stage inject vs the single-stage kernel, over the SAME normed slab.
7986    let inj_w_host = rand_vec(streams * wide);
7987    let inj_w = e.htod(&inj_w_host)?;
7988    let mut all_a = e.zeros(streams * t)?;
7989    let mut partials = e.zeros(streams * t * 16)?;
7990    launch_hc_inject_two_stage(
7991        e,
7992        &normed_b,
7993        &inj_w,
7994        None,
7995        &mut partials,
7996        &mut all_a,
7997        streams,
7998        t,
7999        hidden,
8000        16,
8001    )?;
8002    let mut all_b = e.zeros(streams * t)?;
8003    launch_hc_inject_gates(e, &normed_b, &inj_w, &mut all_b, streams, t, hidden)?;
8004    check("inject", &e.dtoh(&all_a)?, &e.dtoh(&all_b)?, &mut worst)?;
8005
8006    // (c) slab write vs the add_scaled_rows chain, from identical plane states.
8007    let block_out = e.htod(&rand_vec(t * hidden))?;
8008    launch_hc_write_planes(e, &ptrs, &block_out, &all_b, hidden, t, streams)?;
8009    let mut expect: Vec<Vec<f32>> = Vec::with_capacity(streams);
8010    let all_host = e.dtoh(&all_b)?;
8011    let bo_host = e.dtoh(&block_out)?;
8012    for (s, base) in planes_host.iter().enumerate() {
8013        let mut rows = base.clone();
8014        for tok in 0..t {
8015            let g = all_host[s * t + tok];
8016            for d in 0..hidden {
8017                rows[tok * hidden + d] += bo_host[tok * hidden + d] * g;
8018            }
8019        }
8020        expect.push(rows);
8021    }
8022    for (s, plane) in planes.iter().enumerate() {
8023        check(
8024            &format!("write plane {s}"),
8025            &e.dtoh(plane)?,
8026            &expect[s],
8027            &mut worst,
8028        )?;
8029    }
8030    Ok(format!(
8031        "hc-micro real-geometry oracle: streams 4 hidden 2560 t 10, worst rel {worst:.3e} \
8032         over norm/inject/write vs the classic composition"
8033    ))
8034}
8035
8036/// REAL-GEOMETRY oracle for the perf-round-3 GDN kernels (the tiny plan cannot reach
8037/// either: hk 4 fails the step twin's warp guard, and the fused norm's win is only
8038/// meaningful at real widths). (a) `gdn_scan_step_f32` vs `gdn_scan_naive_f32` at t=1
8039/// on identical inputs and state copies — same per-element math, block-tree vs
8040/// sequential row sums, so tolerance-gated (1e-4 rel, worst reported); covers the
8041/// artifact geometry (nk 16, nv 48, hk/hv 128 — head sharing h%nk) and the minimum
8042/// hk=32 shape. (b) `rms_sigmul_f32` vs the rms_norm + sigmoid + mul chain it replaces
8043/// — asserted BIT-IDENTICAL (the kernel is rms_norm_f32-verbatim + sigmoid_f32 with no
8044/// contraction seam).
8045/// Block-list attention kernel oracle (long-context lane), real QSA geometry (hd 256,
8046/// 24/2 heads). Arm A: masked kernel vs block-list kernel over the SAME selections at
8047/// t_kv 4096 — BIT identity (the masked kernel's -1e30 entries contribute exact-0 terms
8048/// in the same ascending order; see the kernel comment). Arm B: t_kv 16384 — past the
8049/// masked kernel's smem bound, where only the block-list form runs — vs a HOST f32 twin
8050/// of the same phase order (expf vs libm exp differ in ULPs; tolerance class).
8051/// Selections come through the PRODUCTION renderers (`rowsel_to_mask`/`rowsel_positions`)
8052/// so the emission code is gated with the kernel.
8053pub fn gate_sdpa_blocklist(e: &Engine) -> Res<String> {
8054    let mut lcg = 0x51ee_7bad_u64;
8055    let mut next_f32 = move || -> f32 {
8056        lcg = lcg
8057            .wrapping_mul(6364136223846793005)
8058            .wrapping_add(1442695040888963407);
8059        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
8060    };
8061    let (hd, nh, nkv, t) = (256usize, 24usize, 2usize, 3usize);
8062    let block_size = 4usize;
8063    let scale = 1.0 / (hd as f32).sqrt();
8064    let mut bit_rows = 0usize;
8065    let mut worst_rel = 0.0f32;
8066    for (t_kv, vs_masked) in [(4096usize, true), (16384usize, false)] {
8067        let q_host: Vec<f32> = (0..t * nh * hd).map(|_| next_f32()).collect();
8068        let k_host: Vec<f32> = (0..t_kv * nkv * hd).map(|_| next_f32()).collect();
8069        let v_host: Vec<f32> = (0..t_kv * nkv * hd).map(|_| next_f32()).collect();
8070        // Per-row selections: row 0 full causal prefix; rows 1/2 scored-form block lists
8071        // (stride-3 / tail-heavy) with the always-visible incomplete tail.
8072        let sels: Vec<RowSel> = (0..t)
8073            .map(|qt| {
8074                let visible = t_kv - t + qt + 1;
8075                let complete = visible / block_size;
8076                // A full-prefix row (production: complete <= budget) only in the
8077                // 4096 case — its position list scales with `visible`, and the
8078                // 16384 full form would blow the 48 KB smem cap production never
8079                // approaches (full rows are <= 2052 positions there).
8080                if qt == 0 && vs_masked {
8081                    return RowSel {
8082                        full: true,
8083                        blocks: Vec::new(),
8084                        visible,
8085                    };
8086                }
8087                let stride = if qt == 1 { 3 } else { 7 };
8088                let blocks: Vec<u32> = (0..complete as u32)
8089                    .rev()
8090                    .step_by(stride)
8091                    .take(512)
8092                    .collect::<Vec<_>>()
8093                    .into_iter()
8094                    .rev()
8095                    .collect();
8096                RowSel {
8097                    full: false,
8098                    blocks,
8099                    visible,
8100                }
8101            })
8102            .collect();
8103        let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
8104        let q = e.htod(&q_host)?;
8105        let k = e.htod(&k_host)?;
8106        let v = e.htod(&v_host)?;
8107        let pos = e.htod_i32(&pos_flat)?;
8108        let meta_dev = e.htod_i32(&meta)?;
8109        let mut o_list = e.zeros(t * nh * hd)?;
8110        launch_sdpa_blocklist(
8111            e,
8112            &q,
8113            &k.slice(0..t_kv * nkv * hd),
8114            &v.slice(0..t_kv * nkv * hd),
8115            &mut o_list,
8116            &pos,
8117            &meta_dev,
8118            hd,
8119            nh,
8120            nkv,
8121            t,
8122            max_count,
8123            scale,
8124        )?;
8125        let ours = e.dtoh(&o_list)?;
8126        if vs_masked {
8127            let mask = rowsel_to_mask(&sels, block_size, t_kv);
8128            let mask_dev = e.htod_bytes(&mask)?;
8129            let mut o_mask = e.zeros(t * nh * hd)?;
8130            launch_sdpa_mask(
8131                e,
8132                &q,
8133                &k.slice(0..t_kv * nkv * hd),
8134                &v.slice(0..t_kv * nkv * hd),
8135                &mut o_mask,
8136                &mask_dev,
8137                hd,
8138                nh,
8139                nkv,
8140                t,
8141                t_kv,
8142                scale,
8143            )?;
8144            let masked = e.dtoh(&o_mask)?;
8145            for (i, (a, b)) in masked.iter().zip(ours.iter()).enumerate() {
8146                if a.to_bits() != b.to_bits() {
8147                    return Err(format!(
8148                        "sdpa_blocklist vs masked: bit mismatch at {i}: {a} vs {b} (t_kv {t_kv})"
8149                    )
8150                    .into());
8151                }
8152            }
8153            bit_rows = t * nh * hd;
8154        } else {
8155            // HOST twin, same phase order: per (row, head) dots ascending over the
8156            // selection, single-pass max/exp/normalize, weighted V ascending.
8157            for qt in 0..t {
8158                let off = meta[2 * qt] as usize;
8159                let count = meta[2 * qt + 1] as usize;
8160                for head in 0..nh {
8161                    let kvh = head / (nh / nkv);
8162                    let qrow = &q_host[(qt * nh + head) * hd..(qt * nh + head + 1) * hd];
8163                    let mut scores: Vec<f32> = (0..count)
8164                        .map(|i| {
8165                            let p = pos_flat[off + i] as usize;
8166                            let krow = &k_host[(p * nkv + kvh) * hd..(p * nkv + kvh + 1) * hd];
8167                            let mut acc = 0.0f32;
8168                            for d in 0..hd {
8169                                acc += qrow[d] * krow[d];
8170                            }
8171                            acc * scale
8172                        })
8173                        .collect();
8174                    let mx = scores.iter().copied().fold(-1e30f32, f32::max);
8175                    let mut sum = 0.0f32;
8176                    for s in scores.iter_mut() {
8177                        *s = (*s - mx).exp();
8178                        sum += *s;
8179                    }
8180                    let inv = 1.0 / sum;
8181                    for s in scores.iter_mut() {
8182                        *s *= inv;
8183                    }
8184                    for d in 0..hd {
8185                        let mut acc = 0.0f32;
8186                        for (i, s) in scores.iter().enumerate() {
8187                            let p = pos_flat[off + i] as usize;
8188                            acc += s * v_host[(p * nkv + kvh) * hd + d];
8189                        }
8190                        let got = ours[(qt * nh + head) * hd + d];
8191                        let rel = (got - acc).abs() / acc.abs().max(1e-3);
8192                        worst_rel = worst_rel.max(rel);
8193                        if rel > 1e-4 {
8194                            return Err(format!(
8195                                "sdpa_blocklist vs host twin: rel {rel} at row {qt} head {head} \
8196                                 dim {d} (t_kv {t_kv})"
8197                            )
8198                            .into());
8199                        }
8200                    }
8201                }
8202            }
8203        }
8204    }
8205    Ok(format!(
8206        "sdpa-blocklist oracle: BIT-IDENTICAL to the masked kernel over {bit_rows} values \
8207         (t_kv 4096, full+stride selections); past the mask bound (t_kv 16384) worst rel \
8208         {worst_rel:.3e} vs the host twin"
8209    ))
8210}
8211
8212/// kvq/idxq kernel oracles (KV-quant lane). Four pins, all BIT-exact:
8213/// (1) the append-quantize kernels vs the host quantize twins (q8_0 K rows, q5_1 V
8214///     rows) over random + adversarial blocks (zeros, half-ulp rounding ties, subnormal
8215///     scales, constant blocks) at real (512) and padded-tail (40) widths;
8216/// (2) the row-dequant kernel vs the host dequant twins on those bytes;
8217/// (3) the FUSED quantized block-list attention vs the composition
8218///     "q4e_kv_dequant_rows then sdpa_blocklist_f32" — the load-bearing oracle: it
8219///     proves in-kernel dequant reads the same f32 values the storage contract defines
8220///     (the qsa_index_score 1-ULP FMA lesson made both sides explicit-intrinsic);
8221/// (4) the indexer q8/bf16 device appenders vs the host cache twins (the idxcache
8222///     host/device interleave contract).
8223/// Caveat, stated: blocks mixing +0.0 and -0.0 are outside the pin (fminf/fmaxf zero
8224/// sign order is unspecified); projection outputs do not produce signed-zero ties.
8225pub fn gate_kvq_kernels(e: &Engine) -> Res<String> {
8226    let mut lcg = 0x6b_7671_5eed_u64; // "kvq"-seeded LCG
8227    let mut next_f32 = move || -> f32 {
8228        lcg = lcg
8229            .wrapping_mul(6364136223846793005)
8230            .wrapping_add(1442695040888963407);
8231        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
8232    };
8233    let mut report = Vec::new();
8234
8235    // ---- (1) + (2): quantize + dequant twins ----
8236    for &dim in &[512usize, 40usize] {
8237        let rows = 9usize;
8238        let mut host_rows_f: Vec<f32> = (0..rows * dim).map(|_| next_f32()).collect();
8239        // Adversarial rows: 0 = all zeros; 1 = constant block (d == 0 path for q5's
8240        // mx == mn); 2 = rounding ties (values at exact half steps of the block scale).
8241        for v in host_rows_f[0..dim].iter_mut() {
8242            *v = 0.0;
8243        }
8244        for v in host_rows_f[dim..2 * dim].iter_mut() {
8245            *v = 0.75;
8246        }
8247        for (i, v) in host_rows_f[2 * dim..3 * dim].iter_mut().enumerate() {
8248            // amax = 1.0 at lane 0; others sit at k*(1/127)*0.5 half-steps.
8249            *v = if i == 0 {
8250                1.0
8251            } else {
8252                (i as f32) * 0.5 / 127.0
8253            };
8254        }
8255        // Subnormal-scale row.
8256        for v in host_rows_f[3 * dim..4 * dim].iter_mut() {
8257            *v *= 1e-40;
8258        }
8259        let dev_rows = e.htod(&host_rows_f)?;
8260        let mut kq = e.alloc_u8(rows * q8_row_bytes(dim))?;
8261        let mut vq = e.alloc_u8(rows * q5_row_bytes(dim))?;
8262        launch_q4e_kv_append(e, &dev_rows, &dev_rows, &mut kq, &mut vq, 0, rows, dim)?;
8263        let kq_host = e.dtoh_u8(&kq)?;
8264        let vq_host = e.dtoh_u8(&vq)?;
8265        let mut k_twin = Vec::new();
8266        let mut v_twin = Vec::new();
8267        for r in 0..rows {
8268            host_quant_q8_row(&host_rows_f[r * dim..(r + 1) * dim], dim, &mut k_twin);
8269            host_quant_q5_row(&host_rows_f[r * dim..(r + 1) * dim], dim, &mut v_twin);
8270        }
8271        if kq_host != k_twin {
8272            let i = kq_host.iter().zip(&k_twin).position(|(a, b)| a != b);
8273            return Err(format!("kvq q8 quantize twin: byte mismatch at {i:?} (dim {dim})").into());
8274        }
8275        if vq_host != v_twin {
8276            let i = vq_host.iter().zip(&v_twin).position(|(a, b)| a != b);
8277            return Err(format!("kvq q5 quantize twin: byte mismatch at {i:?} (dim {dim})").into());
8278        }
8279        // Dequant twin.
8280        let mut kf = e.zeros(rows * dim)?;
8281        let mut vf = e.zeros(rows * dim)?;
8282        launch_q4e_kv_dequant_rows(e, &kq, &vq, &mut kf, &mut vf, 0, rows, dim)?;
8283        let kf_host = e.dtoh(&kf)?;
8284        let vf_host = e.dtoh(&vf)?;
8285        let mut kf_twin = Vec::new();
8286        let mut vf_twin = Vec::new();
8287        host_deq_q8_rows(&kq_host, 0, rows, dim, &mut kf_twin);
8288        host_deq_q5_rows(&vq_host, 0, rows, dim, &mut vf_twin);
8289        for (i, (a, b)) in kf_host.iter().zip(&kf_twin).enumerate() {
8290            if a.to_bits() != b.to_bits() {
8291                return Err(format!("kvq q8 dequant twin: bit mismatch at {i} (dim {dim})").into());
8292            }
8293        }
8294        for (i, (a, b)) in vf_host.iter().zip(&vf_twin).enumerate() {
8295            if a.to_bits() != b.to_bits() {
8296                return Err(format!("kvq q5 dequant twin: bit mismatch at {i} (dim {dim})").into());
8297            }
8298        }
8299        report.push(format!("quant+dequant twins dim {dim}: BYTE/BIT-IDENTICAL"));
8300    }
8301
8302    // ---- (3) fused quant attention vs the dequant-rows composition ----
8303    {
8304        let (hd, nh, nkv, t) = (256usize, 24usize, 2usize, 3usize);
8305        let kv_dim = nkv * hd;
8306        let block_size = 4usize;
8307        let scale = 1.0 / (hd as f32).sqrt();
8308        let t_kv = 4096usize;
8309        let q_host: Vec<f32> = (0..t * nh * hd).map(|_| next_f32()).collect();
8310        let k_host: Vec<f32> = (0..t_kv * kv_dim).map(|_| next_f32()).collect();
8311        let v_host: Vec<f32> = (0..t_kv * kv_dim).map(|_| next_f32()).collect();
8312        let k_rows = e.htod(&k_host)?;
8313        let v_rows = e.htod(&v_host)?;
8314        let mut kq = e.alloc_u8(t_kv * q8_row_bytes(kv_dim))?;
8315        let mut vq = e.alloc_u8(t_kv * q5_row_bytes(kv_dim))?;
8316        launch_q4e_kv_append(e, &k_rows, &v_rows, &mut kq, &mut vq, 0, t_kv, kv_dim)?;
8317        // Selections: one full-prefix row + two scored stride rows (the
8318        // gate_sdpa_blocklist shapes, bounded to the production smem class).
8319        let sels: Vec<RowSel> = (0..t)
8320            .map(|qt| {
8321                let visible = (t_kv - t + qt + 1).min(2052);
8322                if qt == 0 {
8323                    return RowSel {
8324                        full: true,
8325                        blocks: Vec::new(),
8326                        visible,
8327                    };
8328                }
8329                let complete = (t_kv - t + qt + 1) / block_size;
8330                let stride = if qt == 1 { 3 } else { 7 };
8331                let blocks: Vec<u32> = (0..complete as u32)
8332                    .rev()
8333                    .step_by(stride)
8334                    .take(512)
8335                    .collect::<Vec<_>>()
8336                    .into_iter()
8337                    .rev()
8338                    .collect();
8339                RowSel {
8340                    full: false,
8341                    blocks,
8342                    visible: t_kv - t + qt + 1,
8343                }
8344            })
8345            .collect();
8346        let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
8347        let q = e.htod(&q_host)?;
8348        let pos = e.htod_i32(&pos_flat)?;
8349        let meta_dev = e.htod_i32(&meta)?;
8350        let mut o_fused = e.zeros(t * nh * hd)?;
8351        launch_q4e_sdpa_blocklist_q8q5(
8352            e,
8353            &q,
8354            &kq,
8355            &vq,
8356            &mut o_fused,
8357            &pos,
8358            &meta_dev,
8359            hd,
8360            nh,
8361            nkv,
8362            t,
8363            max_count,
8364            scale,
8365        )?;
8366        let mut k_deq = e.zeros(t_kv * kv_dim)?;
8367        let mut v_deq = e.zeros(t_kv * kv_dim)?;
8368        launch_q4e_kv_dequant_rows(e, &kq, &vq, &mut k_deq, &mut v_deq, 0, t_kv, kv_dim)?;
8369        let mut o_comp = e.zeros(t * nh * hd)?;
8370        launch_sdpa_blocklist(
8371            e,
8372            &q,
8373            &k_deq.slice(0..t_kv * kv_dim),
8374            &v_deq.slice(0..t_kv * kv_dim),
8375            &mut o_comp,
8376            &pos,
8377            &meta_dev,
8378            hd,
8379            nh,
8380            nkv,
8381            t,
8382            max_count,
8383            scale,
8384        )?;
8385        let fused = e.dtoh(&o_fused)?;
8386        let comp = e.dtoh(&o_comp)?;
8387        for (i, (a, b)) in fused.iter().zip(&comp).enumerate() {
8388            if a.to_bits() != b.to_bits() {
8389                return Err(format!(
8390                    "kvq fused attention vs dequant composition: bit mismatch at {i}: {a} vs {b}"
8391                )
8392                .into());
8393            }
8394        }
8395        // ---- (3b) `kvhoist` vs the un-hoisted kernel, SAME real geometry ----
8396        // The hoist is a pure read-pattern change (fp16 K block scale loaded once per 32-element
8397        // block instead of once per element), so the bar is bit-identity and nothing weaker.
8398        //
8399        // This arm rides arm (3)'s geometry deliberately: hd=256 is EIGHT 32-element blocks per
8400        // head slice and nkv=2 means the second KV head starts at element 256, so the hoisted
8401        // loop's block walk and its `e0 = kv_head*head_dim` offset are both genuinely exercised.
8402        // At a tiny head_dim the loop would run ONE iteration and the per-block scale advance —
8403        // the only thing the seam changes — would never be taken. That is precisely the
8404        // tiny-green/real-broken shape this lane has been bitten by twice, so the arm is written
8405        // where it cannot happen rather than trusted to a comment.
8406        {
8407            let was = kv_hoist_on();
8408            set_kv_hoist(true);
8409            let mut o_hoist = e.zeros(t * nh * hd)?;
8410            let launched = launch_q4e_sdpa_blocklist_q8q5(
8411                e,
8412                &q,
8413                &kq,
8414                &vq,
8415                &mut o_hoist,
8416                &pos,
8417                &meta_dev,
8418                hd,
8419                nh,
8420                nkv,
8421                t,
8422                max_count,
8423                scale,
8424            );
8425            set_kv_hoist(was);
8426            launched?;
8427            let hoist = e.dtoh(&o_hoist)?;
8428            let mut worst: Option<(usize, f32, f32)> = None;
8429            for (i, (a, b)) in hoist.iter().zip(&fused).enumerate() {
8430                if a.to_bits() != b.to_bits() && worst.is_none() {
8431                    worst = Some((i, *a, *b));
8432                }
8433            }
8434            if let Some((i, a, b)) = worst {
8435                return Err(format!(
8436                    "kvhoist vs un-hoisted q8q5 blocklist: bit mismatch at {i}: {a} vs {b} \
8437                     (hd={hd} nh={nh} nkv={nkv} t={t} t_kv={t_kv} max_count={max_count})"
8438                )
8439                .into());
8440            }
8441            // A no-op arm would also compare equal. Prove the seam actually selected the other
8442            // kernel: `kv_hoist_on()` gates the `e.func` name, and an unknown name would have
8443            // failed the launch above rather than silently falling through — so a green compare
8444            // plus a completed launch under the armed seam is the engagement evidence. State the
8445            // count so a zero-value compare cannot pass as a pass.
8446            report.push(format!(
8447                "kvhoist vs un-hoisted q8q5 blocklist: BIT-IDENTICAL over {} values \
8448                 (real geometry hd={hd} nh={nh} nkv={nkv}, {} blocks/head slice, max_count={max_count})",
8449                t * nh * hd,
8450                hd / 32
8451            ));
8452        }
8453        report.push(format!(
8454            "fused q8q5 blocklist vs dequant+f32 composition: BIT-IDENTICAL over {} values",
8455            t * nh * hd
8456        ));
8457    }
8458
8459    // ---- (4) indexer appenders vs the host cache twins ----
8460    {
8461        let idx_dim = 128usize;
8462        let qk_width = 5 * idx_dim; // 4 query heads + 1 key head
8463        let rows = 7usize;
8464        let src_host: Vec<f32> = (0..rows * qk_width).map(|_| next_f32()).collect();
8465        let src = e.htod(&src_host)?;
8466        let q_off = 4 * idx_dim;
8467        // q8 arm.
8468        let mut dst_q8 = e.alloc_u8((rows + 2) * q8_row_bytes(idx_dim))?;
8469        launch_q4e_idx_append_q8(e, &src, &mut dst_q8, rows, idx_dim, qk_width, q_off, 2)?;
8470        let got = e.dtoh_u8(&dst_q8)?;
8471        let mut twin = vec![0u8; 2 * q8_row_bytes(idx_dim)];
8472        for r in 0..rows {
8473            host_quant_q8_row(
8474                &src_host[r * qk_width + q_off..(r + 1) * qk_width],
8475                idx_dim,
8476                &mut twin,
8477            );
8478        }
8479        if got[2 * q8_row_bytes(idx_dim)..] != twin[2 * q8_row_bytes(idx_dim)..] {
8480            return Err("idxq q8 append twin: byte mismatch".into());
8481        }
8482        // bf16 arm.
8483        let mut dst_bf = unsafe { e.gpu.stream().alloc::<u16>((rows + 2) * idx_dim)? };
8484        e.gpu.stream().memset_zeros(&mut dst_bf)?;
8485        launch_q4e_idx_append_bf16(e, &src, &mut dst_bf, rows, idx_dim, qk_width, q_off, 2)?;
8486        let got_bf: Vec<u16> = {
8487            let v = e
8488                .gpu
8489                .stream()
8490                .clone_dtoh(&dst_bf.slice(0..(rows + 2) * idx_dim))?;
8491            e.gpu.stream().synchronize()?;
8492            v
8493        };
8494        for r in 0..rows {
8495            for c in 0..idx_dim {
8496                let want = f32_to_bf16_rne(src_host[r * qk_width + q_off + c]);
8497                if got_bf[(2 + r) * idx_dim + c] != want {
8498                    return Err(format!("idxq bf16 append twin: mismatch row {r} col {c}").into());
8499                }
8500            }
8501        }
8502        report.push("idx q8/bf16 appenders vs host twins: BYTE-IDENTICAL".to_string());
8503    }
8504
8505    Ok(format!("kvq kernel oracles: {}", report.join("; ")))
8506}
8507
8508/// Device QSA index-scorer oracle at REAL indexer geometry (4 heads x 128, block 4):
8509/// `qsa_index_score_f32` vs the host twin's arithmetic, BIT for BIT, over a block count
8510/// past the real budget (so the scoring arm — not the structural fast path — is what
8511/// runs), plus the top-k SET equality that the selection actually depends on.
8512pub fn gate_qsa_index_score(e: &Engine) -> Res<String> {
8513    let mut lcg = 0xfeed_1234_u64;
8514    let mut next_f32 = move || -> f32 {
8515        lcg = lcg
8516            .wrapping_mul(6364136223846793005)
8517            .wrapping_add(1442695040888963407);
8518        (((lcg >> 33) as u32) % 4000) as f32 / 2000.0 - 1.0
8519    };
8520    let (heads, head_dim) = (4usize, 128usize);
8521    let scale = (head_dim as f32).sqrt();
8522    let budget = 512usize;
8523    let mut worst_rows = 0usize;
8524    for (rows, n_blocks) in [(1usize, 4096usize), (7, 1031)] {
8525        let q_host: Vec<f32> = (0..rows * heads * head_dim).map(|_| next_f32()).collect();
8526        let pooled_host: Vec<f32> = (0..n_blocks * head_dim).map(|_| next_f32()).collect();
8527        let q = e.htod(&q_host)?;
8528        let pooled = e.htod(&pooled_host)?;
8529        let mut scores_dev = e.uninit(rows * n_blocks)?;
8530        launch_qsa_index_score(
8531            e,
8532            &q,
8533            &pooled,
8534            &mut scores_dev,
8535            heads,
8536            head_dim,
8537            n_blocks,
8538            rows,
8539            scale,
8540        )?;
8541        let got = e.dtoh(&scores_dev)?;
8542        for row in 0..rows {
8543            let qr = &q_host[row * heads * head_dim..(row + 1) * heads * head_dim];
8544            let host = score_blocks(qr, &pooled_host, heads, head_dim, n_blocks, scale, 1);
8545            for (b, want) in host.iter().enumerate() {
8546                let g = got[row * n_blocks + b];
8547                if g.to_bits() != want.to_bits() {
8548                    return Err(format!(
8549                        "qsa_index_score: bit mismatch row {row} block {b}: {g} vs host {want}"
8550                    )
8551                    .into());
8552                }
8553            }
8554            let a = top_blocks_ascending(&host, budget, 1);
8555            let b = top_blocks_ascending(&got[row * n_blocks..(row + 1) * n_blocks], budget, 1);
8556            if a != b {
8557                return Err(format!("qsa_index_score: top-k set differs at row {row}").into());
8558            }
8559            worst_rows += 1;
8560        }
8561    }
8562    // ---- `poolT`: the dim-major plane, through the SAME host-twin bar ----
8563    // Validates the whole chain, not just the kernel: the transpose kernel writes the plane from
8564    // the row-major region on device, and the transposed score kernel reads it. Bit-identity to
8565    // the host twin (not merely to the row-major device kernel) is the bar, because the row-major
8566    // kernel is itself gated against the host above — comparing only device-to-device would let a
8567    // shared mistake pass twice.
8568    //
8569    // The case is chosen to catch the ONE mistake this layout invites: `cap_rows != n_blocks`.
8570    // The plane's pitch is the mirror's block CAPACITY, and the mirror grows to a power of two
8571    // while `n_blocks` is whatever the fill happens to be — so `cap_rows == n_blocks` is the
8572    // ABNORMAL state, and a kernel handed `n_blocks` as its pitch would read dim d of block b as
8573    // dim d of a different block for every d > 0. That is silent wrong values, and it would be
8574    // green in any gate where the two numbers happen to coincide. Here they deliberately do not
8575    // (1031 blocks in a 4096-block plane), and a second case pins the aligned edge.
8576    let mut pool_t_rows = 0usize;
8577    for (rows, n_blocks, cap_rows) in [(1usize, 1031usize, 4096usize), (5, 2048, 2048)] {
8578        let q_host: Vec<f32> = (0..rows * heads * head_dim).map(|_| next_f32()).collect();
8579        let pooled_host: Vec<f32> = (0..n_blocks * head_dim).map(|_| next_f32()).collect();
8580        let q = e.htod(&q_host)?;
8581        // The mirror as `indexer_select_rows` builds it: POOL_PLANES regions of cap_rows*head_dim,
8582        // the row-major rows H2D'd into the first, the plane filled by the transpose kernel.
8583        let mut mirror = e.zeros(cap_rows * head_dim * POOL_PLANES)?;
8584        {
8585            let mut view = mirror.slice_mut(0..n_blocks * head_dim);
8586            e.gpu.stream().memcpy_htod(&pooled_host, &mut view)?;
8587        }
8588        launch_qsa_pooled_transpose(e, &mut mirror, 0, n_blocks, head_dim, cap_rows)?;
8589        let was = pool_t_on();
8590        set_pool_t(true);
8591        let mut scores_dev = e.uninit(rows * n_blocks)?;
8592        let launched = launch_qsa_index_score(
8593            e,
8594            &q,
8595            &mirror,
8596            &mut scores_dev,
8597            heads,
8598            head_dim,
8599            n_blocks,
8600            rows,
8601            scale,
8602        );
8603        set_pool_t(was);
8604        launched?;
8605        let got = e.dtoh(&scores_dev)?;
8606        for row in 0..rows {
8607            let qr = &q_host[row * heads * head_dim..(row + 1) * heads * head_dim];
8608            let host = score_blocks(qr, &pooled_host, heads, head_dim, n_blocks, scale, 1);
8609            for (b, want) in host.iter().enumerate() {
8610                let g = got[row * n_blocks + b];
8611                if g.to_bits() != want.to_bits() {
8612                    return Err(format!(
8613                        "poolT qsa_index_score_f32_t: bit mismatch row {row} block {b}: \
8614                         {g} vs host {want} (n_blocks={n_blocks} cap_rows={cap_rows})"
8615                    )
8616                    .into());
8617                }
8618            }
8619            if top_blocks_ascending(&host, budget, 1)
8620                != top_blocks_ascending(&got[row * n_blocks..(row + 1) * n_blocks], budget, 1)
8621            {
8622                return Err(format!(
8623                    "poolT qsa_index_score_f32_t: top-{budget} set differs at row {row} \
8624                     (n_blocks={n_blocks} cap_rows={cap_rows})"
8625                )
8626                .into());
8627            }
8628            pool_t_rows += 1;
8629        }
8630    }
8631    Ok(format!(
8632        "qsa-index-score oracle: device scores BIT-IDENTICAL to the host twin over \
8633         {worst_rows} rows (4096 + 1031 blocks, real 4x128 geometry) and top-512 sets equal; \
8634         poolT dim-major plane (transpose + transposed kernel) BIT-IDENTICAL to the SAME host \
8635         twin over {pool_t_rows} rows, incl. the pitch-trap case cap_rows=4096 != n_blocks=1031"
8636    ))
8637}
8638
8639/// PLE n-gram id CACHE oracle (262k perf lane, `plecache`): `host_ngram_ids_cached` vs the
8640/// full `host_ngram_ids` twin, ids compared EXACTLY (they are table row indices — one wrong
8641/// id gathers a different embedding row and the output is fluent and wrong, so there is no
8642/// tolerance to have). Host-only, so it costs nothing and runs on every gate invocation.
8643///
8644/// The cases are the ones a cache gets wrong, not the ones it gets right:
8645/// - **one-token-at-a-time growth** (the decode shape) and **chunked growth** (the prefill
8646///   shape) over the same sequence, interleaved lengths, against a fresh full recompute at
8647///   every length.
8648/// - **EOS inside the sequence**: `shift_right_ignore_eos` resets its segment at an eos, and
8649///   the running `last_eos_inclusive` is the one piece of cross-token state the incremental
8650///   form has to carry. A cache that ignored it would be green on eos-free text.
8651/// - **rewind to a DIVERGING prefix** (the spec-reject shape): extend, then ask for a
8652///   sequence that shares only a prefix. The cache must truncate at the divergence, not at
8653///   the length — a length-only check keeps another sequence's hashes and produces fluent
8654///   output from the wrong rows, which is invisible.
8655/// - **a SHORTER unrelated sequence in the same cache** (state reuse).
8656/// - **eos as the very first token** and **an all-eos sequence** (segment_start edges).
8657pub fn gate_ple_ngram_cache() -> Res<String> {
8658    // Real artifact geometry: max_ngram 3, 16 heads (8 per ngram size), per-head vocab.
8659    let max_ngram = 3usize;
8660    let heads_per_ngram = 8usize;
8661    let total_heads = (max_ngram - 1) * heads_per_ngram;
8662    let multipliers: Vec<i64> = vec![
8663        0x2545_F491_4F6C_DD1D,
8664        0x9E37_79B9_7F4A_7C15u64 as i64,
8665        0x1234_5678_9ABC_DEF1,
8666    ];
8667    let sizes: Vec<i64> = (0..total_heads)
8668        .map(|i| 2_500_012_160 - (i as i64) * 7)
8669        .collect();
8670    let offsets: Vec<i64> = (0..total_heads)
8671        .map(|i| (i as i64) * 2_500_012_160)
8672        .collect();
8673    let eos = 248_046u32;
8674    let full = |ids: &[u32]| -> Vec<i64> {
8675        host_ngram_ids(
8676            ids,
8677            &multipliers,
8678            &sizes,
8679            &offsets,
8680            max_ngram,
8681            heads_per_ngram,
8682            eos,
8683        )
8684    };
8685    let mut lcg = 0x0be1_10ca_u64;
8686    let mut next_tok = move || -> u32 {
8687        lcg = lcg
8688            .wrapping_mul(6364136223846793005)
8689            .wrapping_add(1442695040888963407);
8690        ((lcg >> 33) as u32) % 250_000
8691    };
8692    let mut checks = 0usize;
8693    let run = |label: &str, steps: Vec<Vec<u32>>| -> Res<usize> {
8694        // `steps` are cumulative sequences fed to ONE cache, in order.
8695        let (mut ci, mut ch, mut ce) = (Vec::new(), Vec::new(), -1i64);
8696        let mut n = 0usize;
8697        for seq in &steps {
8698            host_ngram_ids_cached(
8699                &mut ci,
8700                &mut ch,
8701                &mut ce,
8702                seq,
8703                &multipliers,
8704                &sizes,
8705                &offsets,
8706                max_ngram,
8707                heads_per_ngram,
8708                eos,
8709            );
8710            let want = full(seq);
8711            if ci.len() != want.len() {
8712                return Err(format!(
8713                    "plecache oracle {label}: cache has {} ids, twin {} at len {}",
8714                    ci.len(),
8715                    want.len(),
8716                    seq.len()
8717                )
8718                .into());
8719            }
8720            if let Some(i) = ci.iter().zip(&want).position(|(a, b)| a != b) {
8721                return Err(format!(
8722                    "plecache oracle {label}: id {i} differs at len {} (token {}, head {}): \
8723                     cache {} vs twin {}",
8724                    seq.len(),
8725                    i / total_heads,
8726                    i % total_heads,
8727                    ci[i],
8728                    want[i]
8729                )
8730                .into());
8731            }
8732            n += seq.len();
8733        }
8734        Ok(n)
8735    };
8736    // 1. Decode shape: grow one token at a time, eos-free.
8737    {
8738        let base: Vec<u32> = (0..200).map(|_| next_tok()).collect();
8739        let steps: Vec<Vec<u32>> = (1..=base.len()).map(|n| base[..n].to_vec()).collect();
8740        checks += run("decode-growth", steps)?;
8741    }
8742    // 2. Prefill shape: chunked growth with ragged chunk sizes.
8743    {
8744        let base: Vec<u32> = (0..600).map(|_| next_tok()).collect();
8745        let mut steps = Vec::new();
8746        let mut n = 0usize;
8747        for step in [7usize, 1, 64, 3, 128, 2, 200, 195] {
8748            n = (n + step).min(base.len());
8749            steps.push(base[..n].to_vec());
8750        }
8751        checks += run("prefill-chunks", steps)?;
8752    }
8753    // 3. EOS inside the sequence (segment resets), incl. adjacent eos and a trailing eos.
8754    {
8755        let mut base: Vec<u32> = (0..300).map(|_| next_tok()).collect();
8756        for p in [0usize, 1, 2, 37, 38, 100, 101, 102, 299] {
8757            base[p] = eos;
8758        }
8759        let steps: Vec<Vec<u32>> = (1..=base.len()).map(|n| base[..n].to_vec()).collect();
8760        checks += run("eos-segments", steps)?;
8761    }
8762    // 4. All-eos: every position resets its own segment.
8763    {
8764        let base: Vec<u32> = vec![eos; 40];
8765        let steps: Vec<Vec<u32>> = (1..=base.len()).map(|n| base[..n].to_vec()).collect();
8766        checks += run("all-eos", steps)?;
8767    }
8768    // 5. Rewind to a DIVERGING prefix, repeatedly, then past the old length.
8769    {
8770        let a: Vec<u32> = (0..300).map(|_| next_tok()).collect();
8771        let mut b = a.clone();
8772        b[150] = a[150].wrapping_add(1) % 250_000;
8773        let mut c = b.clone();
8774        c[7] = b[7].wrapping_add(3) % 250_000;
8775        let mut d = c.clone();
8776        d.truncate(9);
8777        d.extend((0..100).map(|_| next_tok()));
8778        checks += run(
8779            "rewind-divergent",
8780            vec![
8781                a.clone(),
8782                a[..151].to_vec(),
8783                b.clone(),
8784                b[..8].to_vec(),
8785                c.clone(),
8786                d.clone(),
8787                a.clone(),
8788            ],
8789        )?;
8790    }
8791    // 6. A shorter unrelated sequence in the same cache (state reuse), and back up again.
8792    {
8793        let a: Vec<u32> = (0..250).map(|_| next_tok()).collect();
8794        let mut s: Vec<u32> = (0..11).map(|_| next_tok()).collect();
8795        s[0] = eos;
8796        checks += run("state-reuse", vec![a.clone(), s.clone(), a.clone(), s])?;
8797    }
8798    Ok(format!(
8799        "plecache oracle: incremental n-gram ids EXACT vs the full host_ngram_ids twin over \
8800         {checks} cumulative-sequence comparisons across 6 case families (decode one-at-a-time \
8801         growth, ragged prefill chunks, eos segment resets incl. adjacent + leading + trailing \
8802         eos, all-eos, repeated rewinds to DIVERGING prefixes, and shorter-unrelated-sequence \
8803         state reuse)"
8804    ))
8805}
8806
8807/// SEAM TABLE oracle (host-only, 262k host-lever lane): every `MEMRA_Q4E_SEAMS` name maps to its
8808/// OWN switch, `set_seam` and `seam_state` agree, and arming one seam changes NOTHING else.
8809///
8810/// This exists because the name table was refactored out of `apply_env_seams` into `set_seam` so
8811/// a measurement harness could flip a seam between timed rounds, and three agents add arms to it
8812/// concurrently. The failure mode of a mechanical refactor like that is not a crash: it is one
8813/// arm wired to a neighbour's switch, which arms the wrong seam and produces a fully fluent,
8814/// fully green run measuring something other than what the receipt claims. A copy-paste arm that
8815/// duplicates the line above it is exactly what a per-name distinctness check catches and what
8816/// reading the diff does not.
8817///
8818/// The strong assertion is the CROSS one: for each name, snapshot every other seam's state, flip
8819/// this one, and require that every other state is unchanged. That is what makes it a wiring
8820/// test rather than a smoke test — a table where two names share a switch passes "set then read
8821/// it back" and fails this.
8822pub fn gate_seam_table() -> Res<String> {
8823    // Derived from `seam_names()` — the engine's own list — so adding a seam extends this gate
8824    // automatically instead of silently escaping it. The three-valued names (`idxq`, `longatt`)
8825    // have no boolean `seam_state` and are filtered out here, but they are still required below
8826    // to be ACCEPTED by both entry points.
8827    let all: &[&str] = seam_names();
8828    let boolean: Vec<&str> = all
8829        .iter()
8830        .copied()
8831        .filter(|n| seam_state(n).is_some())
8832        .collect();
8833    // Non-vacuity, and it has to be able to FAIL: a collapsed list would make every assertion
8834    // below pass over nothing. Both bounds are real — the table carries 20+ boolean seams today,
8835    // and at least the two three-valued ones (`idxq`, `longatt`) must be present and filtered
8836    // out — so a list that lost either class trips here instead of reporting a green over a stub.
8837    if boolean.len() < 20 || all.len() < boolean.len() + 2 {
8838        return Err(format!(
8839            "seam-table oracle: refusing to report on {} boolean names out of {} total — the \
8840             seam list collapsed, so every assertion below would be vacuous",
8841            boolean.len(),
8842            all.len()
8843        )
8844        .into());
8845    }
8846    let names: &[&str] = &boolean;
8847    let snapshot = || -> Res<Vec<bool>> {
8848        names
8849            .iter()
8850            .map(|n| {
8851                seam_state(n).ok_or_else(|| {
8852                    Box::<dyn std::error::Error>::from(format!(
8853                        "seam-table oracle: seam_state({n:?}) is None — the name is in set_seam \
8854                         but not in seam_state, so save/restore around a measurement would \
8855                         silently not restore it"
8856                    ))
8857                })
8858            })
8859            .collect()
8860    };
8861    let restore = |v: &[bool]| {
8862        for (n, &b) in names.iter().zip(v) {
8863            set_seam(n, b, None);
8864        }
8865    };
8866    let entry = snapshot()?;
8867    let mut checks = 0usize;
8868    for (i, name) in names.iter().enumerate() {
8869        for &want in &[true, false, true] {
8870            let before = snapshot()?;
8871            if !set_seam(name, want, None) {
8872                restore(&entry);
8873                return Err(format!("seam-table oracle: set_seam({name:?}) refused").into());
8874            }
8875            let after = snapshot()?;
8876            if after[i] != want {
8877                restore(&entry);
8878                return Err(format!(
8879                    "seam-table oracle: set_seam({name:?}, {want}) then seam_state read {} — the \
8880                     two tables disagree on this name",
8881                    after[i]
8882                )
8883                .into());
8884            }
8885            // THE CROSS-CHECK, and the reason this is a wiring test rather than a smoke test: a
8886            // copy-paste arm wired to a neighbour's switch passes "set it then read it back" and
8887            // fails only here.
8888            for (j, other) in names.iter().enumerate() {
8889                if j != i && after[j] != before[j] {
8890                    restore(&entry);
8891                    return Err(format!(
8892                        "seam-table oracle: arming {name:?} also changed {other:?} ({} -> {}) — \
8893                         two names share one switch",
8894                        before[j], after[j]
8895                    )
8896                    .into());
8897                }
8898            }
8899            checks += 1;
8900        }
8901    }
8902    // Every name in the engine's own list — including the three-valued ones — must be accepted by
8903    // both entry points, or `apply_env_seams` would silently ignore a documented seam and the
8904    // run would measure the default while its receipt named the seam.
8905    for name in all {
8906        if !seam_exists(name) {
8907            restore(&entry);
8908            return Err(format!(
8909                "seam-table oracle: seam_names() lists {name:?} but seam_exists refuses it"
8910            )
8911            .into());
8912        }
8913        if !set_seam(name, seam_state(name).unwrap_or(false), None) {
8914            restore(&entry);
8915            return Err(format!(
8916                "seam-table oracle: seam_names() lists {name:?} but set_seam refuses it"
8917            )
8918            .into());
8919        }
8920    }
8921    // An unknown name must be refused by BOTH entry points, not silently accepted.
8922    if seam_exists("definitely-not-a-seam") || set_seam("definitely-not-a-seam", true, None) {
8923        restore(&entry);
8924        return Err("seam-table oracle: an unknown seam name was accepted".into());
8925    }
8926    // And `seam_exists` must apply NOTHING — the property the interleaved-A/B harness relies on
8927    // when it validates a seam name before a 25-80 minute prefill begins.
8928    let before = snapshot()?;
8929    for name in all {
8930        let _ = seam_exists(name);
8931    }
8932    if snapshot()? != before {
8933        restore(&entry);
8934        return Err("seam-table oracle: seam_exists mutated a seam (it must be name-only)".into());
8935    }
8936    restore(&entry);
8937    if snapshot()? != entry {
8938        return Err("seam-table oracle: the gate did not restore the entry state".into());
8939    }
8940    Ok(format!(
8941        "seam-table oracle: {} boolean seam names of {} total, {checks} set/read cycles, each \
8942         verified to change its OWN state and NO other (the cross-check that catches an arm \
8943         wired to a neighbour's switch), every listed name accepted by both entry points, \
8944         unknown names refused by both, seam_exists proven side-effect-free, entry state restored",
8945        names.len(),
8946        all.len()
8947    ))
8948}
8949
8950/// Device QSA indexer top-k SELECTION oracle (262k perf lane): `qsa_index_topk_u32` vs
8951/// `top_blocks_ascending` over the SAME score slab. Contract: the selected block ids AND
8952/// their emitted (ascending) order are EXACT — hard fail on any difference, no tolerance,
8953/// because a differing selection changes which KV rows the attention reads.
8954///
8955/// Geometry is REAL, not tiny: budget 512 (the shipped `budget_blocks`) at block counts up
8956/// to **65,536 — the 262,144-token target window's `fill/4`** — plus non-multiple counts
8957/// and RAGGED batches where each row reads its own prefix of a wider slab, which is the
8958/// exact shape the sub-batched caller produces. The tiny-green/real-broken trap has bitten
8959/// this lane twice; a budget-2 fixture would pass a kernel that cannot address 2^16 blocks.
8960///
8961/// Tie batteries a random draw cannot produce, and they are the point rather than an edge
8962/// case — the pinned rule is score desc then block index ASC:
8963/// - **all-zero**: every score +0.0. The whole selection is decided by the index tiebreak,
8964///   and this class is STRUCTURAL here (the scores are a relu-sum, so a deep row really
8965///   does carry long runs of exact +0.0). A tie-blind kernel is green everywhere else and
8966///   silently wrong here.
8967/// - **duplicate group straddling the budget boundary**: more equal scores than remaining
8968///   slots, so the boundary itself is resolved by index.
8969/// - **signed zeros / subnormals / negative / NaN**: outside the reachable score domain
8970///   (the caller's scores are >= +0.0), but the kernel's key is `f32::total_cmp` verbatim
8971///   over the whole domain, so the oracle proves that rather than assuming the domain.
8972pub fn gate_qsa_index_topk(e: &Engine) -> Res<String> {
8973    let budget = 512usize;
8974    let mut lcg = 0x1d5e_10ca_u64;
8975    let mut rows_checked = 0usize;
8976    let mut deepest = 0usize;
8977    // (label, per-row block counts, slab stride, score generator)
8978    let mut cases: Vec<(String, Vec<usize>, usize, Vec<f32>)> = Vec::new();
8979    let mut next_f32 = move || -> f32 {
8980        lcg = lcg
8981            .wrapping_mul(6364136223846793005)
8982            .wrapping_add(1442695040888963407);
8983        // Relu-sum scores are >= 0 with a heavy mass at exactly +0.0 — draw that shape.
8984        let r = ((lcg >> 33) as u32) % 1000;
8985        if r < 250 { 0.0 } else { (r as f32) / 250.0 }
8986    };
8987    for (label, counts) in [
8988        ("real-262k-depth", vec![65_536usize]),
8989        ("real-131k-depth", vec![32_768usize, 32_768]),
8990        ("shallow", vec![513usize, 1_031, 4_096]),
8991        ("ragged-batch", vec![2_049usize, 8_191, 65_536, 4_097]),
8992    ] {
8993        let stride = *counts.iter().max().unwrap();
8994        let slab: Vec<f32> = (0..counts.len() * stride).map(|_| next_f32()).collect();
8995        cases.push((label.to_string(), counts, stride, slab));
8996    }
8997    // all-zero: index tiebreak alone decides the whole selection.
8998    cases.push((
8999        "all-zero".into(),
9000        vec![65_536usize],
9001        65_536,
9002        vec![0.0f32; 65_536],
9003    ));
9004    // duplicate group straddling the boundary: 600 equal scores for the last 500 slots.
9005    {
9006        let n = 4_096usize;
9007        let mut v = vec![0.0f32; n];
9008        for (i, slot) in v.iter_mut().enumerate() {
9009            *slot = if i < 12 {
9010                100.0 - i as f32
9011            } else if i % 7 == 0 {
9012                2.5 // ~585 exact duplicates, straddling slot 512
9013            } else {
9014                (i % 3) as f32 * 0.25
9015            };
9016        }
9017        cases.push(("dup-straddle".into(), vec![n], n, v));
9018    }
9019    // Signed zeros, subnormals, negatives and NaN: the total_cmp domain, not the score
9020    // domain. total_cmp orders -0.0 below +0.0 and every NaN by its sign bit.
9021    {
9022        let n = 2_048usize;
9023        let mut v = vec![0.0f32; n];
9024        for (i, slot) in v.iter_mut().enumerate() {
9025            *slot = match i % 8 {
9026                0 => 0.0,
9027                1 => -0.0,
9028                2 => f32::from_bits(1),  // smallest positive subnormal
9029                3 => -f32::from_bits(1), // smallest negative subnormal
9030                4 => -(i as f32) * 0.5,
9031                5 => f32::NAN,
9032                6 => -f32::NAN,
9033                _ => (i % 5) as f32,
9034            };
9035        }
9036        cases.push(("total-cmp-domain".into(), vec![n], n, v));
9037    }
9038    for (label, counts, stride, slab) in &cases {
9039        let scores = e.htod(slab)?;
9040        let picked = launch_qsa_index_topk(e, &scores, counts, *stride, budget)?;
9041        if picked.len() != counts.len() {
9042            return Err(format!("idxsel oracle {label}: {} rows back", picked.len()).into());
9043        }
9044        for (r, &complete) in counts.iter().enumerate() {
9045            let row = &slab[r * *stride..r * *stride + complete];
9046            let twin = top_blocks_ascending(row, budget, 1);
9047            if twin != picked[r] {
9048                let first = twin
9049                    .iter()
9050                    .zip(picked[r].iter())
9051                    .position(|(a, b)| a != b)
9052                    .unwrap_or(twin.len().min(picked[r].len()));
9053                return Err(format!(
9054                    "idxsel oracle {label}: selection differs at row {r} (blocks {complete}), \
9055                     first differing slot {first}: host {:?} vs device {:?}",
9056                    twin.get(first),
9057                    picked[r].get(first)
9058                )
9059                .into());
9060            }
9061            rows_checked += 1;
9062            deepest = deepest.max(complete);
9063        }
9064    }
9065    Ok(format!(
9066        "qsa-index-topk oracle: device selection ids + ASCENDING order EXACT vs \
9067         top_blocks_ascending over {rows_checked} rows / {} cases at budget {budget}, \
9068         deepest {deepest} blocks (= the 262,144-token window), incl. the all-zero, \
9069         boundary-straddling-duplicate and total_cmp-domain (signed zero / subnormal / \
9070         negative / NaN) tie classes",
9071        cases.len()
9072    ))
9073}
9074
9075/// Device-router oracle at REAL geometry (devtwin lane): `qwen4exp_route_topk_f32` vs
9076/// `host_route_softmax_topk` on the SAME logits. Contract: the selection (ids AND their
9077/// emitted order — the combine reads slots sequentially) is EXACT, hard fail on any
9078/// mismatch; weights within a documented ULP bound (exp is the one op not bit-pinned to
9079/// host libm — kernel doc), worst observed printed in the receipt. Rows include the tie
9080/// batteries a random draw cannot produce: duplicate-logit groups STRADDLING the top-k
9081/// boundary (weight ties resolve by index — the rule a logits-ordered top-k would get
9082/// wrong), an all-equal row, and underflow rows (subnormal/zero weight ties). The renorm
9083/// denominator floor is unbindable on softmax geometry (top-k sum >= k/experts — see
9084/// ROUTE_DENOM_FLOOR) so it carries no arm; the twin computes the same fmaxf.
9085pub fn gate_route_kernel(e: &Engine) -> Res<String> {
9086    let mut lcg = 0x00de_7710_u64;
9087    let mut next_f32 = move || -> f32 {
9088        lcg = lcg
9089            .wrapping_mul(6364136223846793005)
9090            .wrapping_add(1442695040888963407);
9091        (((lcg >> 33) as u32) % 8000) as f32 / 200.0 - 20.0 // router-logit-scale [-20, 20)
9092    };
9093    const ULP_BOUND: u32 = 2;
9094    let mut worst_ulp: u32 = 0;
9095    let mut rows_checked = 0usize;
9096    let run = |e: &Engine,
9097               label: &str,
9098               logits_host: &[f32],
9099               experts: usize,
9100               selected: usize,
9101               rows: usize,
9102               worst_ulp: &mut u32|
9103     -> Res<()> {
9104        let logits = e.htod(logits_host)?;
9105        let mut sel = e.alloc_uninit::<i32>(rows * selected)?;
9106        let mut w = e.uninit(rows * selected)?;
9107        let mut tok = e.alloc_uninit::<i32>(rows * selected)?;
9108        launch_route_topk(
9109            e,
9110            &logits,
9111            &mut sel,
9112            &mut w,
9113            Some((&mut tok, 3)),
9114            experts,
9115            selected,
9116            rows,
9117        )?;
9118        let sel_h = e.gpu.stream().clone_dtoh(&sel.slice(0..rows * selected))?;
9119        let w_h = e.dtoh(&w)?;
9120        let tok_h = e.gpu.stream().clone_dtoh(&tok.slice(0..rows * selected))?;
9121        let k = selected.min(experts);
9122        for row in 0..rows {
9123            let twin =
9124                host_route_softmax_topk(&logits_host[row * experts..(row + 1) * experts], selected);
9125            if twin.len() != k {
9126                return Err(format!("route oracle {label}: host twin width {}", twin.len()).into());
9127            }
9128            for (j, &(idx, wt)) in twin.iter().enumerate() {
9129                let ds = sel_h[row * selected + j];
9130                let dw = w_h[row * selected + j];
9131                if ds != idx as i32 {
9132                    return Err(format!(
9133                        "route oracle {label}: selection mismatch row {row} slot {j}: \
9134                         device {ds} vs host {idx}"
9135                    )
9136                    .into());
9137                }
9138                let ulp = (dw.to_bits() as i64 - wt.to_bits() as i64).unsigned_abs();
9139                let ulp = u32::try_from(ulp).unwrap_or(u32::MAX);
9140                if ulp > ULP_BOUND {
9141                    return Err(format!(
9142                        "route oracle {label}: weight ULP {ulp} > {ULP_BOUND} at row {row} \
9143                         slot {j}: device {dw:e} vs host {wt:e}"
9144                    )
9145                    .into());
9146                }
9147                *worst_ulp = (*worst_ulp).max(ulp);
9148                if tok_h[row * selected + j] != (3 + row) as i32 {
9149                    return Err(format!(
9150                        "route oracle {label}: tok map wrong at row {row} slot {j}"
9151                    )
9152                    .into());
9153                }
9154            }
9155        }
9156        Ok(())
9157    };
9158    // Real geometry, random router-scale logits, batched rows (the verify shape).
9159    let (experts, selected) = (512usize, 10usize);
9160    for rows in [1usize, 6, 16] {
9161        let logits: Vec<f32> = (0..rows * experts).map(|_| next_f32()).collect();
9162        run(e, "real", &logits, experts, selected, rows, &mut worst_ulp)?;
9163        rows_checked += rows;
9164    }
9165    // Tie batteries (single rows).
9166    let mut tie_rows: Vec<(String, Vec<f32>)> = Vec::new();
9167    {
9168        // A 12-wide duplicate group straddling the top-10 boundary at positions 4..16:
9169        // host keeps the six lowest indices of the group after the four strict leaders.
9170        let mut v: Vec<f32> = (0..experts).map(|i| -30.0 - (i as f32) * 0.01).collect();
9171        for (rank, slot) in [40usize, 7, 300, 11].iter().enumerate() {
9172            v[*slot] = 10.0 - rank as f32;
9173        }
9174        for slot in [500usize, 3, 77, 210, 8, 401, 129, 64, 255, 380, 17, 450] {
9175            v[slot] = 2.5;
9176        }
9177        tie_rows.push(("dup-straddle".into(), v));
9178        // All-equal: the selection is indices 0..k by the tie rule alone.
9179        tie_rows.push(("all-equal".into(), vec![0.125f32; experts]));
9180        // Underflow: one dominant logit, the rest deep negative — weights tie at
9181        // 0.0/subnormal and the boundary resolves by index among bit-equal weights.
9182        let mut v = vec![-200.0f32; experts];
9183        v[100] = 5.0;
9184        for (i, slot) in [479usize, 2, 33].iter().enumerate() {
9185            v[*slot] = -80.0 - i as f32; // subnormal-weight class
9186        }
9187        tie_rows.push(("underflow".into(), v));
9188    }
9189    for (label, v) in &tie_rows {
9190        run(e, label, v, experts, selected, 1, &mut worst_ulp)?;
9191        rows_checked += 1;
9192    }
9193    // Off-real geometry (the envelope's edges): small expert counts, selected == experts.
9194    for (ex, se) in [(64usize, 4usize), (16, 16), (128, 32)] {
9195        let logits: Vec<f32> = (0..3 * ex).map(|_| next_f32()).collect();
9196        run(e, "geom", &logits, ex, se, 3, &mut worst_ulp)?;
9197        rows_checked += 3;
9198    }
9199    Ok(format!(
9200        "route oracle: device selection ids+order EXACT vs host twin over {rows_checked} rows \
9201         (real 512/10 + tie straddle/all-equal/underflow + geometry edges), worst weight \
9202         ULP {worst_ulp} (bound {ULP_BOUND}), tok map exact"
9203    ))
9204}
9205
9206pub fn gate_gdn_step_kernels(e: &Engine) -> Res<String> {
9207    let mut lcg = 0x0bad_cafe_u64;
9208    let mut next_f32 = move || -> f32 {
9209        lcg = lcg
9210            .wrapping_mul(6364136223846793005)
9211            .wrapping_add(1442695040888963407);
9212        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
9213    };
9214    let mut worst = 0.0f32;
9215    for (nk, nv, hk, hv) in [(16usize, 48usize, 128usize, 128usize), (2, 4, 32, 8)] {
9216        let conv_dim = 2 * nk * hk + nv * hv;
9217        let qkv_host: Vec<f32> = (0..conv_dim).map(|_| next_f32()).collect();
9218        let g_log_host: Vec<f32> = (0..nv).map(|_| next_f32().abs() * -2.0).collect();
9219        let beta_host: Vec<f32> = (0..nv).map(|_| next_f32()).collect();
9220        let state_host: Vec<f32> = (0..nv * hv * hk).map(|_| next_f32()).collect();
9221        let qkv = e.htod(&qkv_host)?;
9222        let g_log = e.htod(&g_log_host)?;
9223        let beta = e.htod(&beta_host)?;
9224        let scale = 1.0 / (hk as f32).sqrt();
9225        let eps = 1e-6f32;
9226        let mut state_a = e.htod(&state_host)?;
9227        let mut o_a = e.zeros(nv * hv)?;
9228        launch_gdn_scan(
9229            e,
9230            &qkv,
9231            &g_log,
9232            &beta,
9233            &mut state_a,
9234            &mut o_a,
9235            nk,
9236            nv,
9237            hk,
9238            hv,
9239            1,
9240            scale,
9241            eps,
9242        )?;
9243        let mut state_b = e.htod(&state_host)?;
9244        let mut o_b = e.zeros(nv * hv)?;
9245        launch_gdn_scan_step(
9246            e,
9247            &qkv,
9248            &g_log,
9249            &beta,
9250            &mut state_b,
9251            &mut o_b,
9252            nk,
9253            nv,
9254            hk,
9255            hv,
9256            scale,
9257            eps,
9258        )?;
9259        for (name, reference, candidate) in [
9260            ("o", e.dtoh(&o_a)?, e.dtoh(&o_b)?),
9261            ("state", e.dtoh(&state_a)?, e.dtoh(&state_b)?),
9262        ] {
9263            for (i, (&r, &c)) in reference.iter().zip(&candidate).enumerate() {
9264                let rel = (r - c).abs() / r.abs().max(1.0);
9265                if rel > worst {
9266                    worst = rel;
9267                }
9268                if rel > 1e-4 {
9269                    return Err(format!(
9270                        "gdn-step oracle: nk{nk}/nv{nv}/hk{hk}/hv{hv} {name} idx {i}: \
9271                         naive {r} step {c} (rel {rel:.3e})"
9272                    )
9273                    .into());
9274                }
9275            }
9276        }
9277    }
9278    // (b) fused norm+gate bit-identity at the artifact norm shape (48 rows of 128).
9279    let (rows, cols) = (48usize, 128usize);
9280    let x = e.htod(&(0..rows * cols).map(|_| next_f32()).collect::<Vec<_>>())?;
9281    let w = e.htod(&(0..cols).map(|_| next_f32()).collect::<Vec<_>>())?;
9282    let z = e.htod(&(0..rows * cols).map(|_| next_f32()).collect::<Vec<_>>())?;
9283    let eps = 1e-6f32;
9284    let mut normed = e.zeros(rows * cols)?;
9285    e.rms_norm(&x, &w, &mut normed, cols, rows, eps)?;
9286    let mut sg = e.zeros(rows * cols)?;
9287    e.sigmoid(&z, &mut sg, rows * cols)?;
9288    let mut chain = e.zeros(rows * cols)?;
9289    e.mul(&normed, &sg, &mut chain, rows * cols)?;
9290    let mut fused = e.zeros(rows * cols)?;
9291    launch_rms_sigmul(e, &x, &w, &z, &mut fused, cols, rows, eps)?;
9292    let (chain_h, fused_h) = (e.dtoh(&chain)?, e.dtoh(&fused)?);
9293    for (i, (&a, &b)) in chain_h.iter().zip(&fused_h).enumerate() {
9294        if a.to_bits() != b.to_bits() {
9295            return Err(format!(
9296                "rms_sigmul oracle: idx {i} not bit-identical: chain {a:?} fused {b:?}"
9297            )
9298            .into());
9299        }
9300    }
9301    Ok(format!(
9302        "gdn-step kernel oracle: scan step twin worst rel {worst:.3e} over artifact + \
9303         hk32 geometries; rms_sigmul bit-identical to the norm/sigmoid/mul chain ({rows}x{cols})"
9304    ))
9305}
9306
9307pub fn gate_qmatvec_bf16(e: &Engine) -> Res<String> {
9308    let mut lcg = 0x9e37_79b9_u64;
9309    let mut next_u32 = move || -> u32 {
9310        lcg = lcg
9311            .wrapping_mul(6364136223846793005)
9312            .wrapping_add(1442695040888963407);
9313        (lcg >> 33) as u32
9314    };
9315    let mut worst = (0.0f32, 0.0f32);
9316    for (mode, batch, t, out_f, in_f, x_bstride) in [
9317        ("per_batch_x", 3usize, 2usize, 5usize, 48usize, 2 * 48usize),
9318        ("shared_x", 4, 3, 7, 16, 0usize),
9319    ] {
9320        // bf16 weights minted as bf16 BYTES first (so the host twin widens the same
9321        // values the kernel reads), incl. sign and small-exponent coverage.
9322        let w_elems = batch * out_f * in_f;
9323        let mut w_bytes = Vec::with_capacity(w_elems * 2);
9324        let mut w_host = Vec::with_capacity(w_elems);
9325        for _ in 0..w_elems {
9326            // Magnitude bits below 0x4000 (= 2.0): denormals through ~2.0, signed —
9327            // keeps a 48-term dot far from overflow while covering the exponent range.
9328            let h = ((next_u32() % 0x4000) as u16) | (((next_u32() & 1) as u16) << 15);
9329            w_bytes.extend_from_slice(&h.to_le_bytes());
9330            w_host.push(f32::from_bits(u32::from(h) << 16));
9331        }
9332        let x_rows = if x_bstride == 0 { t } else { batch * t };
9333        let x_host: Vec<f32> = (0..x_rows * in_f)
9334            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
9335            .collect();
9336        let w_dev = e.htod_bytes(&w_bytes)?;
9337        let x_dev = e.htod(&x_host)?;
9338        let mut y_dev = e.uninit(batch * t * out_f)?;
9339        launch_qmatvec_bf16w(
9340            e,
9341            &w_dev,
9342            &x_dev,
9343            &mut y_dev,
9344            in_f,
9345            out_f,
9346            t,
9347            batch,
9348            out_f * in_f,
9349            x_bstride,
9350            in_f,
9351            t * out_f,
9352        )?;
9353        let y = e.dtoh(&y_dev)?;
9354        for b in 0..batch {
9355            for tok in 0..t {
9356                let xrow = &x_host[b * x_bstride + tok * in_f..][..in_f];
9357                for o in 0..out_f {
9358                    let wrow = &w_host[(b * out_f + o) * in_f..][..in_f];
9359                    let mut want = 0.0f32;
9360                    for i in 0..in_f {
9361                        want += wrow[i] * xrow[i];
9362                    }
9363                    let got = y[(b * t + tok) * out_f + o];
9364                    let abs = (want - got).abs();
9365                    let rel = abs / want.abs().max(1.0);
9366                    worst.0 = worst.0.max(abs);
9367                    worst.1 = worst.1.max(rel);
9368                    if rel > 1e-5 {
9369                        return Err(format!(
9370                            "bf16-matvec oracle: {mode} b {b} tok {tok} row {o}: want {want} \
9371                             got {got} (rel {rel:.3e})"
9372                        )
9373                        .into());
9374                    }
9375                }
9376            }
9377        }
9378    }
9379    // MT weight-shared mode (mtp-spec verify): the multi-token kernel must be
9380    // BIT-IDENTICAL per (row, token) to the per-token grid on the same operands —
9381    // artifact-class geometry (in_f % 8, wide rows) + odd t.
9382    {
9383        let (out_f, in_f, t) = (33usize, 64usize, 5usize);
9384        let w_elems = out_f * in_f;
9385        let mut w_bytes = Vec::with_capacity(w_elems * 2);
9386        for _ in 0..w_elems {
9387            let h = ((next_u32() % 0x4000) as u16) | (((next_u32() & 1) as u16) << 15);
9388            w_bytes.extend_from_slice(&h.to_le_bytes());
9389        }
9390        let x_host: Vec<f32> = (0..t * in_f)
9391            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
9392            .collect();
9393        let w_dev = e.htod_bytes(&w_bytes)?;
9394        let x_dev = e.htod(&x_host)?;
9395        let mut y_grid = e.uninit(t * out_f)?;
9396        launch_qmatvec_bf16w(
9397            e,
9398            &w_dev,
9399            &x_dev,
9400            &mut y_grid,
9401            in_f,
9402            out_f,
9403            t,
9404            1,
9405            0,
9406            0,
9407            in_f,
9408            0,
9409        )?;
9410        let mut y_mt = e.uninit(t * out_f)?;
9411        launch_qmatvec_bf16w_mt(e, &w_dev, 0, &x_dev, &mut y_mt, in_f, out_f, t)?;
9412        let (a, b) = (e.dtoh(&y_grid)?, e.dtoh(&y_mt)?);
9413        for (i, (&x1, &x2)) in a.iter().zip(&b).enumerate() {
9414            if x1.to_bits() != x2.to_bits() {
9415                return Err(format!(
9416                    "bf16-matvec mt oracle: idx {i}: grid {x1} vs mt {x2} NOT bit-identical"
9417                )
9418                .into());
9419            }
9420        }
9421    }
9422    // SEL mode (devtwin stage 2, the DeviceBf16 draft bank): the device-selected
9423    // grouped kernel must be BIT-IDENTICAL per slot to the per-slot off_into chain on
9424    // the same bank + sel (duplicate slots included), in BOTH stride shapes — shared x
9425    // (gate/up) and per-slot x rows (down).
9426    {
9427        let (experts, out_f, in_f, n_sel) = (16usize, 24usize, 32usize, 6usize);
9428        let w_elems = experts * out_f * in_f;
9429        let mut w_bytes = Vec::with_capacity(w_elems * 2);
9430        for _ in 0..w_elems {
9431            let h = ((next_u32() % 0x4000) as u16) | (((next_u32() & 1) as u16) << 15);
9432            w_bytes.extend_from_slice(&h.to_le_bytes());
9433        }
9434        let sel_host: Vec<i32> = vec![7, 0, 15, 7, 3, 9]; // duplicate expert on purpose
9435        let bank = e.htod_bytes(&w_bytes)?;
9436        let sel = e.htod_i32(&sel_host)?;
9437        for (label, x_rows, x_sstride) in [("shared-x", 1usize, 0usize), ("slot-x", n_sel, in_f)] {
9438            let x_host: Vec<f32> = (0..x_rows * in_f)
9439                .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
9440                .collect();
9441            let x_dev = e.htod(&x_host)?;
9442            let mut y_sel = e.uninit(n_sel * out_f)?;
9443            launch_qmatvec_bf16w_sel(
9444                e, &bank, &sel, 0, &x_dev, 0, x_sstride, &mut y_sel, n_sel, in_f, out_f,
9445            )?;
9446            let mut y_ref = e.uninit(n_sel * out_f)?;
9447            for (slot, &eid) in sel_host.iter().enumerate() {
9448                launch_qmatvec_bf16w_off_into(
9449                    e,
9450                    &bank,
9451                    eid as usize * out_f,
9452                    &x_dev,
9453                    slot * x_sstride,
9454                    &mut y_ref,
9455                    slot * out_f,
9456                    in_f,
9457                    out_f,
9458                )?;
9459            }
9460            let (a, b) = (e.dtoh(&y_sel)?, e.dtoh(&y_ref)?);
9461            for (i, (&x1, &x2)) in a.iter().zip(&b).enumerate() {
9462                if x1.to_bits() != x2.to_bits() {
9463                    return Err(format!(
9464                        "bf16-matvec sel oracle ({label}): idx {i}: sel {x1} vs off_into {x2} \
9465                         NOT bit-identical"
9466                    )
9467                    .into());
9468                }
9469            }
9470        }
9471    }
9472    Ok(format!(
9473        "bf16-matvec kernel oracle: worst abs {:.3e} rel {:.3e} over per-batch + shared-x \
9474         modes, batch>1, t>1, signed/denormal bf16; mt weight-shared twin BIT-IDENTICAL \
9475         at t 5; sel grouped twin BIT-IDENTICAL to the off_into chain (shared-x + slot-x, \
9476         duplicate slots)",
9477        worst.0, worst.1
9478    ))
9479}
9480
9481/// Dequantize ONE expert of a device-resident modelopt-NVFP4 stacked bank to f32.
9482///
9483/// The existing dsv4 kernel (`memra_dsv4_nvfp4_deq_bf16`) emits bf16, so the macro is
9484/// NOT passed into it: e2m1 × e4m3 products carry ≤ 6 significand bits and are EXACT in
9485/// bf16, and the macro multiplies AFTER the exact f32 upcast. That reproduces the host
9486/// decoder (`dsv4::dequant_nvfp4_expert`: `(code * scale) * scale_2`, one f32 rounding)
9487/// bit-for-bit for ANY finite macro — the real qwen4_exp mint ships modelopt's
9488/// amax-derived NON-pow2 `weight_scale_2` (measured 5.9945243e-5), which the dsv4-era
9489/// in-kernel-macro chain would round in bf16 (hence its pow2 law; not needed here).
9490fn dequant_nvfp4_expert_f32(
9491    e: &Engine,
9492    codes: &CudaSlice<u8>,
9493    scales: &CudaSlice<u8>,
9494    macro_scale: f32,
9495    expert: usize,
9496    rows: usize,
9497    cols: usize,
9498) -> Res<CudaSlice<f32>> {
9499    let wbytes = rows * cols / 2;
9500    let sbytes = rows * cols / 16;
9501    let bf = e.alloc_u8(rows * cols * 2)?;
9502    let stream = e.gpu.stream();
9503    let wp = (codes.device_ptr(&stream).0 as usize + expert * wbytes) as *const c_void;
9504    let scp = (scales.device_ptr(&stream).0 as usize + expert * sbytes) as *const c_void;
9505    let dst = bf.device_ptr(&stream).0 as usize as *mut c_void;
9506    let rc = unsafe {
9507        crate::dsv4_ffi::memra_dsv4_nvfp4_deq_bf16(
9508            wp,
9509            scp,
9510            1.0, // macro applied post-upcast in f32 (see the doc comment)
9511            rows as i32,
9512            cols as i32,
9513            dst,
9514            stream.cu_stream() as *mut c_void,
9515        )
9516    };
9517    if rc != 0 {
9518        return Err(format!("memra_dsv4_nvfp4_deq_bf16 rc={rc}").into());
9519    }
9520    let mut out = e.bf16_to_f32(&bf.slice(0..rows * cols * 2), rows * cols)?;
9521    if macro_scale != 1.0 {
9522        e.scale_inplace(&mut out, macro_scale, rows * cols)?;
9523    }
9524    Ok(out)
9525}
9526
9527// ---------------------------------------------------------------- loading
9528
9529fn expect(weights: &ReferenceWeights, id: &TensorId) -> Res<ReferenceTensor> {
9530    weights
9531        .get(id)
9532        .cloned()
9533        .ok_or_else(|| format!("qwen4exp_gpu: missing weight {id:?}").into())
9534}
9535
9536fn family_id(key: String) -> TensorId {
9537    TensorId::Family {
9538        family: "qwen4_exp",
9539        key,
9540    }
9541}
9542
9543fn layer_id(index: u32, tensor: LayerTensor) -> TensorId {
9544    TensorId::Layer { index, tensor }
9545}
9546
9547fn upload(e: &Engine, tensor: &ReferenceTensor) -> Res<CudaSlice<f32>> {
9548    e.htod(&tensor.data)
9549}
9550
9551/// Slice a [rows, wide] row-major tensor into per-stream [rows, hidden] column blocks.
9552fn split_columns(data: &[f32], rows: usize, streams: usize, hidden: usize) -> Vec<Vec<f32>> {
9553    let wide = streams * hidden;
9554    (0..streams)
9555        .map(|s| {
9556            let mut out = Vec::with_capacity(rows * hidden);
9557            for row in 0..rows {
9558                out.extend_from_slice(
9559                    &data[row * wide + s * hidden..row * wide + (s + 1) * hidden],
9560                );
9561            }
9562            out
9563        })
9564        .collect()
9565}
9566
9567/// Slice a [wide, cols] row-major tensor into per-stream [hidden, cols] row blocks.
9568fn split_rows(data: &[f32], streams: usize, hidden: usize, cols: usize) -> Vec<Vec<f32>> {
9569    (0..streams)
9570        .map(|s| data[s * hidden * cols..(s + 1) * hidden * cols].to_vec())
9571        .collect()
9572}
9573
9574fn load_gate(
9575    e: &Engine,
9576    weights: &ReferenceWeights,
9577    prefix: &str,
9578    sublayer: &str,
9579    streams: usize,
9580    hidden: usize,
9581    rank: usize,
9582    with_inject: bool,
9583) -> Res<GateW> {
9584    let wide = streams * hidden;
9585    let norm = expect(
9586        weights,
9587        &family_id(format!("{prefix}{sublayer}hc_norm.weight")),
9588    )?;
9589    let down = expect(
9590        weights,
9591        &family_id(format!("{prefix}{sublayer}input_mix_weight_down.weight")),
9592    )?;
9593    let up = expect(
9594        weights,
9595        &family_id(format!("{prefix}{sublayer}input_mix_weight_up.weight")),
9596    )?;
9597    if norm.data.len() != wide || down.data.len() != rank * wide || up.data.len() != wide * rank {
9598        return Err(format!("qwen4exp_gpu: gate {prefix}{sublayer} shape mismatch").into());
9599    }
9600    let norm_slices = split_rows(&norm.data, streams, hidden, 1);
9601    let down_slices = split_columns(&down.data, rank, streams, hidden);
9602    let up_slices = split_rows(&up.data, streams, hidden, rank);
9603    // bf16 trunk twins, STACKED across streams so the fused gate runs one batched
9604    // launch per projection (guards in `bf16_twin`).
9605    let stack = |slices: &[Vec<f32>]| -> Vec<f32> {
9606        let mut out = Vec::with_capacity(slices.len() * slices[0].len());
9607        for s in slices {
9608            out.extend_from_slice(s);
9609        }
9610        out
9611    };
9612    let down_b16 = bf16_twin(e, &stack(&down_slices), hidden)?;
9613    let up_b16 = bf16_twin(e, &stack(&up_slices), rank)?;
9614    let (inject, inject_b16) = if with_inject {
9615        let inject = expect(
9616            weights,
9617            &family_id(format!("{prefix}{sublayer}block_inject_weight.weight")),
9618        )?;
9619        if inject.data.len() != streams * wide {
9620            return Err(format!("qwen4exp_gpu: inject {prefix}{sublayer} shape mismatch").into());
9621        }
9622        // Kept whole: the fused inject kernel walks [s][s2*hidden + d] directly, which is
9623        // exactly this tensor's row-major layout against the stream-major normed planes.
9624        (
9625            Some(e.htod(&inject.data)?),
9626            bf16_twin(e, &inject.data, hidden)?,
9627        )
9628    } else {
9629        (None, None)
9630    };
9631    Ok(GateW {
9632        norm_stack: e.htod(&stack(&norm_slices))?,
9633        norm: norm_slices
9634            .into_iter()
9635            .map(|v| e.htod(&v))
9636            .collect::<Result<_, _>>()?,
9637        down: down_slices
9638            .into_iter()
9639            .map(|v| e.htod(&v))
9640            .collect::<Result<_, _>>()?,
9641        up: up_slices
9642            .into_iter()
9643            .map(|v| e.htod(&v))
9644            .collect::<Result<_, _>>()?,
9645        inject,
9646        down_b16,
9647        up_b16,
9648        inject_b16,
9649    })
9650}
9651
9652/// Loader-side carriers that bypass `ReferenceWeights` (the real artifact cannot
9653/// materialize them host-f32): device-bound expert banks and host n-gram tables,
9654/// keyed by trunk layer index.
9655#[derive(Default)]
9656pub struct ExternalParts {
9657    expert_banks: std::collections::BTreeMap<u32, ExpertBank>,
9658    ngram_tables: std::collections::BTreeMap<u32, NgramTable>,
9659}
9660
9661/// Build one decoder layer's engine-resident weights from TensorId-keyed reference
9662/// weights — shared by the trunk loop and the MTP draft block (mtp-spec lane), which is
9663/// the same layer schema at global index n_trunk under the `mtp.layers.{depth}.` prefix.
9664#[allow(clippy::too_many_arguments)]
9665fn build_layer_w(
9666    e: &Engine,
9667    weights: &ReferenceWeights,
9668    layer: &memra_gguf::model_plan::LayerPlan,
9669    prefix: &str,
9670    streams: usize,
9671    hidden: usize,
9672    rank: usize,
9673    bank_override: Option<ExpertBank>,
9674    table_override: Option<NgramTable>,
9675) -> Res<LayerW> {
9676    let ResidualTopology::GatedResidual { .. } = layer.residual else {
9677        return Err(format!("qwen4exp_gpu: layer {} is not gated-residual", layer.index).into());
9678    };
9679    let attn_gate = load_gate(
9680        e,
9681        weights,
9682        prefix,
9683        "attn_hyper_connection.",
9684        streams,
9685        hidden,
9686        rank,
9687        true,
9688    )?;
9689    let mlp_gate = load_gate(
9690        e,
9691        weights,
9692        prefix,
9693        "mlp_hyper_connection.",
9694        streams,
9695        hidden,
9696        rank,
9697        true,
9698    )?;
9699    let mixer = match &layer.attention {
9700        AttentionPlan::Full(attn) => {
9701            let overlay = layer.sparse_overlay.ok_or_else(|| {
9702                format!(
9703                    "qwen4exp_gpu: QSA layer {} has no indexer overlay",
9704                    layer.index
9705                )
9706            })?;
9707            // Plain partial rope or YaRN (long-context lane); anything else refuses in
9708            // `build_yarn`.
9709            let yarn = build_yarn(e, &attn.rope, Some(&overlay), layer.index)?;
9710            // The eager attention path lays q/k/v/attended out with ONE head_dim
9711            // and gates full-width; unequal key/value dims would be silently
9712            // wrong, so refuse (family: 256/256).
9713            if attn.key_head_dim != attn.value_head_dim {
9714                return Err(format!(
9715                    "qwen4exp_gpu: layer {} key_head_dim {} != value_head_dim {}",
9716                    layer.index, attn.key_head_dim, attn.value_head_dim
9717                )
9718                .into());
9719            }
9720            let load_opt_norm = |tensor: LayerTensor| -> Res<Option<CudaSlice<f32>>> {
9721                match weights.get(&layer_id(layer.index, tensor)) {
9722                    Some(t) => Ok(Some(e.htod(&t.data)?)),
9723                    None if attn.qk_norm == TensorPresence::Required => {
9724                        Err(format!("qwen4exp_gpu: layer {} missing qk norm", layer.index).into())
9725                    }
9726                    None => Ok(None),
9727                }
9728            };
9729            let wq_t = expect(weights, &layer_id(layer.index, LayerTensor::Query))?;
9730            let wk_t = expect(weights, &layer_id(layer.index, LayerTensor::Key))?;
9731            let wv_t = expect(weights, &layer_id(layer.index, LayerTensor::Value))?;
9732            let wo_t = expect(
9733                weights,
9734                &layer_id(layer.index, LayerTensor::AttentionOutput),
9735            )?;
9736            let o_in = (attn.query_heads * attn.key_head_dim) as usize;
9737            MixerW::Qsa(QsaW {
9738                attn: attn.clone(),
9739                overlay,
9740                yarn,
9741                proj_b16: bf16_stack_twin(e, &[&wq_t.data, &wk_t.data, &wv_t.data], hidden)?,
9742                wo_b16: bf16_twin(e, &wo_t.data, o_in)?,
9743                wq: upload(e, &wq_t)?,
9744                wk: upload(e, &wk_t)?,
9745                wv: upload(e, &wv_t)?,
9746                wo: upload(e, &wo_t)?,
9747                q_norm: load_opt_norm(LayerTensor::QueryNorm)?,
9748                k_norm: load_opt_norm(LayerTensor::KeyNorm)?,
9749                idx_proj: upload(
9750                    e,
9751                    &expect(
9752                        weights,
9753                        &family_id(format!("{prefix}self_attn.indexer.index_qk_proj.weight")),
9754                    )?,
9755                )?,
9756                idx_q_norm: expect(
9757                    weights,
9758                    &family_id(format!("{prefix}self_attn.indexer.q_layernorm.weight")),
9759                )?
9760                .data,
9761                idx_k_norm: expect(
9762                    weights,
9763                    &family_id(format!("{prefix}self_attn.indexer.k_layernorm.weight")),
9764                )?
9765                .data,
9766            })
9767        }
9768        AttentionPlan::GatedDeltaNet(gdn) => {
9769            let qkv_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnQkv))?;
9770            let z_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnGate))?;
9771            let beta_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnBeta))?;
9772            let alpha_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnAlpha))?;
9773            let out_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnOutput))?;
9774            let o_in = (gdn.value_heads * gdn.value_head_dim) as usize;
9775            MixerW::Gdn(GdnW {
9776                plan: *gdn,
9777                proj_b16: bf16_stack_twin(
9778                    e,
9779                    &[&qkv_t.data, &z_t.data, &beta_t.data, &alpha_t.data],
9780                    hidden,
9781                )?,
9782                out_b16: bf16_twin(e, &out_t.data, o_in)?,
9783                qkv: upload(e, &qkv_t)?,
9784                z: upload(e, &z_t)?,
9785                beta: upload(e, &beta_t)?,
9786                alpha: upload(e, &alpha_t)?,
9787                conv_w: upload(
9788                    e,
9789                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnConv1d))?,
9790                )?,
9791                a: upload(
9792                    e,
9793                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnA))?,
9794                )?,
9795                dt: upload(
9796                    e,
9797                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnDtBias))?,
9798                )?,
9799                norm: upload(
9800                    e,
9801                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnNorm))?,
9802                )?,
9803                out: upload(e, &out_t)?,
9804            })
9805        }
9806        other => {
9807            return Err(format!(
9808                "qwen4exp_gpu: unsupported mixer {other:?} at layer {}",
9809                layer.index
9810            )
9811            .into());
9812        }
9813    };
9814    let MlpPlan::Moe(moe_plan) = &layer.mlp else {
9815        return Err(format!("qwen4exp_gpu: layer {} is not MoE", layer.index).into());
9816    };
9817    if !matches!(moe_plan.router, RouterPlan::Softmax) {
9818        return Err("qwen4exp_gpu: only the softmax router arm is implemented".into());
9819    }
9820    let shared = moe_plan
9821        .shared
9822        .as_ref()
9823        .ok_or("qwen4exp_gpu: missing shared expert plan")?;
9824    let bank = match bank_override {
9825        Some(bank) => bank,
9826        None => {
9827            let gate = expect(
9828                weights,
9829                &layer_id(layer.index, LayerTensor::MoeExpertGateBank),
9830            )?;
9831            let up = expect(
9832                weights,
9833                &layer_id(layer.index, LayerTensor::MoeExpertUpBank),
9834            )?;
9835            let down = expect(
9836                weights,
9837                &layer_id(layer.index, LayerTensor::MoeExpertDownBank),
9838            )?;
9839            let experts = moe_plan.expert_count as usize;
9840            let ff = moe_plan.expert_intermediate_size as usize;
9841            if gate.data.len() != experts * ff * hidden
9842                || up.data.len() != experts * ff * hidden
9843                || down.data.len() != experts * hidden * ff
9844            {
9845                return Err(format!(
9846                    "qwen4exp_gpu: layer {} expert bank shape mismatch",
9847                    layer.index
9848                )
9849                .into());
9850            }
9851            ExpertBank {
9852                gate: BankHalf::F32(e.htod(&gate.data)?),
9853                up: BankHalf::F32(e.htod(&up.data)?),
9854                down: BankHalf::F32(e.htod(&down.data)?),
9855            }
9856        }
9857    };
9858    let sh_gate_t = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpGate))?;
9859    let sh_up_t = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpUp))?;
9860    let sh_down_t = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpDown))?;
9861    let sff = shared.intermediate_size as usize;
9862    let router_t = expect(weights, &layer_id(layer.index, LayerTensor::MoeRouter))?;
9863    let moe = MoeW {
9864        plan: moe_plan.clone(),
9865        router_b16: bf16_twin(e, &router_t.data, hidden)?,
9866        router: upload(e, &router_t)?,
9867        bank,
9868        shared_gu_b16: bf16_stack_twin(e, &[&sh_gate_t.data, &sh_up_t.data], hidden)?,
9869        shared_down_b16: bf16_twin(e, &sh_down_t.data, sff)?,
9870        shared_gate: upload(e, &sh_gate_t)?,
9871        shared_up: upload(e, &sh_up_t)?,
9872        shared_down: upload(e, &sh_down_t)?,
9873        shared_input_gate: if shared.gated {
9874            Some(upload(
9875                e,
9876                &expect(
9877                    weights,
9878                    &layer_id(layer.index, LayerTensor::SharedMlpInputGate),
9879                )?,
9880            )?)
9881        } else {
9882            None
9883        },
9884    };
9885    let ple = match layer.ple.as_ref() {
9886        None => None,
9887        Some(ple_plan) => {
9888            let embed_dim = ple_plan.embed_dim as usize;
9889            let head_dim = ple_plan.head_embed_dim as usize;
9890            let wide = streams * hidden;
9891            let key_proj = expect(weights, &family_id(format!("{prefix}ple.key_proj.weight")))?;
9892            let conv_w = expect(weights, &family_id(format!("{prefix}ple.conv1d.weight")))?;
9893            if key_proj.data.len() != wide * embed_dim {
9894                return Err("qwen4exp_gpu: ple key_proj shape mismatch".into());
9895            }
9896            let norm_slices = |name: &str| -> Res<Vec<CudaSlice<f32>>> {
9897                let t = expect(weights, &family_id(format!("{prefix}ple.{name}.weight")))?;
9898                split_rows(&t.data, streams, hidden, 1)
9899                    .into_iter()
9900                    .map(|v| e.htod(&v))
9901                    .collect::<Result<_, _>>()
9902            };
9903            let ints = |name: &str| -> Res<Vec<i64>> {
9904                let t = expect(
9905                    weights,
9906                    &family_id(format!("{prefix}ple.ple_embedding.{name}")),
9907                )?;
9908                t.ints
9909                    .clone()
9910                    .ok_or_else(|| "qwen4exp_gpu: n-gram buffer must be I64".into())
9911            };
9912            let table = match table_override {
9913                Some(table) => table,
9914                None => {
9915                    let t = expect(
9916                        weights,
9917                        &family_id(format!("{prefix}ple.ple_embedding.ngram_embedding")),
9918                    )?;
9919                    if t.shape.len() != 2 || t.shape[1] != head_dim {
9920                        return Err("qwen4exp_gpu: n-gram table shape mismatch".into());
9921                    }
9922                    NgramTable::F32(t.data)
9923                }
9924            };
9925            Some(PleW {
9926                plan: *ple_plan,
9927                key_proj: split_rows(&key_proj.data, streams, hidden, embed_dim)
9928                    .into_iter()
9929                    .map(|v| e.htod(&v))
9930                    .collect::<Result<_, _>>()?,
9931                value_proj: upload(
9932                    e,
9933                    &expect(
9934                        weights,
9935                        &family_id(format!("{prefix}ple.value_proj.weight")),
9936                    )?,
9937                )?,
9938                norm_key: norm_slices("norm_key")?,
9939                norm_query: norm_slices("norm_query")?,
9940                norm_conv: norm_slices("norm_conv")?,
9941                conv_w: split_rows(&conv_w.data, streams, hidden, ple_plan.conv_kernel as usize)
9942                    .into_iter()
9943                    .map(|v| e.htod(&v))
9944                    .collect::<Result<_, _>>()?,
9945                multipliers: ints("layer_multipliers")?,
9946                sizes: ints("ngram_heads_vocab_sizes")?,
9947                offsets: ints("ngram_heads_offsets")?,
9948                table,
9949            })
9950        }
9951    };
9952    Ok(LayerW {
9953        index: layer.index,
9954        eps_attn: layer.pre_attention_norm.epsilon,
9955        eps_mlp: layer.pre_mlp_norm.epsilon,
9956        attn_gate,
9957        mlp_gate,
9958        mixer,
9959        moe,
9960        ple,
9961    })
9962}
9963
9964/// Build the MTP draft block (SEMANTICS.md §MTP): fusion glue + the one decoder layer +
9965/// the draft's own exit mixer. The lm_head is SHARED with the trunk (`self.output`).
9966#[allow(clippy::too_many_arguments)]
9967fn build_mtp_w(
9968    e: &Engine,
9969    weights: &ReferenceWeights,
9970    block: &memra_gguf::model_plan::MtpBlockPlan,
9971    streams: usize,
9972    hidden: usize,
9973    rank: usize,
9974    bank_override: Option<ExpertBank>,
9975) -> Res<MtpW> {
9976    use memra_gguf::tensor_contract::MtpTensor;
9977    if block.input.fusion != memra_gguf::model_plan::MtpFusionPlan::SeparateProjections {
9978        return Err("qwen4exp_gpu: MTP block is not the separate-projections family".into());
9979    }
9980    let wide = streams * hidden;
9981    let depth = block.depth;
9982    let mtp_id = |tensor: MtpTensor| TensorId::Mtp { depth, tensor };
9983    let pre_e = expect(weights, &mtp_id(MtpTensor::EmbeddingNorm))?;
9984    let pre_h = expect(weights, &mtp_id(MtpTensor::HiddenNorm))?;
9985    let fc_e = expect(weights, &mtp_id(MtpTensor::EmbeddingProjection))?;
9986    let fc_h = expect(weights, &mtp_id(MtpTensor::HiddenProjection))?;
9987    if pre_e.data.len() != hidden
9988        || pre_h.data.len() != wide
9989        || fc_e.data.len() != hidden * hidden
9990        || fc_h.data.len() != hidden * hidden
9991    {
9992        return Err("qwen4exp_gpu: MTP fusion tensor shape mismatch".into());
9993    }
9994    let prefix = format!("mtp.layers.{depth}.");
9995    let layer = build_layer_w(
9996        e,
9997        weights,
9998        &block.layer,
9999        &prefix,
10000        streams,
10001        hidden,
10002        rank,
10003        bank_override,
10004        None,
10005    )?;
10006    let mixer = load_gate(
10007        e,
10008        weights,
10009        "mtp.hyper_connection_mixer.",
10010        "",
10011        streams,
10012        hidden,
10013        rank,
10014        false,
10015    )?;
10016    Ok(MtpW {
10017        eps_embed: block.input.embedding_norm.epsilon,
10018        eps_hidden: block.input.hidden_norm.epsilon,
10019        fc_embed_b16: bf16_twin(e, &fc_e.data, hidden)?,
10020        fc_hidden_b16: bf16_twin(e, &fc_h.data, hidden)?,
10021        pre_norm_embed: upload(e, &pre_e)?,
10022        pre_norm_hidden: upload(e, &pre_h)?,
10023        fc_embed: upload(e, &fc_e)?,
10024        fc_hidden: upload(e, &fc_h)?,
10025        layer,
10026        mixer,
10027    })
10028}
10029
10030impl Qwen4ExpGpu {
10031    /// Build the eager model from TensorId-keyed reference weights (the deterministic tiny
10032    /// fixture, or a checkpoint materialized through `read_checkpoint`'s binding walk).
10033    /// Effective (already-folded) norm weights; reference layout throughout.
10034    pub fn from_reference_weights(
10035        e: &Engine,
10036        plan: &ModelPlan,
10037        weights: &ReferenceWeights,
10038    ) -> Res<Self> {
10039        Self::from_reference_weights_with(e, None, plan, weights, ExternalParts::default())
10040    }
10041
10042    fn from_reference_weights_with(
10043        e: &Engine,
10044        // Card-1 draft placement (mtp10): when given, the MTP block's device tensors and
10045        // a private lm-head copy build on THIS engine instead of `e`.
10046        draft_e: Option<&Engine>,
10047        plan: &ModelPlan,
10048        weights: &ReferenceWeights,
10049        mut parts: ExternalParts,
10050    ) -> Res<Self> {
10051        let hidden = plan.hidden_size as usize;
10052        let vocab = plan.vocab_size as usize;
10053        let Some(mixer_plan) = plan.exit_mixer else {
10054            return Err("qwen4exp_gpu requires the gated-residual exit mixer".into());
10055        };
10056        let streams = mixer_plan.streams as usize;
10057        if streams > PLANE_SLOTS.len() {
10058            return Err("qwen4exp_gpu: hc_count exceeds the step-workspace slot table".into());
10059        }
10060        let rank = mixer_plan.bottleneck_rank as usize;
10061        if !plan.logits.is_empty() {
10062            return Err("qwen4exp_gpu: logits transforms are not part of this family".into());
10063        }
10064
10065        let embed = expect(weights, &TensorId::TokenEmbedding)?;
10066        if embed.data.len() != vocab * hidden {
10067            return Err("qwen4exp_gpu: embedding shape mismatch".into());
10068        }
10069        let (output, output_b16) = match weights.get(&TensorId::OutputProjection) {
10070            Some(tensor) => (e.htod(&tensor.data)?, bf16_twin(e, &tensor.data, hidden)?),
10071            None => (e.htod(&embed.data)?, bf16_twin(e, &embed.data, hidden)?),
10072        };
10073
10074        let mut layers = Vec::with_capacity(plan.layers.len());
10075        for layer in &plan.layers {
10076            let prefix = format!("trunk.layers.{}.", layer.index);
10077            layers.push(build_layer_w(
10078                e,
10079                weights,
10080                layer,
10081                &prefix,
10082                streams,
10083                hidden,
10084                rank,
10085                parts.expert_banks.remove(&layer.index),
10086                parts.ngram_tables.remove(&layer.index),
10087            )?);
10088        }
10089        // The MTP draft block (mtp-spec lane): built when its rows are present in the
10090        // materialized weights — presence-driven, so the deterministic fixture carries
10091        // it and a checkpoint loaded without `LoadOptions::load_mtp` skips it.
10092        let mtp = match plan.mtp_blocks.first() {
10093            Some(block)
10094                if weights
10095                    .get(&TensorId::Mtp {
10096                        depth: block.depth,
10097                        tensor: memra_gguf::tensor_contract::MtpTensor::EmbeddingProjection,
10098                    })
10099                    .is_some() =>
10100            {
10101                Some(build_mtp_w(
10102                    draft_e.unwrap_or(e),
10103                    weights,
10104                    block,
10105                    streams,
10106                    hidden,
10107                    rank,
10108                    parts.expert_banks.remove(&block.layer.index),
10109                )?)
10110            }
10111            _ => None,
10112        };
10113        // Card-1 lm-head copy for the dev1 draft: the SAME f32 rows and the SAME bf16
10114        // twin bytes as card 0's head, so the draft head program is verbatim.
10115        let mtp_dev1 = match (draft_e, mtp.as_ref()) {
10116            (Some(de), Some(_)) => {
10117                let head_data: &[f32] = match weights.get(&TensorId::OutputProjection) {
10118                    Some(tensor) => &tensor.data,
10119                    None => &embed.data,
10120                };
10121                Some(MtpDev1 {
10122                    dev: de.ctx().ordinal(),
10123                    output: de.htod(head_data)?,
10124                    output_b16: bf16_twin(de, head_data, hidden)?,
10125                })
10126            }
10127            (Some(_), None) => {
10128                return Err(
10129                    "qwen4exp_gpu: a draft engine was given but no mtp.* rows were \
10130                     materialized (LoadOptions::load_mtp)"
10131                        .into(),
10132                );
10133            }
10134            _ => None,
10135        };
10136        let exit_mixer = load_gate(
10137            e,
10138            weights,
10139            "trunk.hyper_connection_mixer.",
10140            "",
10141            streams,
10142            hidden,
10143            rank,
10144            false,
10145        )?;
10146        Ok(Self {
10147            plan: plan.clone(),
10148            hidden,
10149            streams,
10150            vocab,
10151            embed_host: embed.data,
10152            output,
10153            output_b16,
10154            layers,
10155            exit_mixer,
10156            exit_eps: plan.output_norm.epsilon,
10157            mtp,
10158            mtp_dev1,
10159            draft_trim: None,
10160            draft_trim_parked: None,
10161            chain_embed: None,
10162        })
10163    }
10164
10165    /// Arm the FR-Spec draft-head trim (mtp9): gather the `ids` rows of the SHARED lm head
10166    /// into a [n, hidden] trimmed head, D2D — same bytes, so every trimmed logit is
10167    /// bit-identical to its full-vocab twin. `ids` is the own-gen rank list in rank order
10168    /// (most frequent first); duplicates and out-of-range ids are rejected.
10169    ///
10170    /// Arming changes what the DRAFT can propose (acceptance), never what the model
10171    /// commits: the verify chunk is full-vocab and the accept walk compares against it.
10172    pub fn build_draft_trim(&mut self, e: &Engine, ids: &[u32]) -> Res<()> {
10173        // Card-1 placement: the trim gathers from the DEV1 head copy (same bytes as
10174        // card 0's) and its rows live beside the draft — `e` must be the draft engine.
10175        self.check_draft_engine(e)?;
10176        let n = ids.len();
10177        if n == 0 || n > self.vocab {
10178            return Err(format!("qwen4exp_gpu: draft trim wants 1..={} ids", self.vocab).into());
10179        }
10180        let mut seen = vec![false; self.vocab];
10181        for &id in ids {
10182            let id = id as usize;
10183            if id >= self.vocab {
10184                return Err(format!("qwen4exp_gpu: draft trim id {id} out of vocab").into());
10185            }
10186            if std::mem::replace(&mut seen[id], true) {
10187                return Err(format!("qwen4exp_gpu: draft trim id {id} repeats").into());
10188            }
10189        }
10190        let hidden = self.hidden;
10191        let (src_f32, src_b16) = match self.mtp_dev1.as_ref() {
10192            Some(d) => (&d.output, d.output_b16.as_ref()),
10193            None => (&self.output, self.output_b16.as_ref()),
10194        };
10195        // Gather the bf16 twin when it exists (the arm the trunk seam runs) and SKIP the
10196        // f32 gather entirely — at N=32768 that is 168 MB instead of 503 MB, and the f32
10197        // arm would be dead residency. No twin => gather f32, the only arm available.
10198        let (head_b16, head) = match src_b16 {
10199            Some(full) => {
10200                let mut trim = e.alloc_u8_uninit(n * hidden * 2)?;
10201                for (row, &id) in ids.iter().enumerate() {
10202                    e.copy_u8_range_into(
10203                        &mut trim,
10204                        row * hidden * 2,
10205                        full,
10206                        id as usize * hidden * 2,
10207                        hidden * 2,
10208                    )?;
10209                }
10210                (Some(trim), None)
10211            }
10212            None => {
10213                let mut head = e.uninit(n * hidden)?;
10214                for (row, &id) in ids.iter().enumerate() {
10215                    e.copy_range_into(
10216                        &mut head,
10217                        row * hidden,
10218                        src_f32,
10219                        id as usize * hidden,
10220                        hidden,
10221                    )?;
10222                }
10223                (None, Some(head))
10224            }
10225        };
10226        self.draft_trim = Some(DraftTrim {
10227            n,
10228            d2t: ids.to_vec(),
10229            head,
10230            head_b16,
10231        });
10232        self.draft_trim_parked = None;
10233        Ok(())
10234    }
10235
10236    /// Flip a BUILT trim between live and parked (the interleaved A/B's two arms) without
10237    /// reallocating the gathered head. No-op when no trim was ever built.
10238    pub fn set_draft_trim(&mut self, on: bool) {
10239        if on {
10240            if let Some(t) = self.draft_trim_parked.take() {
10241                self.draft_trim = Some(t);
10242            }
10243        } else if let Some(t) = self.draft_trim.take() {
10244            self.draft_trim_parked = Some(t);
10245        }
10246    }
10247
10248    /// Drop the draft trim entirely (both live and parked).
10249    pub fn clear_draft_trim(&mut self) {
10250        self.draft_trim = None;
10251        self.draft_trim_parked = None;
10252    }
10253
10254    /// Arm the deferred-chain embed table (mtp11, `SpecOpts::defer`): the chain's
10255    /// next-step embed rows, resident on the DRAFT engine, so the device argmax feeds
10256    /// the next chain step without a host round trip (see [`ChainEmbed`] for the
10257    /// bf16-clean bit-identity contract and the trim-rank row order). Re-arm after any
10258    /// trim change — `spec_generate_ext` refuses a table whose trim state or width
10259    /// disagrees with the live draft head.
10260    pub fn arm_spec_devchain(&mut self, de: &Engine) -> Res<()> {
10261        self.check_draft_engine(de)?;
10262        let hidden = self.hidden;
10263        let (rows, for_trim) = match self.draft_trim.as_ref() {
10264            Some(tr) => (tr.n, true),
10265            None => (self.vocab, false),
10266        };
10267        let src_row = |r: usize| -> &[f32] {
10268            let id = match self.draft_trim.as_ref() {
10269                Some(tr) => tr.d2t[r] as usize,
10270                None => r,
10271            };
10272            &self.embed_host[id * hidden..(id + 1) * hidden]
10273        };
10274        // bf16-clean scan over the SELECTED rows: every value must round-trip
10275        // f32 -> bits>>16 -> bits<<16 exactly, or the table falls back to raw f32.
10276        let clean = (0..rows).all(|r| src_row(r).iter().all(|x| x.to_bits() & 0xFFFF == 0));
10277        let (bytes, qt, row_bytes) = if clean {
10278            let mut b = vec![0u8; rows * hidden * 2];
10279            for r in 0..rows {
10280                for (j, &x) in src_row(r).iter().enumerate() {
10281                    let h = (x.to_bits() >> 16) as u16;
10282                    b[(r * hidden + j) * 2..(r * hidden + j) * 2 + 2]
10283                        .copy_from_slice(&h.to_le_bytes());
10284                }
10285            }
10286            (b, crate::QT_BF16, hidden * 2)
10287        } else {
10288            let mut b = vec![0u8; rows * hidden * 4];
10289            for r in 0..rows {
10290                for (j, &x) in src_row(r).iter().enumerate() {
10291                    b[(r * hidden + j) * 4..(r * hidden + j) * 4 + 4]
10292                        .copy_from_slice(&x.to_le_bytes());
10293                }
10294            }
10295            (b, crate::QT_F32, hidden * 4)
10296        };
10297        let table = de.upload_u8(&bytes)?;
10298        println!(
10299            "[qwen4exp-spec] deferred-chain embed table armed: {} rows x {hidden} ({}, {:.1} MiB, dev {}{})",
10300            rows,
10301            if clean {
10302                "bf16 bit-clean"
10303            } else {
10304                "f32 fallback"
10305            },
10306            (rows * row_bytes) as f64 / (1024.0 * 1024.0),
10307            de.ctx().ordinal(),
10308            if for_trim { ", trim-rank order" } else { "" },
10309        );
10310        self.chain_embed = Some(ChainEmbed {
10311            table,
10312            qt,
10313            row_bytes,
10314            rows,
10315            for_trim,
10316            dev: de.ctx().ordinal(),
10317        });
10318        Ok(())
10319    }
10320
10321    /// Drop the deferred-chain embed table (frees the card-1 residency).
10322    pub fn clear_spec_devchain(&mut self) {
10323        self.chain_embed = None;
10324    }
10325
10326    /// Rows the draft's lm_head produces: the trim width when armed, else full vocab.
10327    /// Draft logits live in TRIMMED space when armed; `draft_token` maps a row back.
10328    pub fn draft_logits_width(&self) -> usize {
10329        match self.draft_trim.as_ref() {
10330            Some(t) => t.n,
10331            None => self.vocab,
10332        }
10333    }
10334
10335    /// Map a draft-logits row index back to its TARGET vocab id (identity when the trim
10336    /// is off).
10337    fn draft_token(&self, row: u32) -> Res<u32> {
10338        match self.draft_trim.as_ref() {
10339            Some(t) => t
10340                .d2t
10341                .get(row as usize)
10342                .copied()
10343                .ok_or_else(|| format!("qwen4exp_gpu: draft row {row} outside the trim").into()),
10344            None => Ok(row),
10345        }
10346    }
10347
10348    /// Trunk f32 diet (yarn-cell follow-up 3): FREE the f32 originals whose bf16 twins
10349    /// are resident — under the ship seams (trunk-bf16 + fused-gate, both default ON)
10350    /// every consumer of these tensors runs the bf16 kernels at every t, so the f32
10351    /// copies are pure dead residency (~6 GiB on card 0 at the real geometry). Each
10352    /// dropped tensor becomes a 1-element stub; every f32 fallback path guards on the
10353    /// stub and errs loudly instead of reading it (flipping the trunk seams OFF after
10354    /// the diet refuses rather than corrupting). Returns bytes freed. NOT applied to
10355    /// the MTP draft weights (card-1 slack; the reference-parity gates read them).
10356    pub fn trunk_f32_diet(&mut self, e: &Engine) -> Res<usize> {
10357        if !trunk_bf16_on() || !hc_fused_gate_on() {
10358            return Err(
10359                "qwen4exp_gpu: trunk_f32_diet requires the trunk-bf16 + fused-gate seams ON \
10360                 (the bf16 paths must be the ones serving)"
10361                    .into(),
10362            );
10363        }
10364        let mut freed = 0usize;
10365        fn stub(e: &Engine, s: &mut CudaSlice<f32>, freed: &mut usize) -> Res<()> {
10366            if s.len() > 1 {
10367                *freed += s.len() * 4;
10368                *s = e.zeros(1)?;
10369            }
10370            Ok(())
10371        }
10372        fn diet_gate(e: &Engine, g: &mut GateW, freed: &mut usize) -> Res<()> {
10373            if g.down_b16.is_none()
10374                || g.up_b16.is_none()
10375                || (g.inject.is_some() && g.inject_b16.is_none())
10376            {
10377                return Ok(()); // partial twins: keep the f32 arm whole
10378            }
10379            for s in g.down.iter_mut() {
10380                stub(e, s, freed)?;
10381            }
10382            for s in g.up.iter_mut() {
10383                stub(e, s, freed)?;
10384            }
10385            if let Some(inj) = g.inject.as_mut() {
10386                stub(e, inj, freed)?;
10387            }
10388            Ok(())
10389        }
10390        for layer in self.layers.iter_mut() {
10391            diet_gate(e, &mut layer.attn_gate, &mut freed)?;
10392            diet_gate(e, &mut layer.mlp_gate, &mut freed)?;
10393            match &mut layer.mixer {
10394                MixerW::Qsa(q) => {
10395                    if q.proj_b16.is_some() {
10396                        stub(e, &mut q.wq, &mut freed)?;
10397                        stub(e, &mut q.wk, &mut freed)?;
10398                        stub(e, &mut q.wv, &mut freed)?;
10399                    }
10400                    if q.wo_b16.is_some() {
10401                        stub(e, &mut q.wo, &mut freed)?;
10402                    }
10403                }
10404                MixerW::Gdn(g) => {
10405                    if g.proj_b16.is_some() {
10406                        stub(e, &mut g.qkv, &mut freed)?;
10407                        stub(e, &mut g.z, &mut freed)?;
10408                        stub(e, &mut g.beta, &mut freed)?;
10409                        stub(e, &mut g.alpha, &mut freed)?;
10410                    }
10411                    if g.out_b16.is_some() {
10412                        stub(e, &mut g.out, &mut freed)?;
10413                    }
10414                }
10415            }
10416            let moe = &mut layer.moe;
10417            if moe.router_b16.is_some() {
10418                stub(e, &mut moe.router, &mut freed)?;
10419            }
10420            if moe.shared_gu_b16.is_some() {
10421                stub(e, &mut moe.shared_gate, &mut freed)?;
10422                stub(e, &mut moe.shared_up, &mut freed)?;
10423            }
10424            if moe.shared_down_b16.is_some() {
10425                stub(e, &mut moe.shared_down, &mut freed)?;
10426            }
10427        }
10428        diet_gate(e, &mut self.exit_mixer, &mut freed)?;
10429        if self.output_b16.is_some() {
10430            stub(e, &mut self.output, &mut freed)?;
10431        }
10432        Ok(freed)
10433    }
10434
10435    pub fn alloc_state(&self, e: &Engine, capacity: usize) -> Res<Qwen4ExpState> {
10436        self.alloc_state_reserve(e, capacity, capacity, None)
10437    }
10438
10439    /// Long-context state: `reserve` caps the workspace-slot unit at the chunk bound
10440    /// (see `Qwen4ExpState::reserve`), and `kv_engine` optionally places the QSA KV
10441    /// caches on ANOTHER card (the kv-dev1 ladder arm: card 0 holds the trunk at
10442    /// ~90 GiB; the attention kernels read K/V over UVA P2P). `None` = same card.
10443    pub fn alloc_state_reserve(
10444        &self,
10445        e: &Engine,
10446        capacity: usize,
10447        reserve: usize,
10448        kv_engine: Option<&Engine>,
10449    ) -> Res<Qwen4ExpState> {
10450        let kv_e = kv_engine.unwrap_or(e);
10451        // Peer-resident KV is admissible only at smoke depth (see `peer_kv_max_cap`):
10452        // past the ceiling the block-list attention's scatter reads leave the reading
10453        // card's L2 behind and every selected position becomes a PCIe round trip.
10454        // Refused HERE rather than discovered as a 100%-sm / 0%-mem non-finish, which is
10455        // how memra#53 burned two cells (45 min and 113 min, no rung row either time).
10456        if kv_e.ctx().ordinal() != e.ctx().ordinal() {
10457            let limit = peer_kv_max_cap();
10458            if capacity > limit {
10459                return Err(format!(
10460                    "qwen4exp_gpu: peer-resident QSA KV refused — capacity {capacity} rows on \
10461                     device {} while the attention runs on device {} (ceiling {limit} rows, \
10462                     MEMRA_Q4E_PEER_KV_MAX_CAP). The block-list form is the only read path for a \
10463                     quantized cache and it is a scatter reader (q4e_sdpa_blocklist_q8q5 phase 1 \
10464                     is thread-per-position: 32 lanes on 32 rows, 32 sectors per load \
10465                     instruction). Peer memory is not cached in the reading card's L2, so at this \
10466                     depth ONE 2,048-token prefill chunk asks ~523 GB across the link and the run \
10467                     never finishes — it does not deadlock, it just never arrives. Keep the QSA KV \
10468                     on the compute card: it is 10,368 B/row across the 12 QSA layers (2.7 GiB at \
10469                     262,144), while the allocation that forces a second card is the MTP draft \
10470                     state (~17.6 GiB), which --mtp-dev1 / load_from_dir_dev1 already places \
10471                     there.",
10472                    kv_e.ctx().ordinal(),
10473                    e.ctx().ordinal(),
10474                )
10475                .into());
10476            }
10477        }
10478        let mut layers = Vec::with_capacity(self.layers.len());
10479        for layer in &self.layers {
10480            let mixer = match &layer.mixer {
10481                MixerW::Qsa(qsa) => {
10482                    let kv_width = qsa.attn.kv_heads as usize * qsa.attn.key_head_dim as usize;
10483                    let v_width = qsa.attn.kv_heads as usize * qsa.attn.value_head_dim as usize;
10484                    // kvq/idxq lanes: the storage format latches PER STATE here (a byte
10485                    // cache cannot flip mid-run; the A/B harness allocates per arm).
10486                    let kv = if kv_quant_on() {
10487                        QsaKvStore::Q8Q5 {
10488                            k: kv_e.alloc_u8(capacity * q8_row_bytes(kv_width))?,
10489                            v: kv_e.alloc_u8(capacity * q5_row_bytes(v_width))?,
10490                        }
10491                    } else {
10492                        QsaKvStore::F32 {
10493                            k: kv_e.zeros(capacity * kv_width)?,
10494                            v: kv_e.zeros(capacity * v_width)?,
10495                        }
10496                    };
10497                    MixerState::Qsa {
10498                        kv,
10499                        raw_keys: IdxRawCache::new(idxq_mode()),
10500                        pooled_keys: Vec::new(),
10501                        pooled_dev: None,
10502                        pooled_dev_rows: 0,
10503                        raw_dev: None,
10504                        raw_dev_rows: 0,
10505                        idx_audit: (idxq_mode() != IdxQMode::F32 && idxq_audit_on()).then(|| {
10506                            Box::new(IdxAudit {
10507                                raw_f32: IdxRawCache::F32(Vec::new()),
10508                                pooled_f32: Vec::new(),
10509                            })
10510                        }),
10511                    }
10512                }
10513                MixerW::Gdn(gdn) => {
10514                    let p = &gdn.plan;
10515                    let conv_dim = 2 * (p.key_heads * p.key_head_dim) as usize
10516                        + (p.value_heads * p.value_head_dim) as usize;
10517                    let pad = p.conv_kernel as usize - 1;
10518                    MixerState::Gdn {
10519                        conv: e.zeros(pad * conv_dim)?,
10520                        state: e
10521                            .zeros((p.value_heads * p.value_head_dim * p.key_head_dim) as usize)?,
10522                    }
10523                }
10524            };
10525            let ple = match layer.ple.as_ref() {
10526                None => None,
10527                Some(ple) => {
10528                    let pad = (ple.plan.conv_kernel as usize - 1) * ple.plan.max_ngram as usize;
10529                    let mut conv_hist = Vec::with_capacity(self.streams);
10530                    for _ in 0..self.streams {
10531                        conv_hist.push(e.zeros(pad * self.hidden)?);
10532                    }
10533                    Some(PleState {
10534                        conv_hist,
10535                        ngram_ids: Vec::new(),
10536                        ngram_history: Vec::new(),
10537                        ngram_last_eos: -1,
10538                    })
10539                }
10540            };
10541            layers.push(LayerState { mixer, ple });
10542        }
10543        Ok(Qwen4ExpState {
10544            pos: 0,
10545            capacity,
10546            reserve,
10547            tokens: Vec::new(),
10548            layers,
10549            ws: StepPool::default(),
10550            graphs: StepGraphs::default(),
10551            tp2: None,
10552            verify: None,
10553        })
10554    }
10555
10556    /// Prefill `ids` from the state's current position. Returns [t, vocab] logits (host).
10557    pub fn prefill(&self, e: &Engine, ids: &[u32], state: &mut Qwen4ExpState) -> Res<Vec<f32>> {
10558        self.forward(e, ids, state, None)
10559    }
10560
10561    /// LONG-context chunked prefill: forward `ids` in `chunk`-sized pieces from the
10562    /// state's current position, skipping the exit mixer + lm_head on every chunk but
10563    /// materializing ONLY the final row's logits at the end. State-identical to one big
10564    /// `prefill` (the head reads no state and writes none); the [t, vocab] logits block
10565    /// a big chunk would otherwise materialize is the thing being skipped (16 GB at
10566    /// chunk 16384 on this vocab). Returns the LAST row's logits [vocab].
10567    pub fn prefill_extend(
10568        &self,
10569        e: &Engine,
10570        ids: &[u32],
10571        state: &mut Qwen4ExpState,
10572        chunk: usize,
10573    ) -> Res<Vec<f32>> {
10574        if ids.is_empty() || chunk == 0 {
10575            return Err("qwen4exp_gpu: prefill_extend needs ids and a chunk size".into());
10576        }
10577        let mut last = Vec::new();
10578        for piece in ids.chunks(chunk) {
10579            let is_last =
10580                piece.as_ptr() as usize + piece.len() * 4 == ids.as_ptr() as usize + ids.len() * 4;
10581            let head = if is_last {
10582                HeadMode::LastRow
10583            } else {
10584                HeadMode::Skip
10585            };
10586            last = self.forward_with(e, piece, state, None, head)?;
10587        }
10588        Ok(last)
10589    }
10590
10591    /// One incremental decode step (no prompt recompute). Returns [vocab] logits (host).
10592    pub fn decode_step(&self, e: &Engine, token: u32, state: &mut Qwen4ExpState) -> Res<Vec<f32>> {
10593        self.forward(e, &[token], state, None)
10594    }
10595
10596    /// Prefill with per-layer parity capture (the transformers hidden-goldens hook
10597    /// points): post-layer WIDE rows per trunk layer + the exit mixer output.
10598    pub fn prefill_captured(
10599        &self,
10600        e: &Engine,
10601        ids: &[u32],
10602        state: &mut Qwen4ExpState,
10603    ) -> Res<(Vec<f32>, PrefillCapture)> {
10604        let mut capture = PrefillCapture {
10605            layer_wide: Vec::with_capacity(self.layers.len()),
10606            exit_mixed: Vec::new(),
10607        };
10608        let logits = self.forward(e, ids, state, Some(&mut capture))?;
10609        Ok((logits, capture))
10610    }
10611
10612    /// Interleave stream-major planes into token-major wide rows [t, streams*hidden]
10613    /// (the HF wide-stream layout: token row = concat over streams).
10614    fn planes_to_wide(&self, e: &Engine, planes: &[CudaSlice<f32>], t: usize) -> Res<Vec<f32>> {
10615        let hidden = self.hidden;
10616        let wide = self.streams * hidden;
10617        let mut out = vec![0.0f32; t * wide];
10618        for (s, plane) in planes.iter().enumerate() {
10619            // Slice: workspace planes are reserve-sized (>= t*hidden).
10620            let host = e.dtoh_view(&plane.slice(0..t * hidden))?;
10621            for row in 0..t {
10622                out[row * wide + s * hidden..row * wide + (s + 1) * hidden]
10623                    .copy_from_slice(&host[row * hidden..(row + 1) * hidden]);
10624            }
10625        }
10626        Ok(out)
10627    }
10628
10629    fn forward(
10630        &self,
10631        e: &Engine,
10632        ids: &[u32],
10633        state: &mut Qwen4ExpState,
10634        capture: Option<&mut PrefillCapture>,
10635    ) -> Res<Vec<f32>> {
10636        self.forward_with(e, ids, state, capture, HeadMode::All)
10637    }
10638
10639    fn forward_with(
10640        &self,
10641        e: &Engine,
10642        ids: &[u32],
10643        state: &mut Qwen4ExpState,
10644        mut capture: Option<&mut PrefillCapture>,
10645        head: HeadMode,
10646    ) -> Res<Vec<f32>> {
10647        let t = ids.len();
10648        let hidden = self.hidden;
10649        if t == 0 {
10650            return Err("qwen4exp_gpu: empty input".into());
10651        }
10652        if head != HeadMode::All {
10653            // Head-skipping forwards are a chunked-prefill shape: goldens capture wants
10654            // every row, and a verify-EXACT chunk (t <= k_cap) or a t == 1 step feeds
10655            // the argmax sink from the full logits block. Big verify-armed chunks are
10656            // fine — the wide capture happens before the head, and the spec co-prefill
10657            // is exactly this shape.
10658            if capture.is_some() {
10659                return Err("qwen4exp_gpu: prefill capture wants every logits row".into());
10660            }
10661            if let Some(v) = state.verify.as_ref()
10662                && (t == 1 || t <= v.k_cap)
10663            {
10664                return Err(
10665                    "qwen4exp_gpu: head-skipping forward on a verify-exact chunk shape".into(),
10666                );
10667            }
10668        }
10669        if state.pos + t > state.capacity {
10670            return Err("qwen4exp_gpu: state capacity exceeded".into());
10671        }
10672        if state.tp2.is_some() {
10673            return Err(
10674                "qwen4exp_gpu: state already decoded in TP2 mode; single-card forward \
10675                 requires a fresh state (the half-state migration is one-way)"
10676                    .into(),
10677            );
10678        }
10679        let base_pos = state.pos;
10680        state.tokens.extend_from_slice(ids);
10681        // A multi-token chunk can GROW workspace slots (reallocation) — any captured
10682        // graph would keep the stale baked addresses, so invalidate them first.
10683        if t > 1 {
10684            state.graphs = StepGraphs::default();
10685        }
10686        // Decode graphs never engage on an ARMED-verify state (mtp11): the graphs tail
10687        // (`forward_graphs_tail`) carries neither the wide capture nor the argmax sink,
10688        // so two consecutive t == 1 forwards with verify armed (= consecutive zero-draft
10689        // rounds under the p-min guard) would route the second through the tail and skip
10690        // the wide row the next replay seeds from — an acceptance-only degradation the
10691        // byte-identity gates cannot see (the mtp11 audit's found-while-auditing item).
10692        let graphs_mode = t == 1
10693            && decode_graphs_on()
10694            && step_ws_on()
10695            && hc_fused_gate_on()
10696            && !prof::on()
10697            && capture.is_none()
10698            && state.verify.is_none();
10699        let tokens = &state.tokens;
10700        let ws = &mut state.ws;
10701        // Verify instrument (mtp-spec lane): while armed, capture the final wide rows
10702        // every forward; 1 < t <= k_cap chunks additionally run the EXACT row programs
10703        // (each row bit-identical to t == 1 decode) and stash per-column GDN/PLE state.
10704        let verify = state.verify.as_mut();
10705        let (exact, vfused, stash_gdn, stash_ple, stash_wide, argmax_sink, last_row_only) =
10706            match verify {
10707                Some(v) => {
10708                    // Verify chunks NEVER include the prefill (base_pos == 0): a
10709                    // prompt shorter than k_cap would otherwise prefill through the
10710                    // per-row DECODE programs while the plain baseline prefills FUSED —
10711                    // bit-different state from token 0 that drifts until the first
10712                    // thin-margin argmax flips. Found by the mtp11 256-token battery
10713                    // (raw prompt 2, len 6, K=5: k_cap 6 >= 6 -> exact prefill ->
10714                    // divergence at gen 157; K<=4 fused the same prefill and passed);
10715                    // latent since mtp-spec (every green spec-gate ran 64 tokens, and
10716                    // the tiny fixture's 18-token prompt never fit inside k_cap).
10717                    // The `vfuse` cost instrument moves the SAME chunk shape onto the
10718                    // fused program; it does not widen the shape, so this gen-157 rule
10719                    // holds unchanged on both arms.
10720                    let vchunk = base_pos > 0 && t > 1 && t <= v.k_cap;
10721                    let vfused = vchunk && verify_fused_on();
10722                    let exact = vchunk && !vfused;
10723                    // mtp11 deferred round: the t == 1 steps (zero-draft verify, dynk
10724                    // plain tail) take the argmax fast path too — same sink, same
10725                    // bit-identical device argmax, a 4-byte dtoh instead of ~1 MB.
10726                    let amx_t1 = t == 1 && v.want_argmax_t1;
10727                    if exact {
10728                        v.chunk = Some((base_pos, t));
10729                        v.argmax.clear();
10730                    } else if (vfused || amx_t1) && v.want_argmax {
10731                        v.argmax.clear();
10732                    }
10733                    if vfused {
10734                        // Rewind has no per-column stash to restore from on this arm —
10735                        // record the shape so `verify_rewind` can refuse by NAME instead
10736                        // of reporting "no live verify chunk" and reading like a bug.
10737                        v.fused_chunk = Some((base_pos, t));
10738                    }
10739                    (
10740                        exact,
10741                        vfused,
10742                        Some(&mut v.gdn),
10743                        Some(&mut v.ple),
10744                        Some((&mut v.wide, v.ring_rows)),
10745                        // The fused arm feeds the SAME argmax sink, so the A/B compares
10746                        // programs and not readback sizes (a full [t, vocab] dtoh on one
10747                        // arm only would be ~6 MB of measured noise at t=6).
10748                        if (exact || vfused || amx_t1) && v.want_argmax {
10749                            Some((&mut v.argmax, &mut v.toks))
10750                        } else {
10751                            None
10752                        },
10753                        v.last_row_only && t > 1 && !exact && !vfused,
10754                    )
10755                }
10756                None => (false, false, None, None, None, None, false),
10757            };
10758        let mut stash_gdn = stash_gdn;
10759        let mut stash_ple = stash_ple;
10760        // Slot RESERVE unit: reserve-derived so a growing decode never reallocates a
10761        // slot mid-run (address stability, item 2b's prerequisite). Transients scale
10762        // with the CHUNK length t; `reserve` = capacity by default, but a LONG-context
10763        // state (alloc_state_reserve) caps it at the chunk bound — a 1M-capacity state
10764        // must not reserve 1M-token transients (plane slots alone would be ~41 GB).
10765        let cap = state.reserve.max(t);
10766
10767        // Entry: wide stream = `streams` copies of the embedding (modular L1012), held as
10768        // stream-major planes so every per-stream op is a contiguous existing kernel.
10769        let mut planes = prof_section(e, "entry.embed", || {
10770            let mut embedded = vec![0.0f32; t * hidden];
10771            for (row, &token) in ids.iter().enumerate() {
10772                let token = token as usize;
10773                if token >= self.vocab {
10774                    return Err(format!("qwen4exp_gpu: token {token} out of range").into());
10775                }
10776                embedded[row * hidden..(row + 1) * hidden]
10777                    .copy_from_slice(&self.embed_host[token * hidden..(token + 1) * hidden]);
10778            }
10779            let embedded_dev = ws.take_f32_h2d(e, "entry.embed", &embedded, cap * hidden)?;
10780            let mut planes: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
10781            for s in 0..self.streams {
10782                let mut plane = ws.take_f32(e, PLANE_SLOTS[s], t * hidden, cap * hidden)?;
10783                e.copy_into(&mut plane, 0, &embedded_dev, t * hidden)?;
10784                planes.push(plane);
10785            }
10786            ws.put_f32("entry.embed", embedded_dev);
10787            Ok(planes)
10788        })?;
10789
10790        // Plane pointer table for the stream-batched kernels (hcmicro): refreshed every
10791        // step (eagerly, outside any graph) into a stable slot the captured launches
10792        // read at run time.
10793        let ptr_vals: Vec<u64> = {
10794            let stream = e.gpu.stream();
10795            planes.iter().map(|p| p.device_ptr(&stream).0).collect()
10796        };
10797        let ptrs = ws.take_u64_h2d(e, "hc.ptrs", &ptr_vals, 0)?;
10798
10799        if graphs_mode {
10800            if state.graphs.warm {
10801                return self.forward_graphs_tail(e, state, planes, ptrs, base_pos);
10802            }
10803            // First graph-eligible step: run EAGER to warm/park every slot (allocations
10804            // inside a capture region become graph mem nodes); capture starts next step.
10805            state.graphs.warm = true;
10806        }
10807
10808        for (li, (layer, lstate)) in self.layers.iter().zip(state.layers.iter_mut()).enumerate() {
10809            if let (Some(ple), Some(ple_state)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
10810                let ps = if exact {
10811                    stash_ple
10812                        .as_mut()
10813                        .and_then(|v| v.get_mut(li))
10814                        .and_then(|s| s.as_mut())
10815                } else {
10816                    None
10817                };
10818                self.ple_block(
10819                    e,
10820                    layer,
10821                    ple,
10822                    &ple.table,
10823                    ple_state,
10824                    &mut planes,
10825                    tokens,
10826                    t,
10827                    exact,
10828                    ps,
10829                )?;
10830            }
10831            let (mixed, inject) = prof_section(e, "hyper.read", || {
10832                self.gate_read(
10833                    e,
10834                    ws,
10835                    &ptrs,
10836                    &layer.attn_gate,
10837                    &planes,
10838                    t,
10839                    layer.eps_attn,
10840                    exact,
10841                )
10842            })?;
10843            let block_out = match &layer.mixer {
10844                MixerW::Qsa(qsa) => self.qsa_forward(
10845                    e,
10846                    ws,
10847                    layer,
10848                    qsa,
10849                    &mixed,
10850                    &mut lstate.mixer,
10851                    base_pos,
10852                    t,
10853                    0,
10854                    exact,
10855                )?,
10856                MixerW::Gdn(gdn) => {
10857                    let gs = if exact {
10858                        stash_gdn
10859                            .as_mut()
10860                            .and_then(|v| v.get_mut(li))
10861                            .and_then(|s| s.as_mut())
10862                    } else {
10863                        None
10864                    };
10865                    self.gdn_forward(e, ws, layer, gdn, &mixed, &mut lstate.mixer, t, gs)?
10866                }
10867            };
10868            ws.put_f32("hc.mixed", mixed);
10869            prof_section(e, "hyper.write", || {
10870                self.gate_write(e, &mut planes, &ptrs, &block_out, &inject, t)
10871            })?;
10872            ws.put_f32("mixer.out", block_out);
10873            put_inject(ws, inject);
10874            let (mixed, inject) = prof_section(e, "hyper.read", || {
10875                self.gate_read(
10876                    e,
10877                    ws,
10878                    &ptrs,
10879                    &layer.mlp_gate,
10880                    &planes,
10881                    t,
10882                    layer.eps_mlp,
10883                    exact,
10884                )
10885            })?;
10886            // Chunked long-context prefill (head-skipping forwards) rides the GROUPED
10887            // MoE program like verify chunks do: the per-expert prefill executor pays
10888            // 3 dequants + several small syncing H2Ds + GEMMs PER ROUTED EXPERT per
10889            // chunk (~512 x 48 per chunk = minutes/chunk measured on the smoke ladder);
10890            // the grouped path is 2 launches + t combines per layer on NVFP4 banks.
10891            // Decode-class rows (per-slot programs bit-identical to t == 1) — the
10892            // chunked-prefill gates are tolerance-class by design.
10893            // `prefill_grouped_all_on()` is the TP2 class gate's PRIME instrument (default
10894            // OFF = today's behavior exactly): it lets an all-rows single-card forward run
10895            // the GROUPED executor so a TP2 comparison isolates the expert-half split
10896            // instead of straddling it and the executor difference. See the flag's doc.
10897            // `vfused` forces grouped too: the MoE routed union is ALREADY one grouped
10898            // gufuse launch over every verify column on the exact arm, so letting a fused
10899            // verify chunk fall into the per-expert prefill executor would measure that
10900            // executor (minutes/chunk, above) instead of the fusion. Identical MoE program
10901            // on both arms is also the honest cost model — this section cannot be a vfuse
10902            // win, and the A/B must not pretend otherwise in either direction.
10903            let grouped = exact || vfused || head != HeadMode::All || prefill_grouped_all_on();
10904            let mlp = self.moe_forward(e, ws, &layer.moe, &mixed, t, grouped, layer.index)?;
10905            ws.put_f32("hc.mixed", mixed);
10906            prof_section(e, "hyper.write", || {
10907                self.gate_write(e, &mut planes, &ptrs, &mlp, &inject, t)
10908            })?;
10909            ws.put_f32("moe.out", mlp);
10910            put_inject(ws, inject);
10911            if let Some(capture) = capture.as_deref_mut() {
10912                capture.layer_wide.push(self.planes_to_wide(e, &planes, t)?);
10913            }
10914        }
10915
10916        // Verify wide capture: the trunk's FINAL wide rows at their absolute positions,
10917        // ring-slotted (row % ring_rows; ring == capacity is the historical identity
10918        // layout) — the draft's hidden seeds (SEMANTICS.md §MTP).
10919        if let Some((wide_buf, ring_rows)) = stash_wide {
10920            let wide = self.streams * hidden;
10921            for (s, plane) in planes.iter().enumerate() {
10922                for tok in 0..t {
10923                    e.copy_range_into(
10924                        wide_buf,
10925                        ((base_pos + tok) % ring_rows) * wide + s * hidden,
10926                        plane,
10927                        tok * hidden,
10928                        hidden,
10929                    )?;
10930                }
10931            }
10932        }
10933
10934        // Head skip (chunked long-context prefill): the exit mixer + lm_head read no
10935        // state and write none — a mid-prefill chunk stops here, state-identical.
10936        if head == HeadMode::Skip {
10937            ws.put_u64("hc.ptrs", ptrs);
10938            state.pos += t;
10939            for (s, plane) in planes.into_iter().enumerate() {
10940                ws.put_f32(PLANE_SLOTS[s], plane);
10941            }
10942            return Ok(Vec::new());
10943        }
10944
10945        // Exit downmix replaces the final norm (SEMANTICS.md §Layer stack).
10946        let x = prof_section(e, "exit.mixer", || {
10947            Ok(self
10948                .gate_read_inner(
10949                    e,
10950                    ws,
10951                    &ptrs,
10952                    &self.exit_mixer,
10953                    &planes,
10954                    t,
10955                    self.exit_eps,
10956                    false,
10957                    exact,
10958                )?
10959                .0)
10960        })?;
10961        ws.put_u64("hc.ptrs", ptrs);
10962        if let Some(capture) = capture.as_deref_mut() {
10963            capture.exit_mixed = e.dtoh(&x)?;
10964        }
10965        // LastRow (chunked prefill's final chunk): lm_head on ONE row — a [t, vocab]
10966        // logits block at long-context chunk sizes is gigabytes.
10967        let head_rows = if head == HeadMode::LastRow { 1 } else { t };
10968        let logits = prof_section(e, "lm_head", || {
10969            let mut logits =
10970                ws.take_f32(e, "logits", head_rows * self.vocab, head_rows * self.vocab)?;
10971            let x_head = if head == HeadMode::LastRow {
10972                let mut last = ws.take_f32(e, "exit.last", hidden, hidden)?;
10973                e.copy_range_into(&mut last, 0, &x, (t - 1) * hidden, hidden)?;
10974                last
10975            } else {
10976                x
10977            };
10978            linear_trunk_into(
10979                e,
10980                &self.output,
10981                &self.output_b16,
10982                &x_head,
10983                &mut logits,
10984                head_rows,
10985                hidden,
10986                self.vocab,
10987            )?;
10988            ws.put_f32(
10989                if head == HeadMode::LastRow {
10990                    "exit.last"
10991                } else {
10992                    "hc.mixed"
10993                },
10994                x_head,
10995            );
10996            Ok(logits)
10997        })?;
10998        state.pos += t;
10999        if head == HeadMode::LastRow {
11000            let out = prof_section(e, "logits.dtoh", || {
11001                Ok(e.dtoh_view(&logits.slice(0..self.vocab))?)
11002            })?;
11003            ws.put_f32("logits", logits);
11004            for (s, plane) in planes.into_iter().enumerate() {
11005                ws.put_f32(PLANE_SLOTS[s], plane);
11006            }
11007            return Ok(out);
11008        }
11009        // Verify fast path: per-row device argmax + a 4t-byte dtoh instead of the
11010        // [t, vocab] block (the spec loop reads target rows only).
11011        let out = if let Some((argmax_rows, toks)) = argmax_sink {
11012            prof_section(e, "logits.argmax", || {
11013                for row in 0..t {
11014                    e.argmax_token_device_col(&logits, row, self.vocab, toks, row)?;
11015                }
11016                let host = e.gpu.stream().clone_dtoh(&toks.slice(0..t))?;
11017                argmax_rows.extend_from_slice(&host);
11018                Ok(Vec::new())
11019            })?
11020        } else if last_row_only {
11021            // mtp11: big-t (prefill) forwards under the deferred seam dtoh ONE row —
11022            // the spec loop reads exactly one (x0). Same bytes for that row.
11023            prof_section(e, "logits.dtoh", || {
11024                Ok(e.dtoh_view(&logits.slice((t - 1) * self.vocab..t * self.vocab))?)
11025            })?
11026        } else {
11027            prof_section(e, "logits.dtoh", || {
11028                Ok(e.dtoh_view(&logits.slice(0..t * self.vocab))?)
11029            })?
11030        };
11031        ws.put_f32("logits", logits);
11032        for (s, plane) in planes.into_iter().enumerate() {
11033            ws.put_f32(PLANE_SLOTS[s], plane);
11034        }
11035        Ok(out)
11036    }
11037
11038    /// Gated-residual read gate (`gated_residual_read` twin): grouped (effective-weight)
11039    /// RMSNorm per stream, `w = sigmoid(up(silu(down(normed)/S)))`, `mixed = mean_s(w ⊙
11040    /// normed_s)`, inject scalars `2*sigmoid(block_inject(normed)/S)` per stream.
11041    #[allow(clippy::too_many_arguments)]
11042    fn gate_read(
11043        &self,
11044        e: &Engine,
11045        ws: &mut StepPool,
11046        ptrs: &CudaSlice<u64>,
11047        gate: &GateW,
11048        planes: &[CudaSlice<f32>],
11049        t: usize,
11050        eps: f32,
11051        exact: bool,
11052    ) -> Res<(CudaSlice<f32>, InjectOut)> {
11053        self.gate_read_inner(e, ws, ptrs, gate, planes, t, eps, true, exact)
11054    }
11055
11056    #[allow(clippy::too_many_arguments)]
11057    fn gate_read_inner(
11058        &self,
11059        e: &Engine,
11060        ws: &mut StepPool,
11061        ptrs: &CudaSlice<u64>,
11062        gate: &GateW,
11063        planes: &[CudaSlice<f32>],
11064        t: usize,
11065        eps: f32,
11066        with_inject: bool,
11067        // Verify-chunk exactness (mtp-spec lane): engage the DIET kernels at t > 1 so
11068        // every verify row runs the DECODE gate program verbatim per token (the diet
11069        // kernels' token dim is the t == 1 program at a plane offset — bit-identical
11070        // rows). Plain prefill keeps the fused chain (banked-goldens numerics stay).
11071        exact: bool,
11072    ) -> Res<(CudaSlice<f32>, InjectOut)> {
11073        if !hc_fused_gate_on() {
11074            return self.gate_read_legacy(e, ws, gate, planes, t, eps, with_inject);
11075        }
11076        let hidden = self.hidden;
11077        let streams = self.streams;
11078        let rank = gate_rank(gate, hidden, streams)?;
11079        let micro_norm = micro_norm_on();
11080        let micro_inj = micro_inj_on();
11081        // Hyper-gate diet (round 4): the whole read gate in THREE launches. Requires the
11082        // bf16 twins + the Slab inject posture (micro_inj — take_inject's form contract)
11083        // + real geometry; anything else falls back to the fused chain below.
11084        if hc_diet_on()
11085            && (t == 1 || exact)
11086            && trunk_bf16_on()
11087            && micro_inj
11088            && hidden % 8 == 0
11089            && rank % 8 == 0
11090            && gate.down_b16.is_some()
11091            && gate.up_b16.is_some()
11092            && (!with_inject || gate.inject_b16.is_some())
11093        {
11094            let mut parts = ws.take_f32(e, "hc.parts", t * streams * rank, 0)?;
11095            let mut injp = ws.take_f32(e, "hc.injp", t * streams * streams, 0)?;
11096            let mut inv = ws.take_f32(e, "hc.inv", t * streams, 0)?;
11097            let winj = if with_inject {
11098                gate.inject_b16.as_ref()
11099            } else {
11100                None
11101            };
11102            // Weight-shared MT stages (set_verify_mt) at verify chunks: bit-identical
11103            // per token to the token-grid stages (kernel docs + gate oracle), weight
11104            // reads 1x instead of t x.
11105            let mt = t > 1 && verify_mt_on() && (2..=12).contains(&t);
11106            if mt {
11107                launch_hc_diet_stage0_mt(e, ptrs, &mut inv, hidden, streams, t, eps)?;
11108                launch_hc_diet_stage1_mt(
11109                    e,
11110                    ptrs,
11111                    &gate.norm_stack,
11112                    &inv,
11113                    gate.down_b16.as_ref().expect("guarded above"),
11114                    winj,
11115                    &mut parts,
11116                    &mut injp,
11117                    hidden,
11118                    rank,
11119                    streams,
11120                    t,
11121                )?;
11122            } else {
11123                launch_hc_diet_stage1(
11124                    e,
11125                    ptrs,
11126                    &gate.norm_stack,
11127                    gate.down_b16.as_ref().expect("guarded above"),
11128                    winj,
11129                    &mut parts,
11130                    &mut injp,
11131                    &mut inv,
11132                    hidden,
11133                    rank,
11134                    streams,
11135                    t,
11136                    eps,
11137                )?;
11138            }
11139            let mut low_act = ws.take_f32(e, "hc.low_act", t * rank, 0)?;
11140            let mut all = ws.take_f32(e, "hc.inj_all", streams * t, 0)?;
11141            launch_hc_diet_stage2(
11142                e,
11143                &parts,
11144                &injp,
11145                &mut low_act,
11146                &mut all,
11147                rank,
11148                streams,
11149                t,
11150                with_inject,
11151            )?;
11152            let mut mixed = ws.take_f32(e, "hc.mixed", t * hidden, 0)?;
11153            if mt && (t * rank + 8 * streams * t) * 4 <= 96 * 1024 {
11154                launch_hc_diet_stage3_mt(
11155                    e,
11156                    ptrs,
11157                    &gate.norm_stack,
11158                    &inv,
11159                    gate.up_b16.as_ref().expect("guarded above"),
11160                    &low_act,
11161                    &mut mixed,
11162                    hidden,
11163                    rank,
11164                    streams,
11165                    t,
11166                )?;
11167            } else {
11168                launch_hc_diet_stage3(
11169                    e,
11170                    ptrs,
11171                    &gate.norm_stack,
11172                    &inv,
11173                    gate.up_b16.as_ref().expect("guarded above"),
11174                    &low_act,
11175                    &mut mixed,
11176                    hidden,
11177                    rank,
11178                    streams,
11179                    t,
11180                )?;
11181            }
11182            ws.put_f32("hc.parts", parts);
11183            ws.put_f32("hc.injp", injp);
11184            ws.put_f32("hc.inv", inv);
11185            ws.put_f32("hc.low_act", low_act);
11186            let inject_out = if with_inject {
11187                InjectOut::Slab(all)
11188            } else {
11189                ws.put_f32("hc.inj_all", all);
11190                InjectOut::Rows(Vec::new())
11191            };
11192            return Ok((mixed, inject_out));
11193        }
11194
11195        // Buffers are STREAM-MAJOR and CONTIGUOUS ([streams, t, width]) so the three fused
11196        // gate kernels (perf lane attack (c)) each read every stream in one launch; the
11197        // 12 GEMVs stay cuBLASLt. Launches per read gate: 4 norms + 4 down + 1 reduce +
11198        // 4 up + 1 epilogue + 1 inject = 15, vs ~71 before (PROFILE-0: 27.7% of the token
11199        // across 96 calls, nearly all issue latency).
11200        let mut normed = ws.take_f32(e, "hc.normed", streams * t * hidden, 0)?;
11201        if micro_norm {
11202            // One launch for all streams over the plane pointer table (hcmicro).
11203            launch_hc_norm_planes(
11204                e,
11205                ptrs,
11206                &gate.norm_stack,
11207                &mut normed,
11208                hidden,
11209                t,
11210                streams,
11211                eps,
11212            )?;
11213        } else {
11214            for s in 0..streams {
11215                let mut dst = normed.slice_mut(s * t * hidden..(s + 1) * t * hidden);
11216                launch_rms_norm_into_view(e, &planes[s], &gate.norm[s], &mut dst, hidden, t, eps)?;
11217            }
11218        }
11219        // low_act = silu(mean_s down_s @ normed_s). bf16 trunk residency runs the
11220        // projection as ONE batched launch over the stream-major slab (stacked twin,
11221        // same output layout as the per-stream cuBLASLt chain — the A/B/fallback arm).
11222        let trunk_b16 = trunk_bf16_on();
11223        let mut parts = ws.take_f32(e, "hc.parts", streams * t * rank, 0)?;
11224        if let (true, Some(w)) = (trunk_b16, gate.down_b16.as_ref()) {
11225            launch_qmatvec_bf16w(
11226                e,
11227                w,
11228                &normed,
11229                &mut parts,
11230                hidden,
11231                rank,
11232                t,
11233                streams,
11234                rank * hidden,
11235                t * hidden,
11236                hidden,
11237                t * rank,
11238            )?;
11239        } else {
11240            if gate.down[0].len() < rank * hidden {
11241                return Err(
11242                    "qwen4exp_gpu: gate down f32 dropped (trunk_f32_diet) — keep the \
11243                            trunk-bf16 seam ON"
11244                        .into(),
11245                );
11246            }
11247            for s in 0..streams {
11248                let x = normed.slice(s * t * hidden..(s + 1) * t * hidden);
11249                let w = gate.down[s].slice(0..rank * hidden);
11250                let mut out = parts.slice_mut(s * t * rank..(s + 1) * t * rank);
11251                e.linear_device_into(&x, &w, &mut out, t, hidden, rank)?;
11252            }
11253        }
11254        let mut low_act = ws.take_f32(e, "hc.low_act", t * rank, 0)?;
11255        launch_hc_lowrank_reduce(e, &parts, &mut low_act, streams, t, rank)?;
11256        ws.put_f32("hc.parts", parts);
11257
11258        // mixed = mean_s sigmoid(up_s @ low_act) ⊙ normed_s (batched twin: x_bstride 0
11259        // shares the one low_act plane across streams).
11260        let mut gates = ws.take_f32(e, "hc.gates", streams * t * hidden, 0)?;
11261        if let (true, Some(w)) = (trunk_b16, gate.up_b16.as_ref()) {
11262            launch_qmatvec_bf16w(
11263                e,
11264                w,
11265                &low_act,
11266                &mut gates,
11267                rank,
11268                hidden,
11269                t,
11270                streams,
11271                hidden * rank,
11272                0,
11273                rank,
11274                t * hidden,
11275            )?;
11276        } else {
11277            if gate.up[0].len() < hidden * rank {
11278                return Err(
11279                    "qwen4exp_gpu: gate up f32 dropped (trunk_f32_diet) — keep the \
11280                            trunk-bf16 seam ON"
11281                        .into(),
11282                );
11283            }
11284            for s in 0..streams {
11285                let x = low_act.slice(0..t * rank);
11286                let w = gate.up[s].slice(0..hidden * rank);
11287                let mut out = gates.slice_mut(s * t * hidden..(s + 1) * t * hidden);
11288                e.linear_device_into(&x, &w, &mut out, t, rank, hidden)?;
11289            }
11290        }
11291        let mut mixed = ws.take_f32(e, "hc.mixed", t * hidden, 0)?;
11292        launch_hc_mix_epilogue(e, &gates, &normed, &mut mixed, streams, t, hidden)?;
11293        ws.put_f32("hc.gates", gates);
11294        ws.put_f32("hc.low_act", low_act);
11295
11296        let mut inject_out = InjectOut::Rows(Vec::new());
11297        if with_inject {
11298            let inject = gate
11299                .inject
11300                .as_ref()
11301                .ok_or("qwen4exp_gpu: read gate missing inject weights")?;
11302            // trunk_f32_diet: the f32 inject may be a dropped stub — every non-b16
11303            // consumer below must refuse it rather than read garbage.
11304            let inject_dropped = inject.len() < streams * streams * hidden;
11305            let inject_guard = || -> Res<()> {
11306                if inject_dropped {
11307                    return Err("qwen4exp_gpu: inject f32 dropped (trunk_f32_diet) — keep \
11308                                the trunk-bf16 seam ON"
11309                        .into());
11310                }
11311                Ok(())
11312            };
11313            let mut all = ws.take_f32(e, "hc.inj_all", streams * t, 0)?;
11314            if micro_inj {
11315                // Two-stage inject (hcmicro): chunked partials fill the card, the reduce
11316                // applies the sigmoid; the slab goes straight to `gate_write`.
11317                const CHUNKS: usize = 16;
11318                let mut partials = ws.take_f32(e, "hc.inj_part", streams * t * CHUNKS, 0)?;
11319                let w_b16 = if trunk_b16 {
11320                    gate.inject_b16.as_ref()
11321                } else {
11322                    None
11323                };
11324                if w_b16.is_none() {
11325                    inject_guard()?;
11326                }
11327                launch_hc_inject_two_stage(
11328                    e,
11329                    &normed,
11330                    inject,
11331                    w_b16,
11332                    &mut partials,
11333                    &mut all,
11334                    streams,
11335                    t,
11336                    hidden,
11337                    CHUNKS,
11338                )?;
11339                ws.put_f32("hc.inj_part", partials);
11340                inject_out = InjectOut::Slab(all);
11341            } else {
11342                // [streams, t] scalars in one launch; `gate_write` consumes one row per
11343                // stream.
11344                if let (true, Some(w)) = (trunk_b16, gate.inject_b16.as_ref()) {
11345                    launch_hc_inject_gates_b16(e, &normed, w, &mut all, streams, t, hidden)?;
11346                } else {
11347                    inject_guard()?;
11348                    launch_hc_inject_gates(e, &normed, inject, &mut all, streams, t, hidden)?;
11349                }
11350                let mut rows = Vec::with_capacity(streams);
11351                for s in 0..streams {
11352                    let mut row = ws.take_f32(e, INJECT_SLOTS[s], t, 0)?;
11353                    e.copy_range_into(&mut row, 0, &all, s * t, t)?;
11354                    rows.push(row);
11355                }
11356                ws.put_f32("hc.inj_all", all);
11357                inject_out = InjectOut::Rows(rows);
11358            }
11359        }
11360        ws.put_f32("hc.normed", normed);
11361        Ok((mixed, inject_out))
11362    }
11363
11364    /// Unfused read gate — the literal `gated_residual_read` composition from existing
11365    /// engine ops, kept as the A/B twin of the fused arm (`set_hc_fused_gate(false)`) and
11366    /// as the readable statement of the program. ~71 launches per call at hc_count 4.
11367    /// Deliberately NOT workspace-pooled: it is the hc-off measurement twin.
11368    #[allow(clippy::too_many_arguments)]
11369    fn gate_read_legacy(
11370        &self,
11371        e: &Engine,
11372        _ws: &mut StepPool,
11373        gate: &GateW,
11374        planes: &[CudaSlice<f32>],
11375        t: usize,
11376        eps: f32,
11377        with_inject: bool,
11378    ) -> Res<(CudaSlice<f32>, InjectOut)> {
11379        let hidden = self.hidden;
11380        let streams = self.streams;
11381        let rank = gate_rank(gate, hidden, streams)?;
11382        if gate.down[0].len() < rank * hidden {
11383            return Err(
11384                "qwen4exp_gpu: gate f32 originals dropped (trunk_f32_diet) — the \
11385                        legacy gate path needs them (keep hc seams ON)"
11386                    .into(),
11387            );
11388        }
11389        let inv_streams = 1.0 / streams as f32; // pow2 (hc_count 4 / tiny 2) — exact
11390
11391        let mut normed = Vec::with_capacity(streams);
11392        for s in 0..streams {
11393            let mut dst = e.uninit(t * hidden)?;
11394            e.rms_norm(&planes[s], &gate.norm[s], &mut dst, hidden, t, eps)?;
11395            normed.push(dst);
11396        }
11397        // low = silu(sum_s down_s @ normed_s / S)
11398        let mut low = e.linear(&normed[0], &gate.down[0], t, hidden, rank)?;
11399        for s in 1..streams {
11400            let part = e.linear(&normed[s], &gate.down[s], t, hidden, rank)?;
11401            let mut view = low.slice_mut(0..t * rank);
11402            e.axpy_into(&part, 1.0, &mut view, t * rank)?;
11403        }
11404        e.scale_inplace(&mut low, inv_streams, t * rank)?;
11405        let ones = e.htod(&vec![1.0f32; t * rank.max(1)])?;
11406        let mut low_act = e.uninit(t * rank)?;
11407        e.silu_mul(&low, &ones, &mut low_act, t * rank)?;
11408
11409        // mixed = mean_s sigmoid(up_s @ low) ⊙ normed_s
11410        let mut mixed = e.zeros(t * hidden)?;
11411        let mut gate_buf = e.uninit(t * hidden)?;
11412        let mut prod = e.uninit(t * hidden)?;
11413        for s in 0..streams {
11414            let g = e.linear(&low_act, &gate.up[s], t, rank, hidden)?;
11415            e.sigmoid(&g, &mut gate_buf, t * hidden)?;
11416            e.mul(&gate_buf, &normed[s], &mut prod, t * hidden)?;
11417            let mut view = mixed.slice_mut(0..t * hidden);
11418            e.axpy_into(&prod, 1.0, &mut view, t * hidden)?;
11419        }
11420        e.scale_inplace(&mut mixed, inv_streams, t * hidden)?;
11421
11422        let mut inject_out = Vec::new();
11423        if with_inject {
11424            let inject = gate
11425                .inject
11426                .as_ref()
11427                .ok_or("qwen4exp_gpu: read gate missing inject weights")?;
11428            let wide = streams * hidden;
11429            for s in 0..streams {
11430                // Per-(s, s2) [hidden] weight windows of block_inject_weight row s.
11431                let mut acc = {
11432                    let w = inject.slice(s * wide..s * wide + hidden);
11433                    let x = normed[0].slice(0..t * hidden);
11434                    let mut out = e.uninit(t)?;
11435                    e.linear_device_into(&x, &w, &mut out, t, hidden, 1)?;
11436                    out
11437                };
11438                for s2 in 1..streams {
11439                    let w = inject.slice(s * wide + s2 * hidden..s * wide + (s2 + 1) * hidden);
11440                    let x = normed[s2].slice(0..t * hidden);
11441                    let mut part = e.uninit(t)?;
11442                    e.linear_device_into(&x, &w, &mut part, t, hidden, 1)?;
11443                    let mut view = acc.slice_mut(0..t);
11444                    e.axpy_into(&part, 1.0, &mut view, t)?;
11445                }
11446                e.scale_inplace(&mut acc, inv_streams, t)?;
11447                let mut sg = e.uninit(t)?;
11448                e.sigmoid(&acc, &mut sg, t)?;
11449                e.scale_inplace(&mut sg, 2.0, t)?;
11450                inject_out.push(sg);
11451            }
11452        }
11453        Ok((mixed, InjectOut::Rows(inject_out)))
11454    }
11455
11456    /// Write half (`gated_residual_write` twin): plane_s += block_out ⊗ inject_s.
11457    /// Rows = per-stream add_scaled_rows (item-1-era plumbing); Slab = one launch over
11458    /// the plane pointer table (hcmicro).
11459    fn gate_write(
11460        &self,
11461        e: &Engine,
11462        planes: &mut [CudaSlice<f32>],
11463        ptrs: &CudaSlice<u64>,
11464        block_out: &CudaSlice<f32>,
11465        inject: &InjectOut,
11466        t: usize,
11467    ) -> Res<()> {
11468        match inject {
11469            InjectOut::Rows(rows) => {
11470                for (plane, inj) in planes.iter_mut().zip(rows) {
11471                    e.add_scaled_rows(block_out, inj, plane, self.hidden, t)?;
11472                }
11473                Ok(())
11474            }
11475            InjectOut::Slab(slab) => {
11476                launch_hc_write_planes(e, ptrs, block_out, slab, self.hidden, t, self.streams)
11477            }
11478        }
11479    }
11480
11481    /// One decode layer's INTERIOR at t == 1 (graph driver, item 2b): PLE (when
11482    /// present) → attn read gate → mixer → write → mlp read gate, ending with the mlp
11483    /// `mixed`/inject scalars PARKED in their slots for the MoE tail. The exact
11484    /// semantics of the eager `forward` loop body up to `moe_forward`; device-only for
11485    /// GDN layers without PLE, which is what makes those capturable.
11486    #[allow(clippy::too_many_arguments)]
11487    fn layer_interior(
11488        &self,
11489        e: &Engine,
11490        ws: &mut StepPool,
11491        ptrs: &CudaSlice<u64>,
11492        layer: &LayerW,
11493        lstate: &mut LayerState,
11494        planes: &mut [CudaSlice<f32>],
11495        tokens: &[u32],
11496        base_pos: usize,
11497    ) -> Res<()> {
11498        if let (Some(ple), Some(ple_state)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
11499            self.ple_block(
11500                e, layer, ple, &ple.table, ple_state, planes, tokens, 1, false, None,
11501            )?;
11502        }
11503        let (mixed, inject) = self.gate_read(
11504            e,
11505            ws,
11506            ptrs,
11507            &layer.attn_gate,
11508            planes,
11509            1,
11510            layer.eps_attn,
11511            false,
11512        )?;
11513        let block_out = match &layer.mixer {
11514            MixerW::Qsa(qsa) => self.qsa_forward(
11515                e,
11516                ws,
11517                layer,
11518                qsa,
11519                &mixed,
11520                &mut lstate.mixer,
11521                base_pos,
11522                1,
11523                0,
11524                false,
11525            )?,
11526            MixerW::Gdn(gdn) => {
11527                self.gdn_forward(e, ws, layer, gdn, &mixed, &mut lstate.mixer, 1, None)?
11528            }
11529        };
11530        ws.put_f32("hc.mixed", mixed);
11531        self.gate_write(e, planes, ptrs, &block_out, &inject, 1)?;
11532        ws.put_f32("mixer.out", block_out);
11533        put_inject(ws, inject);
11534        let (mixed, inject) = self.gate_read(
11535            e,
11536            ws,
11537            ptrs,
11538            &layer.mlp_gate,
11539            planes,
11540            1,
11541            layer.eps_mlp,
11542            false,
11543        )?;
11544        ws.put_f32("hc.mixed", mixed);
11545        put_inject(ws, inject);
11546        Ok(())
11547    }
11548
11549    /// Per-step MoE routing (graph driver): router GEMV over the parked mlp `mixed`,
11550    /// dtoh (the per-layer host boundary — routing is a HOST twin by lane doctrine, so
11551    /// a whole-step graph is structurally impossible; this is the sync the segment
11552    /// graphs meet at), reference top-k, then H2D of the selection into the slot
11553    /// addresses the captured MoE-tail graph baked.
11554    fn moe_route_slots(&self, e: &Engine, ws: &mut StepPool, moe: &MoeW, layer: u32) -> Res<()> {
11555        let hidden = self.hidden;
11556        let experts = moe.plan.expert_count as usize;
11557        let selected = moe.plan.experts_per_token as usize;
11558        let mixed = ws.take_f32(e, "hc.mixed", hidden, 0)?;
11559        let mut router_out = ws.take_f32(e, "moe.router", experts, 0)?;
11560        let none: Option<CudaSlice<u8>> = None;
11561        let rb = if router_bf16_on() {
11562            &moe.router_b16
11563        } else {
11564            &none
11565        };
11566        linear_trunk_into(
11567            e,
11568            &moe.router,
11569            rb,
11570            &mixed,
11571            &mut router_out,
11572            1,
11573            hidden,
11574            experts,
11575        )?;
11576        // Device router (devtwin lane): the route stays on device — no dtoh, no host
11577        // top-k, no selection h2d. Writes land in the SAME parked slots the captured
11578        // MoE-tail graph baked (take-without-upload + put preserves the address).
11579        if router_dev_on() && route_dev_geometry(experts, selected) {
11580            let mut sel = ws.take_i32_slot(e, "moe.sel", selected, 0)?;
11581            let mut w = ws.take_f32(e, "moe.w", selected, 0)?;
11582            route_topk_device(
11583                e,
11584                &router_out,
11585                &mut sel,
11586                &mut w,
11587                None,
11588                experts,
11589                selected,
11590                1,
11591                layer,
11592            )?;
11593            // DIAGNOSTIC ONLY (`MEMRA_Q4E_ROUTE_SYNC=1`, never a serving arm): restore the
11594            // host arm's per-layer SYNC structure while keeping the device route, to
11595            // separate "the kernel costs" from "the missing sync costs" in the
11596            // graphs-ON regression (devtwin: graphs OFF the seam wins 1.083x, graphs ON
11597            // it loses — PROFILE-9 §3).
11598            if route_sync_diag() {
11599                e.gpu.stream().synchronize()?;
11600            }
11601            ws.put_i32("moe.sel", sel);
11602            ws.put_f32("moe.w", w);
11603            ws.put_f32("moe.router", router_out);
11604            ws.put_f32("hc.mixed", mixed);
11605            return Ok(());
11606        }
11607        let logits = e.dtoh_view(&router_out.slice(0..experts))?;
11608        ws.put_f32("moe.router", router_out);
11609        ws.put_f32("hc.mixed", mixed);
11610        let route = host_route_softmax_topk(&logits, selected);
11611        let sel_host: Vec<i32> = route.iter().map(|&(x, _)| x as i32).collect();
11612        let w_host: Vec<f32> = route.iter().map(|&(_, w)| w).collect();
11613        ws.write_i32(e, "moe.sel", &sel_host)?;
11614        ws.write_f32(e, "moe.w", &w_host)?;
11615        Ok(())
11616    }
11617
11618    /// The grouped-MoE tail at t == 1 over PARKED slots (graph driver): sel matvecs →
11619    /// shared expert → mlp gate_write. Same kernels/order as the `moe_forward` grouped
11620    /// block; the selection indices/weights arrive via `moe_route_slots` into the baked
11621    /// slot addresses.
11622    fn moe_grouped_tail_slots(
11623        &self,
11624        e: &Engine,
11625        ws: &mut StepPool,
11626        ptrs: &CudaSlice<u64>,
11627        moe: &MoeW,
11628        planes: &mut [CudaSlice<f32>],
11629    ) -> Res<()> {
11630        let hidden = self.hidden;
11631        let ff = moe.plan.expert_intermediate_size as usize;
11632        let n_sel = moe.plan.experts_per_token as usize;
11633        let (
11634            BankHalf::Nvfp4 {
11635                codes: gc,
11636                scales: gs,
11637                macros_dev: gm,
11638                ..
11639            },
11640            BankHalf::Nvfp4 {
11641                codes: uc,
11642                scales: us,
11643                macros_dev: um,
11644                ..
11645            },
11646            BankHalf::Nvfp4 {
11647                codes: dc,
11648                scales: ds,
11649                macros_dev: dm,
11650                ..
11651            },
11652        ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
11653        else {
11654            return Err("qwen4exp_gpu: grouped tail on a non-NVFP4 bank".into());
11655        };
11656        let mixed = ws.take_f32(e, "hc.mixed", hidden, 0)?;
11657        let sel = ws
11658            .i32s
11659            .remove("moe.sel")
11660            .ok_or("step workspace: moe.sel is not parked")?;
11661        let w_dev = ws.take_f32(e, "moe.w", n_sel, 0)?;
11662        let mut act = ws.take_f32(e, "moe.act", n_sel * ff, 0)?;
11663        // Fused gate+up+silu (round 4): the graph bakes whichever arm is live at
11664        // capture (fresh state per A/B arm); bit-identical to the chain.
11665        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
11666            launch_nvfp4_sel_gu_silu(
11667                e,
11668                (gc, gs, gm),
11669                (uc, us, um),
11670                Some(&sel),
11671                0,
11672                n_sel,
11673                &mixed,
11674                &mut act,
11675                hidden,
11676                ff,
11677                None,
11678            )?;
11679        } else {
11680            let mut yg = ws.take_f32(e, "moe.yg", n_sel * ff, 0)?;
11681            let mut yu = ws.take_f32(e, "moe.yu", n_sel * ff, 0)?;
11682            launch_nvfp4_sel_matvec(e, gc, gs, gm, &sel, &mixed, &mut yg, n_sel, hidden, ff, 0)?;
11683            launch_nvfp4_sel_matvec(e, uc, us, um, &sel, &mixed, &mut yu, n_sel, hidden, ff, 0)?;
11684            e.silu_mul(&yg, &yu, &mut act, n_sel * ff)?;
11685            ws.put_f32("moe.yg", yg);
11686            ws.put_f32("moe.yu", yu);
11687        }
11688        let mut partial = ws.take_f32(e, "moe.partial", n_sel * hidden, 0)?;
11689        launch_nvfp4_sel_matvec(
11690            e,
11691            dc,
11692            ds,
11693            dm,
11694            &sel,
11695            &act,
11696            &mut partial,
11697            n_sel,
11698            ff,
11699            hidden,
11700            ff,
11701        )?;
11702        let mut out = ws.take_f32(e, "moe.out", hidden, 0)?;
11703        e.axpy_rows_seq_into(&partial, &w_dev, &mut out, hidden, n_sel)?;
11704        ws.put_i32("moe.sel", sel);
11705        ws.put_f32("moe.w", w_dev);
11706        ws.put_f32("moe.act", act);
11707        ws.put_f32("moe.partial", partial);
11708        let out = self.moe_shared_tail(e, ws, moe, &mixed, out, 1)?;
11709        ws.put_f32("hc.mixed", mixed);
11710        let inject = take_inject(e, ws, self.streams, 1)?;
11711        self.gate_write(e, planes, ptrs, &out, &inject, 1)?;
11712        ws.put_f32("moe.out", out);
11713        put_inject(ws, inject);
11714        Ok(())
11715    }
11716
11717    /// Graph-mode decode tail (item 2b): per layer, replay (or lazily capture) the
11718    /// interior graph, run the host routing boundary, replay the MoE-tail graph; then
11719    /// the exit graph and one logits dtoh. Falls back to the eager helpers per layer
11720    /// where a graph is structurally unavailable (QSA/PLE interiors — the indexer host
11721    /// twin and PLE host hashing live there; non-NVFP4 banks for the tail).
11722    fn forward_graphs_tail(
11723        &self,
11724        e: &Engine,
11725        state: &mut Qwen4ExpState,
11726        mut planes: Vec<CudaSlice<f32>>,
11727        ptrs: CudaSlice<u64>,
11728        base_pos: usize,
11729    ) -> Res<Vec<f32>> {
11730        let mut graphs = std::mem::take(&mut state.graphs);
11731        if graphs.a.len() != self.layers.len() {
11732            graphs.a = (0..self.layers.len()).map(|_| None).collect();
11733            graphs.b = (0..self.layers.len()).map(|_| None).collect();
11734        }
11735        let ws = &mut state.ws;
11736        let tokens = &state.tokens;
11737        for (li, (layer, lstate)) in self.layers.iter().zip(state.layers.iter_mut()).enumerate() {
11738            let a_ok = matches!(layer.mixer, MixerW::Gdn(_)) && layer.ple.is_none();
11739            if a_ok {
11740                if graphs.a[li].is_none() {
11741                    graphs.a[li] = Some(e.capture_graph_retained_nowarm(|eng| {
11742                        self.layer_interior(
11743                            eng,
11744                            ws,
11745                            &ptrs,
11746                            layer,
11747                            lstate,
11748                            &mut planes,
11749                            tokens,
11750                            base_pos,
11751                        )
11752                    })?);
11753                }
11754                graphs.a[li].as_ref().unwrap().0.launch()?;
11755            } else {
11756                self.layer_interior(e, ws, &ptrs, layer, lstate, &mut planes, tokens, base_pos)?;
11757            }
11758            let b_ok = moe_sel_path_on()
11759                && matches!(
11760                    (
11761                        &layer.moe.bank.gate,
11762                        &layer.moe.bank.up,
11763                        &layer.moe.bank.down
11764                    ),
11765                    (
11766                        BankHalf::Nvfp4 { .. },
11767                        BankHalf::Nvfp4 { .. },
11768                        BankHalf::Nvfp4 { .. }
11769                    )
11770                );
11771            if b_ok {
11772                self.moe_route_slots(e, ws, &layer.moe, layer.index)?;
11773                if graphs.b[li].is_none() {
11774                    graphs.b[li] = Some(e.capture_graph_retained_nowarm(|eng| {
11775                        self.moe_grouped_tail_slots(eng, ws, &ptrs, &layer.moe, &mut planes)
11776                    })?);
11777                }
11778                graphs.b[li].as_ref().unwrap().0.launch()?;
11779            } else {
11780                // Eager MoE (per-expert path routes internally) + mlp write.
11781                let mixed = ws.take_f32(e, "hc.mixed", self.hidden, 0)?;
11782                let mlp = self.moe_forward(e, ws, &layer.moe, &mixed, 1, false, layer.index)?;
11783                ws.put_f32("hc.mixed", mixed);
11784                let inject = take_inject(e, ws, self.streams, 1)?;
11785                self.gate_write(e, &mut planes, &ptrs, &mlp, &inject, 1)?;
11786                ws.put_f32("moe.out", mlp);
11787                put_inject(ws, inject);
11788            }
11789        }
11790        if graphs.exit.is_none() {
11791            graphs.exit = Some(e.capture_graph_retained_nowarm(|eng| {
11792                let x = self
11793                    .gate_read_inner(
11794                        eng,
11795                        ws,
11796                        &ptrs,
11797                        &self.exit_mixer,
11798                        &planes,
11799                        1,
11800                        self.exit_eps,
11801                        false,
11802                        false,
11803                    )?
11804                    .0;
11805                let mut logits = ws.take_f32(eng, "logits", self.vocab, 0)?;
11806                linear_trunk_into(
11807                    eng,
11808                    &self.output,
11809                    &self.output_b16,
11810                    &x,
11811                    &mut logits,
11812                    1,
11813                    self.hidden,
11814                    self.vocab,
11815                )?;
11816                ws.put_f32("hc.mixed", x);
11817                ws.put_f32("logits", logits);
11818                Ok(())
11819            })?);
11820        }
11821        graphs.exit.as_ref().unwrap().0.launch()?;
11822        let out = {
11823            let logits = ws.peek_f32("logits")?;
11824            e.dtoh_view(&logits.slice(0..self.vocab))?
11825        };
11826        for (s, plane) in planes.into_iter().enumerate() {
11827            ws.put_f32(PLANE_SLOTS[s], plane);
11828        }
11829        ws.put_u64("hc.ptrs", ptrs);
11830        state.pos += 1;
11831        state.graphs = graphs;
11832        Ok(out)
11833    }
11834
11835    /// QSA layer: fused [q|gate] projection, q/k RMSNorm, partial rope, KV append, the
11836    /// host indexer-selection twin, dense masked attention, sigmoid fused output gate.
11837    ///
11838    /// Indexer update + selection for one chunk (factored from `qsa_forward` so the
11839    /// TP2 route shares it verbatim): idx projection, the idxcache device raw-key
11840    /// cache maintenance, host/pooled cache updates, the device-scorer selection, and
11841    /// the idxq audit twin. Returns per-row selections (`RowSel`).
11842    #[allow(clippy::too_many_arguments)]
11843    fn qsa_update_select(
11844        &self,
11845        e: &Engine,
11846        ws: &mut StepPool,
11847        qsa: &QsaW,
11848        eps: f32,
11849        mixed: &CudaSlice<f32>,
11850        raw_keys: &mut IdxRawCache,
11851        pooled_keys: &mut Vec<f32>,
11852        pooled_dev: &mut Option<CudaSlice<f32>>,
11853        pooled_dev_rows: &mut usize,
11854        raw_dev: &mut Option<IdxRawDev>,
11855        raw_dev_rows: &mut usize,
11856        mut idx_audit: Option<&mut Box<IdxAudit>>,
11857        base_pos: usize,
11858        t: usize,
11859        pos_off: usize,
11860        exact: bool,
11861    ) -> Res<Vec<RowSel>> {
11862        let hidden = self.hidden;
11863        let base = qsa.attn.rope.base;
11864        let t_kv = base_pos + t;
11865        // Indexer selection: host twin of micro_block_selection_mask over the raw-key cache.
11866        let overlay = &qsa.overlay;
11867        let idx_dim = overlay.head_dim as usize;
11868        let qk_width = (overlay.query_heads as usize + overlay.kv_heads as usize) * idx_dim;
11869        if overlay.kv_heads != 1 {
11870            return Err("qwen4exp_gpu: indexer with more than one key head".into());
11871        }
11872        let idx_proj = prof_section(e, "qsa.idx_proj", || {
11873            let mut idx_proj = ws.take_f32(e, "qsa.idxp", t * qk_width, 0)?;
11874            if exact && t > 1 {
11875                let wv = qsa.idx_proj.slice(0..qsa.idx_proj.len());
11876                for tok in 0..t {
11877                    let xv = mixed.slice(tok * hidden..(tok + 1) * hidden);
11878                    let mut yv = idx_proj.slice_mut(tok * qk_width..(tok + 1) * qk_width);
11879                    e.linear_device_into(&xv, &wv, &mut yv, 1, hidden, qk_width)?;
11880                }
11881            } else {
11882                e.linear_device_into(mixed, &qsa.idx_proj, &mut idx_proj, t, hidden, qk_width)?;
11883            }
11884            Ok(idx_proj)
11885        })?;
11886        // Device raw-key cache (devtwin stage 3, `idxcache`): row r of `raw_dev` is
11887        // absolute cache row r. Below the selection horizon ((base_pos + t)/block <=
11888        // budget — the indexer_select_rows fast path, decided from positions alone)
11889        // the selection needs NO device data, so the k-part rows append d2d and the
11890        // idx_proj dtoh dies; the host cache lags and materializes LAZILY at the first
11891        // scored chunk — the same bytes dtoh'd later, bit-identical by construction.
11892        // Mid-run seam flips on a live state pay their debt loudly here: OFF->ON
11893        // backfills the device from the host (h2d, exact bytes); any host lag is paid
11894        // BEFORE this chunk lands whenever the fast path does not take it.
11895        let dev_cache = idx_cache_on();
11896        let block_size = overlay.block_size as usize;
11897        let all_full = (base_pos + t) / block_size <= overlay.budget_blocks as usize;
11898        let host_rows = raw_keys.rows(idx_dim);
11899        if *raw_dev_rows > host_rows && !(dev_cache && all_full) {
11900            // Lazy host materialization (or an ON->OFF flip's debt): dtoh the delta
11901            // VERBATIM — quantized formats materialize their own bytes, no re-quant,
11902            // so the seam's bit-identity contract is preserved per format.
11903            idx_materialize_host(e, raw_keys, raw_dev, *raw_dev_rows, idx_dim)?;
11904        }
11905        if dev_cache {
11906            let host_rows = raw_keys.rows(idx_dim);
11907            let base_rows = (*raw_dev_rows).max(host_rows);
11908            let cap_rows = (base_rows + t).next_power_of_two().max(64);
11909            let q_off = overlay.query_heads as usize * idx_dim;
11910            match &mut *raw_keys {
11911                IdxRawCache::F32(h) => {
11912                    let want = (base_rows + t) * idx_dim;
11913                    let grow = match raw_dev.as_ref() {
11914                        Some(IdxRawDev::F32(m)) => m.len() < want,
11915                        Some(_) => return Err("idxcache: device format lag on f32".into()),
11916                        None => true,
11917                    };
11918                    if grow {
11919                        let mut fresh = e.uninit(cap_rows * idx_dim)?;
11920                        if let (Some(IdxRawDev::F32(old)), rows) = (raw_dev.as_ref(), *raw_dev_rows)
11921                        {
11922                            if rows > 0 {
11923                                e.copy_range_into(&mut fresh, 0, old, 0, rows * idx_dim)?;
11924                            }
11925                        }
11926                        *raw_dev = Some(IdxRawDev::F32(fresh));
11927                    }
11928                    let Some(IdxRawDev::F32(m)) = raw_dev.as_mut() else {
11929                        unreachable!("allocated above");
11930                    };
11931                    if host_rows > *raw_dev_rows {
11932                        // OFF->ON flip on a live state: backfill the device from host.
11933                        let mut view = m.slice_mut(*raw_dev_rows * idx_dim..host_rows * idx_dim);
11934                        e.gpu
11935                            .stream()
11936                            .memcpy_htod(&h[*raw_dev_rows * idx_dim..], &mut view)?;
11937                        *raw_dev_rows = host_rows;
11938                    }
11939                    launch_copy_rows_col(
11940                        e,
11941                        &idx_proj,
11942                        m,
11943                        t,
11944                        idx_dim,
11945                        qk_width,
11946                        q_off,
11947                        *raw_dev_rows,
11948                    )?;
11949                }
11950                IdxRawCache::Q8(h) => {
11951                    let rb = q8_row_bytes(idx_dim);
11952                    let want = (base_rows + t) * rb;
11953                    let grow = match raw_dev.as_ref() {
11954                        Some(IdxRawDev::Q8(m)) => m.len() < want,
11955                        Some(_) => return Err("idxcache: device format lag on q8".into()),
11956                        None => true,
11957                    };
11958                    if grow {
11959                        let mut fresh = e.alloc_u8_uninit(cap_rows * rb)?;
11960                        if let (Some(IdxRawDev::Q8(old)), rows) = (raw_dev.as_ref(), *raw_dev_rows)
11961                        {
11962                            if rows > 0 {
11963                                let mut dst = fresh.slice_mut(0..rows * rb);
11964                                e.gpu
11965                                    .stream()
11966                                    .memcpy_dtod(&old.slice(0..rows * rb), &mut dst)?;
11967                            }
11968                        }
11969                        *raw_dev = Some(IdxRawDev::Q8(fresh));
11970                    }
11971                    let Some(IdxRawDev::Q8(m)) = raw_dev.as_mut() else {
11972                        unreachable!("allocated above");
11973                    };
11974                    if host_rows > *raw_dev_rows {
11975                        let mut view = m.slice_mut(*raw_dev_rows * rb..host_rows * rb);
11976                        e.gpu
11977                            .stream()
11978                            .memcpy_htod(&h[*raw_dev_rows * rb..host_rows * rb], &mut view)?;
11979                        *raw_dev_rows = host_rows;
11980                    }
11981                    launch_q4e_idx_append_q8(
11982                        e,
11983                        &idx_proj,
11984                        m,
11985                        t,
11986                        idx_dim,
11987                        qk_width,
11988                        q_off,
11989                        *raw_dev_rows,
11990                    )?;
11991                }
11992                IdxRawCache::Bf16(h) => {
11993                    let want = (base_rows + t) * idx_dim;
11994                    let grow = match raw_dev.as_ref() {
11995                        Some(IdxRawDev::Bf16(m)) => m.len() < want,
11996                        Some(_) => return Err("idxcache: device format lag on bf16".into()),
11997                        None => true,
11998                    };
11999                    if grow {
12000                        let mut fresh = unsafe { e.gpu.stream().alloc::<u16>(cap_rows * idx_dim)? };
12001                        if let (Some(IdxRawDev::Bf16(old)), rows) =
12002                            (raw_dev.as_ref(), *raw_dev_rows)
12003                        {
12004                            if rows > 0 {
12005                                let mut dst = fresh.slice_mut(0..rows * idx_dim);
12006                                e.gpu
12007                                    .stream()
12008                                    .memcpy_dtod(&old.slice(0..rows * idx_dim), &mut dst)?;
12009                            }
12010                        }
12011                        *raw_dev = Some(IdxRawDev::Bf16(fresh));
12012                    }
12013                    let Some(IdxRawDev::Bf16(m)) = raw_dev.as_mut() else {
12014                        unreachable!("allocated above");
12015                    };
12016                    if host_rows > *raw_dev_rows {
12017                        let mut view = m.slice_mut(*raw_dev_rows * idx_dim..host_rows * idx_dim);
12018                        e.gpu.stream().memcpy_htod(
12019                            &h[*raw_dev_rows * idx_dim..host_rows * idx_dim],
12020                            &mut view,
12021                        )?;
12022                        *raw_dev_rows = host_rows;
12023                    }
12024                    launch_q4e_idx_append_bf16(
12025                        e,
12026                        &idx_proj,
12027                        m,
12028                        t,
12029                        idx_dim,
12030                        qk_width,
12031                        q_off,
12032                        *raw_dev_rows,
12033                    )?;
12034                }
12035            }
12036            *raw_dev_rows += t;
12037        }
12038        // idxq selection-identity audit (instrument): the f32 twin cache is fed on
12039        // EVERY chunk — this re-adds the idx_proj dtoh the idxcache seam removed, and
12040        // is never a perf arm. Fed BEFORE selection so the twin includes this chunk.
12041        if let Some(audit) = idx_audit.as_deref_mut() {
12042            let q_off = overlay.query_heads as usize * idx_dim;
12043            let rows_f = e.dtoh_view(&idx_proj.slice(0..t * qk_width))?;
12044            let IdxRawCache::F32(twin) = &mut audit.raw_f32 else {
12045                return Err("idxq audit: twin cache is not f32".into());
12046            };
12047            for row in 0..t {
12048                twin.extend_from_slice(&rows_f[row * qk_width + q_off..(row + 1) * qk_width]);
12049            }
12050        }
12051        let sels: Vec<RowSel> = if dev_cache && all_full {
12052            ws.put_f32("qsa.idxp", idx_proj);
12053            (0..t)
12054                .map(|qt| RowSel {
12055                    full: true,
12056                    blocks: Vec::new(),
12057                    visible: base_pos + qt + 1,
12058                })
12059                .collect()
12060        } else {
12061            let idx_rows = e.dtoh_view(&idx_proj.slice(0..t * qk_width))?;
12062            ws.put_f32("qsa.idxp", idx_proj);
12063            let q_off = overlay.query_heads as usize * idx_dim;
12064            for row in 0..t {
12065                raw_keys.append_rows_f32(
12066                    &idx_rows[row * qk_width + q_off..(row + 1) * qk_width],
12067                    1,
12068                    idx_dim,
12069                );
12070            }
12071            // Device block scorer (long-context lane): the host twin is O(context) per
12072            // token per layer — 52% of the decode token at a 32k fill (smoke ladder),
12073            // and quadratic across a long prefill. Scores are bit-identical (same
12074            // arithmetic order), so the selection is the same set. `idx_dev` (default
12075            // ON) is the rollback seam; the host twin remains the reference and the
12076            // TP2 path.
12077            let dev_scorer = idx_dev_on();
12078            let sels = prof_section(e, "qsa.idx_host", || {
12079                indexer_select_rows(
12080                    overlay,
12081                    base,
12082                    qsa.yarn.as_ref().map(|y| (y.ff_host.as_slice(), y.mscale)),
12083                    eps,
12084                    &qsa.idx_q_norm,
12085                    &qsa.idx_k_norm,
12086                    &idx_rows,
12087                    raw_keys,
12088                    pooled_keys,
12089                    if dev_scorer {
12090                        Some((e, pooled_dev, pooled_dev_rows))
12091                    } else {
12092                        None
12093                    },
12094                    base_pos,
12095                    t,
12096                    t_kv,
12097                    pos_off,
12098                )
12099            })?;
12100            // Audit compare: recompute every scored row's selection from the f32 twin
12101            // caches (host scorer) and count flipped sets. Full rows cannot flip (the
12102            // structural fast path reads no scores) and are skipped. BOUNDED to
12103            // decode/draft/verify shapes (t <= 8): a prefill chunk would pay the
12104            // O(context) host selection PER ROW x 2048 rows x every chunk — quadratic
12105            // across a long prefill, the exact cost the device scorer retired. Prefill
12106            // chunks still FEED the twin (above); the twin's pooled cache catches up
12107            // lazily inside its next compare. Stated in the receipt: the flip rate is
12108            // measured on decode/verify rows at depth.
12109            if let Some(audit) = idx_audit.as_deref_mut() {
12110                if t <= 8 && sels.iter().any(|s| !s.full) {
12111                    let twin_sels = indexer_select_rows(
12112                        overlay,
12113                        base,
12114                        qsa.yarn.as_ref().map(|y| (y.ff_host.as_slice(), y.mscale)),
12115                        eps,
12116                        &qsa.idx_q_norm,
12117                        &qsa.idx_k_norm,
12118                        &idx_rows,
12119                        &audit.raw_f32,
12120                        &mut audit.pooled_f32,
12121                        None,
12122                        base_pos,
12123                        t,
12124                        t_kv,
12125                        pos_off,
12126                    )?;
12127                    use std::sync::atomic::Ordering::Relaxed;
12128                    for (a, b) in sels.iter().zip(&twin_sels) {
12129                        if a.full && b.full {
12130                            continue;
12131                        }
12132                        IDXQ_AUDIT_ROWS.fetch_add(1, Relaxed);
12133                        if a.full != b.full || a.blocks != b.blocks {
12134                            IDXQ_AUDIT_FLIPPED.fetch_add(1, Relaxed);
12135                            let mut diff = 0u64;
12136                            let (sa, sb) = (&a.blocks, &b.blocks);
12137                            let seta: std::collections::BTreeSet<_> = sa.iter().collect();
12138                            let setb: std::collections::BTreeSet<_> = sb.iter().collect();
12139                            diff += seta.symmetric_difference(&setb).count() as u64;
12140                            IDXQ_AUDIT_BLOCKS.fetch_add(diff, Relaxed);
12141                        }
12142                    }
12143                }
12144            }
12145            sels
12146        };
12147        Ok(sels)
12148    }
12149
12150    fn qsa_forward(
12151        &self,
12152        e: &Engine,
12153        ws: &mut StepPool,
12154        layer: &LayerW,
12155        qsa: &QsaW,
12156        mixed: &CudaSlice<f32>,
12157        mstate: &mut MixerState,
12158        base_pos: usize,
12159        t: usize,
12160        // Rope/indexer position offset (0 = trunk; 1 = the MTP draft, see
12161        // `indexer_mask_rows`). Causality stays cache-row based either way.
12162        pos_off: usize,
12163        // Verify-exact rows (mtp-spec): per-token indexer-projection launches — the
12164        // one cuBLASLt op in this path whose m > 1 algorithm may differ from the
12165        // decode-shape GEMV; m == 1 per token keeps rows bit-identical to decode.
12166        exact: bool,
12167    ) -> Res<CudaSlice<f32>> {
12168        let MixerState::Qsa {
12169            kv,
12170            raw_keys,
12171            pooled_keys,
12172            pooled_dev,
12173            pooled_dev_rows,
12174            raw_dev,
12175            raw_dev_rows,
12176            idx_audit,
12177        } = mstate
12178        else {
12179            return Err(format!(
12180                "qwen4exp_gpu: QSA layer {} bound to non-QSA state",
12181                layer.index
12182            )
12183            .into());
12184        };
12185        let hidden = self.hidden;
12186        let nh = qsa.attn.query_heads as usize;
12187        let nkv = qsa.attn.kv_heads as usize;
12188        let hd = qsa.attn.key_head_dim as usize;
12189        let eps = layer.eps_attn;
12190        // Mask-slot reserve: [t, capacity] never grows mid-run (t_kv does, every step).
12191        let cap = kv.capacity_rows(nkv * hd);
12192
12193        let n_rot = qsa.attn.rope.dimensions as usize;
12194        let base = qsa.attn.rope.base;
12195        let (q, gate) = prof_section(e, "qsa.proj", || {
12196            let mut q_fused = ws.take_f32(e, "qsa.qf", t * 2 * nh * hd, 0)?;
12197            let mut k_new = ws.take_f32(e, "qsa.k", t * nkv * hd, 0)?;
12198            let mut v_new = ws.take_f32(e, "qsa.v", t * nkv * hd, 0)?;
12199            // Proj stack (round 4): wq/wk/wv in ONE launch over the row-stacked twin;
12200            // per-row bit-identical to the per-mat launches (OFF arm = row-offset views
12201            // of the same stack).
12202            if let (true, Some(stack)) = (
12203                t == 1 && proj_stack_on() && trunk_bf16_on(),
12204                qsa.proj_b16.as_ref(),
12205            ) {
12206                launch_qmatvec_bf16w_multi4(
12207                    e,
12208                    stack,
12209                    mixed,
12210                    &[
12211                        (&q_fused, 2 * nh * hd),
12212                        (&k_new, nkv * hd),
12213                        (&v_new, nkv * hd),
12214                    ],
12215                    hidden,
12216                )?;
12217            } else {
12218                linear_trunk_stacked_into(
12219                    e,
12220                    &qsa.wq,
12221                    &qsa.proj_b16,
12222                    0,
12223                    mixed,
12224                    &mut q_fused,
12225                    t,
12226                    hidden,
12227                    2 * nh * hd,
12228                )?;
12229                linear_trunk_stacked_into(
12230                    e,
12231                    &qsa.wk,
12232                    &qsa.proj_b16,
12233                    2 * nh * hd,
12234                    mixed,
12235                    &mut k_new,
12236                    t,
12237                    hidden,
12238                    nkv * hd,
12239                )?;
12240                linear_trunk_stacked_into(
12241                    e,
12242                    &qsa.wv,
12243                    &qsa.proj_b16,
12244                    2 * nh * hd + nkv * hd,
12245                    mixed,
12246                    &mut v_new,
12247                    t,
12248                    hidden,
12249                    nkv * hd,
12250                )?;
12251            }
12252            let mut q = ws.take_f32(e, "qsa.q", t * nh * hd, 0)?;
12253            let mut gate = ws.take_f32(e, "qsa.gate", t * nh * hd, 0)?;
12254            e.q_gate_split(&q_fused, &mut q, &mut gate, hd, nh, t)?;
12255            ws.put_f32("qsa.qf", q_fused);
12256            let mut q = if let Some(norm) = qsa.q_norm.as_ref() {
12257                let mut dst = ws.take_f32(e, "qsa.qn", t * nh * hd, 0)?;
12258                e.rms_norm(&q, norm, &mut dst, hd, t * nh, eps)?;
12259                ws.put_f32("qsa.q", q);
12260                dst
12261            } else {
12262                q
12263            };
12264            let mut k_new = if let Some(norm) = qsa.k_norm.as_ref() {
12265                let mut dst = ws.take_f32(e, "qsa.kn", t * nkv * hd, 0)?;
12266                e.rms_norm(&k_new, norm, &mut dst, hd, t * nkv, eps)?;
12267                ws.put_f32("qsa.k", k_new);
12268                dst
12269            } else {
12270                k_new
12271            };
12272            let positions: Vec<i32> = (0..t).map(|i| (base_pos + i + pos_off) as i32).collect();
12273            let pos_dev = ws.take_i32(e, "qsa.pos", &positions, 0)?;
12274            if let Some(yarn) = qsa.yarn.as_ref() {
12275                e.rope_neox_ffm(
12276                    &mut q,
12277                    &pos_dev,
12278                    hd,
12279                    n_rot,
12280                    nh,
12281                    t,
12282                    base,
12283                    1.0,
12284                    &yarn.ff,
12285                    yarn.mscale,
12286                )?;
12287                e.rope_neox_ffm(
12288                    &mut k_new,
12289                    &pos_dev,
12290                    hd,
12291                    n_rot,
12292                    nkv,
12293                    t,
12294                    base,
12295                    1.0,
12296                    &yarn.ff,
12297                    yarn.mscale,
12298                )?;
12299            } else {
12300                e.rope_neox(&mut q, &pos_dev, hd, n_rot, nh, t, base, 1.0)?;
12301                e.rope_neox(&mut k_new, &pos_dev, hd, n_rot, nkv, t, base, 1.0)?;
12302            }
12303            ws.put_i32("qsa.pos", pos_dev);
12304            // Explicit lengths: workspace slots may be larger than this chunk.
12305            match kv {
12306                QsaKvStore::F32 { k, v } => {
12307                    e.copy_range_into(k, base_pos * nkv * hd, &k_new, 0, t * nkv * hd)?;
12308                    e.copy_range_into(v, base_pos * nkv * hd, &v_new, 0, t * nkv * hd)?;
12309                }
12310                // kvq lane: append-quantize the post-RoPE rows in place (K=q8_0,
12311                // V=q5_1) — same slot addressing, no host round trip.
12312                QsaKvStore::Q8Q5 { k, v } => {
12313                    launch_q4e_kv_append(e, &k_new, &v_new, k, v, base_pos, t, nkv * hd)?;
12314                }
12315            }
12316            ws.put_f32(
12317                if qsa.k_norm.is_some() {
12318                    "qsa.kn"
12319                } else {
12320                    "qsa.k"
12321                },
12322                k_new,
12323            );
12324            ws.put_f32("qsa.v", v_new);
12325            Ok((q, gate))
12326        })?;
12327        let t_kv = base_pos + t;
12328        let sels = self.qsa_update_select(
12329            e,
12330            ws,
12331            qsa,
12332            eps,
12333            mixed,
12334            raw_keys,
12335            pooled_keys,
12336            pooled_dev,
12337            pooled_dev_rows,
12338            raw_dev,
12339            raw_dev_rows,
12340            idx_audit.as_mut(),
12341            base_pos,
12342            t,
12343            pos_off,
12344            exact,
12345        )?;
12346        let overlay = &qsa.overlay;
12347
12348        let scale = match qsa.attn.scale {
12349            memra_gguf::model_plan::AttentionScale::InverseSqrtKeyDim => 1.0 / (hd as f32).sqrt(),
12350            memra_gguf::model_plan::AttentionScale::Fixed(scale) => scale,
12351        };
12352        // Long-context attention form: past the masked kernel's smem bound the dense
12353        // [t, t_kv] mask is impossible (bytes scale with context), so the block-list
12354        // kernel consumes the selection directly — BIT-IDENTICAL math (the masked
12355        // kernel's -1e30 rows contribute exact 0.0 terms in the same ascending order;
12356        // gate arm `fixture-longatt` + the blocklist kernel oracle).
12357        //
12358        // AUTO engages when the block-list form reads STRICTLY FEWER KV rows than the
12359        // dense form — i.e. as soon as the indexer actually drops blocks (any non-full
12360        // row, which on real geometry means position >= 2051) — and always past the
12361        // masked kernel's smem bound. This is where QSA's bounded-attention claim
12362        // becomes real: the dense mask still READS every t_kv row (the mask only zeroes
12363        // scores), so masked decode is O(context) bytes, while the block-list form reads
12364        // the <= 2052 selected rows at ANY depth. Measured motivation (smoke ladder,
12365        // yarn-1M, KV on card 1): masked decode at a 4k fill spent 97% of the token in
12366        // `qsa.sdpa` at 673 ms/token. Below the drop point every row IS the full prefix,
12367        // so the two forms read the same rows and AUTO keeps the historical masked path
12368        // (byte-stable receipts). `MEMRA_Q4E_SEAMS=longatt` forces it for the gate A/B;
12369        // `longatt=0` restores the masked-only behavior (and its long-context refusal).
12370        // kvq lane: the quantized cache has no masked-kernel form — the block-list
12371        // program (with in-place dequant) is the ONLY read path, at every depth. Below
12372        // the drop point every row is the full prefix, so the block-list form reads the
12373        // same rows the masked kernel would; there is no byte-stability question because
12374        // a quantized state has no historical masked receipts.
12375        let long_att = if kv.is_quant() {
12376            if longatt_mode() == LongAttMode::Off {
12377                return Err(
12378                    "qwen4exp_gpu: kvq requires the block-list attention form (longatt=off)".into(),
12379                );
12380            }
12381            true
12382        } else {
12383            match longatt_mode() {
12384                LongAttMode::Force => true,
12385                LongAttMode::Auto => t_kv > SDPA_MASK_TKV_BOUND || sels.iter().any(|s| !s.full),
12386                LongAttMode::Off => false,
12387            }
12388        };
12389        let block_size = overlay.block_size as usize;
12390        let attended = if long_att {
12391            let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
12392            let pos_dev = prof_section(e, "qsa.mask_h2d", || {
12393                ws.take_i32(e, "qsa.selpos", &pos_flat, 0)
12394            })?;
12395            let meta_dev = ws.take_i32(e, "qsa.selmeta", &meta, 0)?;
12396            let attended = prof_section(e, "qsa.sdpa", || {
12397                let mut attended = ws.take_f32(e, "qsa.att", t * nh * hd, 0)?;
12398                match kv {
12399                    QsaKvStore::F32 { k, v } => {
12400                        let k_view = k.slice(0..t_kv * nkv * hd);
12401                        let v_view = v.slice(0..t_kv * nkv * hd);
12402                        launch_sdpa_blocklist(
12403                            e,
12404                            &q,
12405                            &k_view,
12406                            &v_view,
12407                            &mut attended,
12408                            &pos_dev,
12409                            &meta_dev,
12410                            hd,
12411                            nh,
12412                            nkv,
12413                            t,
12414                            max_count,
12415                            scale,
12416                        )?;
12417                    }
12418                    QsaKvStore::Q8Q5 { k, v } => {
12419                        launch_q4e_sdpa_blocklist_q8q5(
12420                            e,
12421                            &q,
12422                            k,
12423                            v,
12424                            &mut attended,
12425                            &pos_dev,
12426                            &meta_dev,
12427                            hd,
12428                            nh,
12429                            nkv,
12430                            t,
12431                            max_count,
12432                            scale,
12433                        )?;
12434                    }
12435                }
12436                Ok(attended)
12437            })?;
12438            ws.put_i32("qsa.selpos", pos_dev);
12439            ws.put_i32("qsa.selmeta", meta_dev);
12440            attended
12441        } else {
12442            let QsaKvStore::F32 { k, v } = &*kv else {
12443                return Err("qwen4exp_gpu: masked SDPA reached with a quantized cache".into());
12444            };
12445            let mask = rowsel_to_mask(&sels, block_size, t_kv);
12446            let mask_dev = prof_section(e, "qsa.mask_h2d", || {
12447                // Masked-kernel rows never exceed the smem bound, so the slot reserve is
12448                // bounded even on a long-context-capacity state.
12449                ws.take_u8_h2d(e, "qsa.mask", &mask, t * cap.min(SDPA_MASK_TKV_BOUND))
12450            })?;
12451            let attended = prof_section(e, "qsa.sdpa", || {
12452                let mut attended = ws.take_f32(e, "qsa.att", t * nh * hd, 0)?;
12453                let k_view = k.slice(0..t_kv * nkv * hd);
12454                let v_view = v.slice(0..t_kv * nkv * hd);
12455                launch_sdpa_mask(
12456                    e,
12457                    &q,
12458                    &k_view,
12459                    &v_view,
12460                    &mut attended,
12461                    &mask_dev,
12462                    hd,
12463                    nh,
12464                    nkv,
12465                    t,
12466                    t_kv,
12467                    scale,
12468                )?;
12469                Ok(attended)
12470            })?;
12471            ws.put_u8("qsa.mask", mask_dev);
12472            attended
12473        };
12474        ws.put_f32(
12475            if qsa.q_norm.is_some() {
12476                "qsa.qn"
12477            } else {
12478                "qsa.q"
12479            },
12480            q,
12481        );
12482        let out = prof_section(e, "qsa.gate_wo", || {
12483            // fused per-(head, dim) sigmoid output gate (family convention).
12484            let mut sg = ws.take_f32(e, "qsa.sg", t * nh * hd, 0)?;
12485            e.sigmoid(&gate, &mut sg, t * nh * hd)?;
12486            let mut gated = ws.take_f32(e, "qsa.gated", t * nh * hd, 0)?;
12487            e.mul(&attended, &sg, &mut gated, t * nh * hd)?;
12488            let mut out = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
12489            linear_trunk_into(
12490                e,
12491                &qsa.wo,
12492                &qsa.wo_b16,
12493                &gated,
12494                &mut out,
12495                t,
12496                nh * hd,
12497                hidden,
12498            )?;
12499            ws.put_f32("qsa.sg", sg);
12500            ws.put_f32("qsa.gated", gated);
12501            Ok(out)
12502        })?;
12503        ws.put_f32("qsa.att", attended);
12504        ws.put_f32("qsa.gate", gate);
12505        Ok(out)
12506    }
12507
12508    /// GDN layer (`gated_delta_net` twin): fused qkv/z/beta/alpha projections, causal
12509    /// conv (dilation 1, silu) over cached raw rows, the geometry-generic sequential scan,
12510    /// gated RMSNorm with the family's SIGMOID z-gate (SEMANTICS.md §GDN).
12511    #[allow(clippy::too_many_arguments)]
12512    fn gdn_forward(
12513        &self,
12514        e: &Engine,
12515        ws: &mut StepPool,
12516        layer: &LayerW,
12517        gdn: &GdnW,
12518        mixed: &CudaSlice<f32>,
12519        mstate: &mut MixerState,
12520        t: usize,
12521        // Verify-exact stash (mtp-spec): Some => per-token scan (each column the t == 1
12522        // decode kernel dispatch, bit-identical) + per-column state snapshots + the
12523        // chunk's conv-rewind inputs.
12524        mut stash: Option<&mut GdnStash>,
12525    ) -> Res<CudaSlice<f32>> {
12526        let MixerState::Gdn { conv, state } = mstate else {
12527            return Err(format!(
12528                "qwen4exp_gpu: GDN layer {} bound to non-GDN state",
12529                layer.index
12530            )
12531            .into());
12532        };
12533        let hidden = self.hidden;
12534        let p = &gdn.plan;
12535        let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
12536        let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
12537        let kernel = p.conv_kernel as usize;
12538        let pad = kernel - 1;
12539        let conv_dim = 2 * nk * hk + nv * hv;
12540        let eps = layer.eps_attn;
12541
12542        let (qkv, z, beta_raw, g_log) = prof_section(e, "gdn.proj", || {
12543            let mut qkv = ws.take_f32(e, "gdn.qkv", t * conv_dim, 0)?;
12544            let mut z = ws.take_f32(e, "gdn.z", t * nv * hv, 0)?;
12545            let mut beta_raw = ws.take_f32(e, "gdn.beta", t * nv, 0)?;
12546            let mut alpha = ws.take_f32(e, "gdn.alpha", t * nv, 0)?;
12547            // Proj stack (round 4): the 4 same-activation projections in ONE launch over
12548            // the row-stacked twin; per-row bit-identical to the per-mat launches (the
12549            // OFF arm reads row-offset views of the SAME stack — same bytes, same
12550            // kernel, VRAM-neutral residency).
12551            if let (true, Some(stack)) = (
12552                t == 1 && proj_stack_on() && trunk_bf16_on(),
12553                gdn.proj_b16.as_ref(),
12554            ) {
12555                launch_qmatvec_bf16w_multi4(
12556                    e,
12557                    stack,
12558                    mixed,
12559                    &[
12560                        (&qkv, conv_dim),
12561                        (&z, nv * hv),
12562                        (&beta_raw, nv),
12563                        (&alpha, nv),
12564                    ],
12565                    hidden,
12566                )?;
12567            } else {
12568                linear_trunk_stacked_into(
12569                    e,
12570                    &gdn.qkv,
12571                    &gdn.proj_b16,
12572                    0,
12573                    mixed,
12574                    &mut qkv,
12575                    t,
12576                    hidden,
12577                    conv_dim,
12578                )?;
12579                linear_trunk_stacked_into(
12580                    e,
12581                    &gdn.z,
12582                    &gdn.proj_b16,
12583                    conv_dim,
12584                    mixed,
12585                    &mut z,
12586                    t,
12587                    hidden,
12588                    nv * hv,
12589                )?;
12590                linear_trunk_stacked_into(
12591                    e,
12592                    &gdn.beta,
12593                    &gdn.proj_b16,
12594                    conv_dim + nv * hv,
12595                    mixed,
12596                    &mut beta_raw,
12597                    t,
12598                    hidden,
12599                    nv,
12600                )?;
12601                linear_trunk_stacked_into(
12602                    e,
12603                    &gdn.alpha,
12604                    &gdn.proj_b16,
12605                    conv_dim + nv * hv + nv,
12606                    mixed,
12607                    &mut alpha,
12608                    t,
12609                    hidden,
12610                    nv,
12611                )?;
12612            }
12613            let mut g_log = ws.take_f32(e, "gdn.glog", t * nv, 0)?;
12614            e.gdn_glog_v(&alpha.slice(0..t * nv), &gdn.dt, &gdn.a, &mut g_log, nv, t)?;
12615            ws.put_f32("gdn.alpha", alpha);
12616            Ok((qkv, z, beta_raw, g_log))
12617        })?;
12618
12619        let o = prof_section(e, "gdn.conv_scan", || {
12620            // Verify stash: the pre-chunk conv history + the chunk's raw rows are the
12621            // rewind rebuild inputs (pure retains — no kernel sees them). Kept OUTSIDE the
12622            // segment graph: they are the only part whose destination is the stash itself.
12623            if let Some(st) = stash.as_deref_mut() {
12624                e.copy_range_into(&mut st.conv_pre, 0, conv, 0, pad * conv_dim)?;
12625                e.copy_range_into(&mut st.qkv_rows, 0, &qkv, 0, t * conv_dim)?;
12626            }
12627            // Slots are taken (and so ALLOCATED, if this is their first use) before any
12628            // capture region opens; addresses are stable from here on.
12629            let mut conv_out = ws.take_f32(e, "gdn.conv_out", t * conv_dim, 0)?;
12630            let mut o = ws.take_f32(e, "gdn.o", t * nv * hv, 0)?;
12631            let mut tmp = if t >= pad {
12632                None
12633            } else {
12634                Some(ws.take_f32(e, "gdn.tmp", (pad - t) * conv_dim, 0)?)
12635            };
12636            let scale = 1.0 / (hk as f32).sqrt();
12637            let step_ok = gdn_step_on() && hk % 32 == 0 && hk <= 1024;
12638            // The dwconv -> per-column scan -> conv-history roll chain, as ONE callable
12639            // unit so the eager arm and the captured arm run the IDENTICAL launch
12640            // sequence (the graph A/B's bit-identity is by construction, not by review).
12641            //
12642            // Decode-step twin (perf round 3): one state element per thread instead of
12643            // one state row — geometry guard keeps the tiny plan (hk 4) on the naive
12644            // kernel; prefill (t > 1) always takes the naive sequential scan. VERIFY
12645            // chunks (stash Some) run per-token launches of the SAME dispatch decode
12646            // takes (step when the guard admits, else naive-at-1) with a per-column
12647            // state snapshot after each token — the rewind checkpoints.
12648            let chain = |eng: &Engine,
12649                         conv: &mut CudaSlice<f32>,
12650                         state: &mut CudaSlice<f32>,
12651                         states_snap: Option<&mut CudaSlice<f32>>,
12652                         conv_out: &mut CudaSlice<f32>,
12653                         o: &mut CudaSlice<f32>,
12654                         tmp: Option<&mut CudaSlice<f32>>|
12655             -> Res<()> {
12656                launch_dwconv(
12657                    eng,
12658                    &qkv,
12659                    conv,
12660                    &gdn.conv_w,
12661                    conv_out,
12662                    t,
12663                    pad,
12664                    conv_dim,
12665                    kernel,
12666                    1,
12667                    1,
12668                )?;
12669                match states_snap {
12670                    Some(states) => {
12671                        let state_len = nv * hv * hk;
12672                        for tok in 0..t {
12673                            if step_ok {
12674                                launch_gdn_scan_step_at(
12675                                    eng, conv_out, &g_log, &beta_raw, state, o, tok, nk, nv, hk,
12676                                    hv, scale, eps,
12677                                )?;
12678                            } else {
12679                                launch_gdn_scan_at(
12680                                    eng, conv_out, &g_log, &beta_raw, state, o, tok, nk, nv, hk,
12681                                    hv, scale, eps,
12682                                )?;
12683                            }
12684                            eng.copy_range_into(states, tok * state_len, state, 0, state_len)?;
12685                        }
12686                    }
12687                    None if t == 1 && step_ok => {
12688                        launch_gdn_scan_step(
12689                            eng, conv_out, &g_log, &beta_raw, state, o, nk, nv, hk, hv, scale, eps,
12690                        )?;
12691                    }
12692                    None => {
12693                        launch_gdn_scan(
12694                            eng, conv_out, &g_log, &beta_raw, state, o, nk, nv, hk, hv, t, scale,
12695                            eps,
12696                        )?;
12697                    }
12698                }
12699                // conv history <- last `pad` raw qkv rows (zeros keep their place when
12700                // t < pad).
12701                if t >= pad {
12702                    eng.copy_range_into(conv, 0, &qkv, (t - pad) * conv_dim, pad * conv_dim)?;
12703                } else {
12704                    let keep = pad - t;
12705                    let tmp = tmp.ok_or("qwen4exp_gpu: gdn conv roll needs the tmp slot")?;
12706                    eng.copy_range_into(tmp, 0, conv, t * conv_dim, keep * conv_dim)?;
12707                    eng.copy_range_into(conv, 0, tmp, 0, keep * conv_dim)?;
12708                    eng.copy_range_into(conv, keep * conv_dim, &qkv, 0, t * conv_dim)?;
12709                }
12710                Ok(())
12711            };
12712            // Segment graph (mtp9, default OFF): only the verify shape is graphed — plain
12713            // decode already has its own whole-interior graph, and prefill shapes vary.
12714            let graphable = stash.is_some() && verify_graphs_on() && step_ws_on() && !prof::on();
12715            match stash.as_deref_mut() {
12716                Some(st) if graphable => {
12717                    // Take the graph out so the snapshot buffer can be borrowed mutably.
12718                    // A different chunk width invalidates the capture (baked shapes).
12719                    let entry = match st.scan_graph.take() {
12720                        Some((gt, g)) if gt == t => Some(g),
12721                        _ => None,
12722                    };
12723                    let warm = st.scan_warm == Some(t);
12724                    st.scan_warm = Some(t);
12725                    // EXACTLY ONE of the three arms executes the chain once.
12726                    let entry = match (warm, entry) {
12727                        // First chunk at this width: eager, so every slot is allocated
12728                        // and parked before any capture region opens.
12729                        (false, _) => {
12730                            chain(
12731                                e,
12732                                conv,
12733                                state,
12734                                Some(&mut st.states),
12735                                &mut conv_out,
12736                                &mut o,
12737                                tmp.as_mut(),
12738                            )?;
12739                            None
12740                        }
12741                        // Captured at this width already: replay, no eager pass.
12742                        (true, Some(g)) => {
12743                            g.0.launch()?;
12744                            Some(g)
12745                        }
12746                        // Warm but not yet captured: capture WITHOUT executing
12747                        // (`nowarm`), then launch once — capture + launch is exactly one
12748                        // execution, so the column snapshots and the state advance happen
12749                        // exactly once.
12750                        (true, None) => {
12751                            let states = &mut st.states;
12752                            let mut tmp_ref = tmp.as_mut();
12753                            let g = e.capture_graph_retained_nowarm(|eng| {
12754                                chain(
12755                                    eng,
12756                                    conv,
12757                                    state,
12758                                    Some(states),
12759                                    &mut conv_out,
12760                                    &mut o,
12761                                    tmp_ref.as_deref_mut(),
12762                                )
12763                            })?;
12764                            g.0.launch()?;
12765                            Some(g)
12766                        }
12767                    };
12768                    if let Some(g) = entry {
12769                        st.scan_graph = Some((t, g));
12770                    }
12771                }
12772                Some(st) => chain(
12773                    e,
12774                    conv,
12775                    state,
12776                    Some(&mut st.states),
12777                    &mut conv_out,
12778                    &mut o,
12779                    tmp.as_mut(),
12780                )?,
12781                None => chain(e, conv, state, None, &mut conv_out, &mut o, tmp.as_mut())?,
12782            }
12783            ws.put_f32("gdn.conv_out", conv_out);
12784            if let Some(tmp) = tmp {
12785                ws.put_f32("gdn.tmp", tmp);
12786            }
12787            Ok(o)
12788        })?;
12789        ws.put_f32("gdn.qkv", qkv);
12790        ws.put_f32("gdn.beta", beta_raw);
12791        ws.put_f32("gdn.glog", g_log);
12792
12793        let out = prof_section(e, "gdn.norm_gate_out", || {
12794            let mut gated = ws.take_f32(e, "gdn.gated", t * nv * hv, 0)?;
12795            match p.gate_activation {
12796                // Fused norm+gate (perf round 3): one launch, bit-identical to the
12797                // rms_norm + sigmoid + mul chain below (rms_sigmul_f32 kernel doc).
12798                GdnGateActivation::Sigmoid if gdn_fuse_on() => {
12799                    launch_rms_sigmul(e, &o, &gdn.norm, &z, &mut gated, hv, t * nv, eps)?;
12800                }
12801                GdnGateActivation::Sigmoid => {
12802                    let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
12803                    e.rms_norm(&o, &gdn.norm, &mut normed, hv, t * nv, eps)?;
12804                    let mut sg = ws.take_f32(e, "gdn.sg", t * nv * hv, 0)?;
12805                    e.sigmoid(&z, &mut sg, t * nv * hv)?;
12806                    e.mul(&normed, &sg, &mut gated, t * nv * hv)?;
12807                    ws.put_f32("gdn.sg", sg);
12808                    ws.put_f32("gdn.normed", normed);
12809                }
12810                GdnGateActivation::Silu => {
12811                    let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
12812                    e.rms_norm(&o, &gdn.norm, &mut normed, hv, t * nv, eps)?;
12813                    e.silu_mul(&z, &normed, &mut gated, t * nv * hv)?;
12814                    ws.put_f32("gdn.normed", normed);
12815                }
12816            }
12817            let mut out = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
12818            linear_trunk_into(
12819                e,
12820                &gdn.out,
12821                &gdn.out_b16,
12822                &gated,
12823                &mut out,
12824                t,
12825                nv * hv,
12826                hidden,
12827            )?;
12828            ws.put_f32("gdn.gated", gated);
12829            Ok(out)
12830        })?;
12831        ws.put_f32("gdn.z", z);
12832        ws.put_f32("gdn.o", o);
12833        Ok(out)
12834    }
12835
12836    /// MoE (`moe_mlp` twin): device router GEMM, HOST softmax-top-k routing (reference
12837    /// tie rule + renorm floor), per-expert gathered GEMMs, slot scatter/FMA-reduce, and
12838    /// the sigmoid-gated shared expert.
12839    fn moe_forward(
12840        &self,
12841        e: &Engine,
12842        ws: &mut StepPool,
12843        moe: &MoeW,
12844        mixed: &CudaSlice<f32>,
12845        t: usize,
12846        // Rows mode (MTP draft + spec verify chunks): at t > 1, run the GROUPED decode
12847        // program per TOKEN — each token's launch sequence is the t == 1 program
12848        // verbatim (bit-identical rows), instead of the prefill per-expert executor.
12849        rows_grouped: bool,
12850        // Layer index, for the shared-format MoE route trace only (`MEMRA_MOE_TRACE`); it does
12851        // not select any behaviour. Threaded rather than kept in a thread-local because a hidden
12852        // ambient layer id is the kind of state that mislabels a whole trace file silently.
12853        layer: u32,
12854    ) -> Res<CudaSlice<f32>> {
12855        let hidden = self.hidden;
12856        let experts = moe.plan.expert_count as usize;
12857        let selected = moe.plan.experts_per_token as usize;
12858        let ff = moe.plan.expert_intermediate_size as usize;
12859
12860        // Device router engage (devtwin lane): grouped dispatch only — those consumers
12861        // read device sel/w(/tok) arrays, so the route never crosses. NVFP4 (trunk):
12862        // t == 1 decode or the merged verify path (the per-token grouped twin addresses
12863        // its sel slot per token, which needs the host arrays). DeviceBf16 (the card-1
12864        // draft bank, devtwin stage 2): all rows-mode shapes via `qmatvec_bf16w_sel_f32`
12865        // (per-token launches read sel at a device offset — no host expert ids). The
12866        // per-expert prefill executor keeps the host twin (host-gathered rows by
12867        // construction).
12868        let nvfp4_bank = matches!(
12869            (&moe.bank.gate, &moe.bank.up, &moe.bank.down),
12870            (
12871                BankHalf::Nvfp4 { .. },
12872                BankHalf::Nvfp4 { .. },
12873                BankHalf::Nvfp4 { .. }
12874            )
12875        );
12876        let devbf16_bank = matches!(
12877            (&moe.bank.gate, &moe.bank.up, &moe.bank.down),
12878            (
12879                BankHalf::DeviceBf16(_),
12880                BankHalf::DeviceBf16(_),
12881                BankHalf::DeviceBf16(_)
12882            )
12883        );
12884        let use_dev_router = router_dev_on()
12885            && moe_sel_path_on()
12886            && route_dev_geometry(experts, selected)
12887            && ((nvfp4_bank
12888                && hidden % 32 == 0
12889                && ff % 4 == 0
12890                && (t == 1
12891                    || (rows_grouped
12892                        && verify_mt_on()
12893                        && sel_gufuse_on()
12894                        && t * selected <= 8192)))
12895                || (devbf16_bank && hidden % 8 == 0 && ff % 8 == 0 && (t == 1 || rows_grouped)));
12896        // (routes, device route). Exactly one is populated: host routes for the host
12897        // twin arms, or the device sel/w(/tok) triplet for the grouped device arms.
12898        type DevRoute = (CudaSlice<i32>, CudaSlice<f32>, Option<CudaSlice<i32>>);
12899        let (routes, mut dev_route): (Vec<Vec<(usize, f32)>>, Option<DevRoute>) =
12900            prof_section(e, "moe.router", || {
12901                let mut router_out = ws.take_f32(e, "moe.router", t * experts, 0)?;
12902                let none: Option<CudaSlice<u8>> = None;
12903                let rb = if router_bf16_on() {
12904                    &moe.router_b16
12905                } else {
12906                    &none
12907                };
12908                linear_trunk_into(
12909                    e,
12910                    &moe.router,
12911                    rb,
12912                    mixed,
12913                    &mut router_out,
12914                    t,
12915                    hidden,
12916                    experts,
12917                )?;
12918                if use_dev_router {
12919                    let mut sel = ws.take_i32_slot(e, "moe.sel", t * selected, 0)?;
12920                    let mut w = ws.take_f32(e, "moe.w", t * selected, 0)?;
12921                    let mut tokm = if t > 1 {
12922                        Some(ws.take_i32_slot(e, "moe.tok", t * selected, 0)?)
12923                    } else {
12924                        None
12925                    };
12926                    route_topk_device(
12927                        e,
12928                        &router_out,
12929                        &mut sel,
12930                        &mut w,
12931                        tokm.as_mut().map(|m| (m, 0)),
12932                        experts,
12933                        selected,
12934                        t,
12935                        layer,
12936                    )?;
12937                    ws.put_f32("moe.router", router_out);
12938                    return Ok((Vec::new(), Some((sel, w, tokm))));
12939                }
12940                let logits = e.dtoh_view(&router_out.slice(0..t * experts))?;
12941                ws.put_f32("moe.router", router_out);
12942                let mut routes: Vec<Vec<(usize, f32)>> = Vec::with_capacity(t);
12943                for token in 0..t {
12944                    routes.push(host_route_softmax_topk(
12945                        &logits[token * experts..(token + 1) * experts],
12946                        selected,
12947                    ));
12948                }
12949                Ok((routes, None))
12950            })?;
12951        // Grouped decode path (perf-lane attack (a)): one kernel launch per PROJECTION
12952        // covers every selected expert — the per-expert dispatch below (dequant chain +
12953        // three tiny GEMVs + scatter per routed expert, ~52% of the decode token in
12954        // PROFILE-0) collapses to 6 launches per layer. NVFP4 banks + single-token decode
12955        // only (prefill keeps the gathered per-expert path); W4A16 — the kernel computes
12956        // the eager dequant chain's per-element products with a different summation order
12957        // (accumulation class, kernel doc), gated by the tiny four-arm + real gates.
12958        if (t == 1 || rows_grouped) && moe_sel_path_on() {
12959            if let (
12960                BankHalf::Nvfp4 {
12961                    codes: gc,
12962                    scales: gs,
12963                    macros_dev: gm,
12964                    ..
12965                },
12966                BankHalf::Nvfp4 {
12967                    codes: uc,
12968                    scales: us,
12969                    macros_dev: um,
12970                    ..
12971                },
12972                BankHalf::Nvfp4 {
12973                    codes: dc,
12974                    scales: ds,
12975                    macros_dev: dm,
12976                    ..
12977                },
12978            ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
12979            {
12980                // Merged verify columns (set_verify_mt): ONE gufuse launch over every
12981                // column's routed experts via the slot->token map + ONE down launch over
12982                // all slots + per-token windowed combines. Per-slot programs and the
12983                // per-token combine order are the decode program VERBATIM (bit-identical);
12984                // launch count per layer drops from 3t to 2 + t combines.
12985                if t > 1 && verify_mt_on() && sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
12986                    // Device-routed merged verify (devtwin): ONE batch (the engage
12987                    // guard bounds t*selected <= 8192 <= SLOT_CAP), per-slot programs
12988                    // and the per-token combine order the decode program VERBATIM —
12989                    // bit-identical rows; only the route's residency changed. The
12990                    // slot->token map comes from the route kernel, not a host build.
12991                    if let Some((sel, w_dev, tokm)) = dev_route.take() {
12992                        let tokm =
12993                            tokm.ok_or("moe_forward: device route at t > 1 without a tok map")?;
12994                        let out = prof_section(e, "moe.sel_grouped", || {
12995                            let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
12996                            let s_total = t * selected;
12997                            let mut act = ws.take_f32(e, "moe.act", s_total * ff, 0)?;
12998                            launch_nvfp4_sel_gu_silu(
12999                                e,
13000                                (gc, gs, gm),
13001                                (uc, us, um),
13002                                Some(&sel),
13003                                0,
13004                                s_total,
13005                                mixed,
13006                                &mut act,
13007                                hidden,
13008                                ff,
13009                                Some((&tokm, hidden)),
13010                            )?;
13011                            let mut partial = ws.take_f32(e, "moe.partial", s_total * hidden, 0)?;
13012                            launch_nvfp4_sel_matvec(
13013                                e,
13014                                dc,
13015                                ds,
13016                                dm,
13017                                &sel,
13018                                &act,
13019                                &mut partial,
13020                                s_total,
13021                                ff,
13022                                hidden,
13023                                ff,
13024                            )?;
13025                            for tok in 0..t {
13026                                launch_axpy_rows_seq_at(
13027                                    e,
13028                                    &partial,
13029                                    tok * selected,
13030                                    &w_dev,
13031                                    tok * selected,
13032                                    &mut out,
13033                                    tok,
13034                                    hidden,
13035                                    selected,
13036                                )?;
13037                            }
13038                            ws.put_i32("moe.sel", sel);
13039                            ws.put_i32("moe.tok", tokm);
13040                            ws.put_f32("moe.w", w_dev);
13041                            ws.put_f32("moe.act", act);
13042                            ws.put_f32("moe.partial", partial);
13043                            Ok(out)
13044                        })?;
13045                        return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13046                    }
13047                    let out = prof_section(e, "moe.sel_grouped", || {
13048                        let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
13049                        // Slot sub-batching: the grouped kernels index slots on grid.y,
13050                        // which CUDA caps at 65,535 — a long-context prefill chunk
13051                        // (t 8192 x 10 selected = 81,920 slots) overflowed it with
13052                        // CUDA_ERROR_INVALID_VALUE (smoke ladder, rung 32768). Sub-batches
13053                        // also bound the transients (act s*ff, partial s*hidden) on a card
13054                        // already holding the trunk. Sub-batching changes NOTHING per slot
13055                        // or per token: each slot's program and each token's combine order
13056                        // are identical to one big batch (and to the t == 1 decode
13057                        // program) — the boundary only splits launches.
13058                        const SLOT_CAP: usize = 8192;
13059                        let tok_step = (SLOT_CAP / selected.max(1)).max(1);
13060                        let mut tok0 = 0usize;
13061                        while tok0 < t {
13062                            let tok_n = tok_step.min(t - tok0);
13063                            let batch = &routes[tok0..tok0 + tok_n];
13064                            let mut sel_all: Vec<i32> = Vec::with_capacity(tok_n * selected);
13065                            let mut w_all: Vec<f32> = Vec::with_capacity(tok_n * selected);
13066                            let mut tok_all: Vec<i32> = Vec::with_capacity(tok_n * selected);
13067                            let mut ranges: Vec<(usize, usize)> = Vec::with_capacity(tok_n);
13068                            for (i, route) in batch.iter().enumerate() {
13069                                ranges.push((sel_all.len(), route.len()));
13070                                for &(eid, wgt) in route {
13071                                    sel_all.push(eid as i32);
13072                                    w_all.push(wgt);
13073                                    // ABSOLUTE token index: the kernel reads the
13074                                    // activation row at tok * hidden from the same
13075                                    // `mixed` buffer, so a sub-batch reads exactly the
13076                                    // rows one big batch would (no view, no offset math).
13077                                    tok_all.push((tok0 + i) as i32);
13078                                }
13079                            }
13080                            let s_total = sel_all.len();
13081                            let sel = ws.take_i32(e, "moe.sel", &sel_all, 0)?;
13082                            let w_dev = ws.take_f32_h2d(e, "moe.w", &w_all, 0)?;
13083                            let tokm = ws.take_i32(e, "moe.tok", &tok_all, 0)?;
13084                            let mut act = ws.take_f32(e, "moe.act", s_total * ff, 0)?;
13085                            launch_nvfp4_sel_gu_silu(
13086                                e,
13087                                (gc, gs, gm),
13088                                (uc, us, um),
13089                                Some(&sel),
13090                                0,
13091                                s_total,
13092                                mixed,
13093                                &mut act,
13094                                hidden,
13095                                ff,
13096                                Some((&tokm, hidden)),
13097                            )?;
13098                            let mut partial = ws.take_f32(e, "moe.partial", s_total * hidden, 0)?;
13099                            launch_nvfp4_sel_matvec(
13100                                e,
13101                                dc,
13102                                ds,
13103                                dm,
13104                                &sel,
13105                                &act,
13106                                &mut partial,
13107                                s_total,
13108                                ff,
13109                                hidden,
13110                                ff,
13111                            )?;
13112                            for (i, &(start, len)) in ranges.iter().enumerate() {
13113                                launch_axpy_rows_seq_at(
13114                                    e,
13115                                    &partial,
13116                                    start,
13117                                    &w_dev,
13118                                    start,
13119                                    &mut out,
13120                                    tok0 + i,
13121                                    hidden,
13122                                    len,
13123                                )?;
13124                            }
13125                            ws.put_i32("moe.sel", sel);
13126                            ws.put_i32("moe.tok", tokm);
13127                            ws.put_f32("moe.w", w_dev);
13128                            ws.put_f32("moe.act", act);
13129                            ws.put_f32("moe.partial", partial);
13130                            tok0 += tok_n;
13131                        }
13132                        Ok(out)
13133                    })?;
13134                    return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13135                }
13136                // Device-routed decode step (devtwin, t == 1 by the engage guard): the
13137                // grouped decode program launch-for-launch, sel/w read from the device
13138                // route — bit-identical to the host-routed chain on the same selection.
13139                if let Some((sel, w_dev, _)) = dev_route.take() {
13140                    let out = prof_section(e, "moe.sel_grouped", || {
13141                        let mut out = ws.take_f32(e, "moe.out", hidden, 0)?;
13142                        let mut act = ws.take_f32(e, "moe.act", selected * ff, 0)?;
13143                        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
13144                            launch_nvfp4_sel_gu_silu(
13145                                e,
13146                                (gc, gs, gm),
13147                                (uc, us, um),
13148                                Some(&sel),
13149                                0,
13150                                selected,
13151                                mixed,
13152                                &mut act,
13153                                hidden,
13154                                ff,
13155                                None,
13156                            )?;
13157                        } else {
13158                            let mut yg = ws.take_f32(e, "moe.yg", selected * ff, 0)?;
13159                            let mut yu = ws.take_f32(e, "moe.yu", selected * ff, 0)?;
13160                            launch_nvfp4_sel_matvec(
13161                                e, gc, gs, gm, &sel, mixed, &mut yg, selected, hidden, ff, 0,
13162                            )?;
13163                            launch_nvfp4_sel_matvec(
13164                                e, uc, us, um, &sel, mixed, &mut yu, selected, hidden, ff, 0,
13165                            )?;
13166                            e.silu_mul(&yg, &yu, &mut act, selected * ff)?;
13167                            ws.put_f32("moe.yg", yg);
13168                            ws.put_f32("moe.yu", yu);
13169                        }
13170                        let mut partial = ws.take_f32(e, "moe.partial", selected * hidden, 0)?;
13171                        launch_nvfp4_sel_matvec(
13172                            e,
13173                            dc,
13174                            ds,
13175                            dm,
13176                            &sel,
13177                            &act,
13178                            &mut partial,
13179                            selected,
13180                            ff,
13181                            hidden,
13182                            ff,
13183                        )?;
13184                        e.axpy_rows_seq_into(&partial, &w_dev, &mut out, hidden, selected)?;
13185                        ws.put_i32("moe.sel", sel);
13186                        ws.put_f32("moe.w", w_dev);
13187                        ws.put_f32("moe.act", act);
13188                        ws.put_f32("moe.partial", partial);
13189                        Ok(out)
13190                    })?;
13191                    return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13192                }
13193                let out = prof_section(e, "moe.sel_grouped", || {
13194                    let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
13195                    for (tok, route) in routes.iter().enumerate() {
13196                        let n_sel = route.len();
13197                        let sel_host: Vec<i32> = route.iter().map(|&(x, _)| x as i32).collect();
13198                        let w_host: Vec<f32> = route.iter().map(|&(_, w)| w).collect();
13199                        let sel = ws.take_i32(e, "moe.sel", &sel_host, 0)?;
13200                        let w_dev = ws.take_f32_h2d(e, "moe.w", &w_host, 0)?;
13201                        // Activation operand: t == 1 reads `mixed` in place (the decode
13202                        // program, launch-for-launch unchanged); rows mode stages the
13203                        // token's row in a stable slot (exact copy — the kernel reads
13204                        // identical values, so rows stay bit-identical to decode).
13205                        let x_tok = if t == 1 {
13206                            None
13207                        } else {
13208                            let mut x = ws.take_f32(e, "moe.x", hidden, 0)?;
13209                            e.copy_range_into(&mut x, 0, mixed, tok * hidden, hidden)?;
13210                            Some(x)
13211                        };
13212                        let x_ref = x_tok.as_ref().unwrap_or(mixed);
13213                        let mut act = ws.take_f32(e, "moe.act", n_sel * ff, 0)?;
13214                        // Fused gate+up+silu (round 4): ONE launch, bit-identical to the
13215                        // three-op chain below (kernel doc + oracle gufuse mode).
13216                        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
13217                            launch_nvfp4_sel_gu_silu(
13218                                e,
13219                                (gc, gs, gm),
13220                                (uc, us, um),
13221                                Some(&sel),
13222                                0,
13223                                n_sel,
13224                                x_ref,
13225                                &mut act,
13226                                hidden,
13227                                ff,
13228                                None,
13229                            )?;
13230                        } else {
13231                            let mut yg = ws.take_f32(e, "moe.yg", n_sel * ff, 0)?;
13232                            let mut yu = ws.take_f32(e, "moe.yu", n_sel * ff, 0)?;
13233                            launch_nvfp4_sel_matvec(
13234                                e, gc, gs, gm, &sel, x_ref, &mut yg, n_sel, hidden, ff, 0,
13235                            )?;
13236                            launch_nvfp4_sel_matvec(
13237                                e, uc, us, um, &sel, x_ref, &mut yu, n_sel, hidden, ff, 0,
13238                            )?;
13239                            e.silu_mul(&yg, &yu, &mut act, n_sel * ff)?;
13240                            ws.put_f32("moe.yg", yg);
13241                            ws.put_f32("moe.yu", yu);
13242                        }
13243                        let mut partial = ws.take_f32(e, "moe.partial", n_sel * hidden, 0)?;
13244                        launch_nvfp4_sel_matvec(
13245                            e,
13246                            dc,
13247                            ds,
13248                            dm,
13249                            &sel,
13250                            &act,
13251                            &mut partial,
13252                            n_sel,
13253                            ff,
13254                            hidden,
13255                            ff,
13256                        )?;
13257                        // Slot-ordered sequential combine (axpy_rows_seq_f32
13258                        // self-initializes); rows mode lands the row by exact copy.
13259                        if t == 1 {
13260                            e.axpy_rows_seq_into(&partial, &w_dev, &mut out, hidden, n_sel)?;
13261                        } else {
13262                            let mut row = ws.take_f32(e, "moe.row", hidden, 0)?;
13263                            e.axpy_rows_seq_into(&partial, &w_dev, &mut row, hidden, n_sel)?;
13264                            e.copy_range_into(&mut out, tok * hidden, &row, 0, hidden)?;
13265                            ws.put_f32("moe.row", row);
13266                        }
13267                        ws.put_i32("moe.sel", sel);
13268                        ws.put_f32("moe.w", w_dev);
13269                        ws.put_f32("moe.act", act);
13270                        ws.put_f32("moe.partial", partial);
13271                        if let Some(x) = x_tok {
13272                            ws.put_f32("moe.x", x);
13273                        }
13274                    }
13275                    Ok(out)
13276                })?;
13277                return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13278            }
13279            // DeviceBf16 bank (the MTP draft): per-selected-expert row-offset bf16
13280            // matvecs straight off the resident bytes — n_sel launches per projection
13281            // (arbitrary expert ids cannot batch through the strided kernel), silu and
13282            // combine exactly like the NVFP4 grouped chain.
13283            if let (BankHalf::DeviceBf16(gb), BankHalf::DeviceBf16(ub), BankHalf::DeviceBf16(db)) =
13284                (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
13285            {
13286                // Device-routed draft MoE (devtwin stage 2): per token, ONE
13287                // `qmatvec_bf16w_sel_f32` launch per projection reads its expert ids
13288                // from the device route at a sel offset — no host expert ids, no
13289                // per-slot launch chain. Per-row programs are the off_into chain
13290                // VERBATIM (kernel doc + the bf16 oracle's sel mode) and the combine
13291                // writes the same window `axpy_rows_seq` initialized — bit-identical.
13292                if let Some((sel, w_dev, _)) = dev_route.take() {
13293                    let out = prof_section(e, "moe.sel_bf16", || {
13294                        let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
13295                        for tok in 0..t {
13296                            let mut yg = ws.take_f32(e, "moe.yg", selected * ff, 0)?;
13297                            let mut yu = ws.take_f32(e, "moe.yu", selected * ff, 0)?;
13298                            launch_qmatvec_bf16w_sel(
13299                                e,
13300                                gb,
13301                                &sel,
13302                                tok * selected,
13303                                mixed,
13304                                tok * hidden,
13305                                0,
13306                                &mut yg,
13307                                selected,
13308                                hidden,
13309                                ff,
13310                            )?;
13311                            launch_qmatvec_bf16w_sel(
13312                                e,
13313                                ub,
13314                                &sel,
13315                                tok * selected,
13316                                mixed,
13317                                tok * hidden,
13318                                0,
13319                                &mut yu,
13320                                selected,
13321                                hidden,
13322                                ff,
13323                            )?;
13324                            let mut act = ws.take_f32(e, "moe.act", selected * ff, 0)?;
13325                            e.silu_mul(&yg, &yu, &mut act, selected * ff)?;
13326                            let mut partial =
13327                                ws.take_f32(e, "moe.partial", selected * hidden, 0)?;
13328                            launch_qmatvec_bf16w_sel(
13329                                e,
13330                                db,
13331                                &sel,
13332                                tok * selected,
13333                                &act,
13334                                0,
13335                                ff,
13336                                &mut partial,
13337                                selected,
13338                                ff,
13339                                hidden,
13340                            )?;
13341                            launch_axpy_rows_seq_at(
13342                                e,
13343                                &partial,
13344                                0,
13345                                &w_dev,
13346                                tok * selected,
13347                                &mut out,
13348                                tok,
13349                                hidden,
13350                                selected,
13351                            )?;
13352                            ws.put_f32("moe.yg", yg);
13353                            ws.put_f32("moe.yu", yu);
13354                            ws.put_f32("moe.act", act);
13355                            ws.put_f32("moe.partial", partial);
13356                        }
13357                        ws.put_i32("moe.sel", sel);
13358                        ws.put_f32("moe.w", w_dev);
13359                        Ok(out)
13360                    })?;
13361                    return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13362                }
13363                let out = prof_section(e, "moe.sel_bf16", || {
13364                    let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
13365                    for (tok, route) in routes.iter().enumerate() {
13366                        let n_sel = route.len();
13367                        let w_host: Vec<f32> = route.iter().map(|&(_, w)| w).collect();
13368                        let w_dev = ws.take_f32_h2d(e, "moe.w", &w_host, 0)?;
13369                        let mut yg = ws.take_f32(e, "moe.yg", n_sel * ff, 0)?;
13370                        let mut yu = ws.take_f32(e, "moe.yu", n_sel * ff, 0)?;
13371                        for (slot, &(eid, _)) in route.iter().enumerate() {
13372                            launch_qmatvec_bf16w_off_into(
13373                                e,
13374                                gb,
13375                                eid * ff,
13376                                mixed,
13377                                tok * hidden,
13378                                &mut yg,
13379                                slot * ff,
13380                                hidden,
13381                                ff,
13382                            )?;
13383                            launch_qmatvec_bf16w_off_into(
13384                                e,
13385                                ub,
13386                                eid * ff,
13387                                mixed,
13388                                tok * hidden,
13389                                &mut yu,
13390                                slot * ff,
13391                                hidden,
13392                                ff,
13393                            )?;
13394                        }
13395                        let mut act = ws.take_f32(e, "moe.act", n_sel * ff, 0)?;
13396                        e.silu_mul(&yg, &yu, &mut act, n_sel * ff)?;
13397                        let mut partial = ws.take_f32(e, "moe.partial", n_sel * hidden, 0)?;
13398                        for (slot, &(eid, _)) in route.iter().enumerate() {
13399                            launch_qmatvec_bf16w_off_into(
13400                                e,
13401                                db,
13402                                eid * hidden,
13403                                &act,
13404                                slot * ff,
13405                                &mut partial,
13406                                slot * hidden,
13407                                ff,
13408                                hidden,
13409                            )?;
13410                        }
13411                        let mut row = ws.take_f32(e, "moe.row", hidden, 0)?;
13412                        e.axpy_rows_seq_into(&partial, &w_dev, &mut row, hidden, n_sel)?;
13413                        e.copy_range_into(&mut out, tok * hidden, &row, 0, hidden)?;
13414                        ws.put_f32("moe.row", row);
13415                        ws.put_f32("moe.w", w_dev);
13416                        ws.put_f32("moe.yg", yg);
13417                        ws.put_f32("moe.yu", yu);
13418                        ws.put_f32("moe.act", act);
13419                        ws.put_f32("moe.partial", partial);
13420                    }
13421                    Ok(out)
13422                })?;
13423                return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13424            }
13425        }
13426
13427        // A device route that reaches here would feed the per-expert executor EMPTY
13428        // host routes and silently compute nothing — fail loud instead (the engage
13429        // guard and the dispatch arms must stay in lockstep).
13430        if dev_route.is_some() {
13431            return Err(
13432                "moe_forward: device route left unconsumed (engage guard drifted from the \
13433                 dispatch arms)"
13434                    .into(),
13435            );
13436        }
13437        // expert -> [(token, slot, weight)]
13438        let mut by_expert: Vec<Vec<(i32, i32, f32)>> = vec![Vec::new(); experts];
13439        for (token, token_routes) in routes.iter().enumerate() {
13440            for (slot, &(expert, weight)) in token_routes.iter().enumerate() {
13441                by_expert[expert].push((token as i32, slot as i32, weight));
13442            }
13443        }
13444        let mut slots = e.zeros(t * selected * hidden)?;
13445        let mut wbuf = e.zeros(t * selected)?;
13446        for (expert, entries) in by_expert.iter().enumerate() {
13447            if entries.is_empty() {
13448                continue;
13449            }
13450            let m_e = entries.len();
13451            let (tok_dev, slot_dev, w_dev, xg) = prof_section(e, "moe.idx_gather", || {
13452                let tok_idx: Vec<i32> = entries.iter().map(|&(tok, _, _)| tok).collect();
13453                let slot_idx: Vec<i32> = entries.iter().map(|&(_, slot, _)| slot).collect();
13454                let weights: Vec<f32> = entries.iter().map(|&(_, _, w)| w).collect();
13455                let tok_dev = e.htod_i32(&tok_idx)?;
13456                let slot_dev = e.htod_i32(&slot_idx)?;
13457                let w_dev = e.htod(&weights)?;
13458                let mut xg = e.uninit(m_e * hidden)?;
13459                e.gather_rows(mixed, &tok_dev, &mut xg, hidden, m_e)?;
13460                Ok((tok_dev, slot_dev, w_dev, xg))
13461            })?;
13462            // Resolve this expert's operand views per bank half (F32 = view into the
13463            // resident bank; NVFP4 = per-expert kernel dequant into a transient f32).
13464            let resolve = |half: &BankHalf,
13465                           out_f: usize,
13466                           in_f: usize|
13467             -> Res<(Option<CudaSlice<f32>>, usize)> {
13468                match half {
13469                    BankHalf::F32(_) => Ok((None, expert * out_f * in_f)),
13470                    BankHalf::Nvfp4 {
13471                        codes,
13472                        scales,
13473                        macros,
13474                        ..
13475                    } => Ok((
13476                        Some(dequant_nvfp4_expert_f32(
13477                            e,
13478                            codes,
13479                            scales,
13480                            macros[expert],
13481                            expert,
13482                            out_f,
13483                            in_f,
13484                        )?),
13485                        0,
13486                    )),
13487                    // Host-resident bf16 bank: upload THIS expert's rows and upcast
13488                    // (exact) — the per-routed-expert twin of the load-time dequant.
13489                    BankHalf::HostBf16(bytes) => {
13490                        let row_bytes = out_f * in_f * 2;
13491                        let dev =
13492                            e.htod_bytes(&bytes[expert * row_bytes..(expert + 1) * row_bytes])?;
13493                        Ok((
13494                            Some(e.bf16_to_f32(&dev.slice(0..row_bytes), out_f * in_f)?),
13495                            0,
13496                        ))
13497                    }
13498                    // Device-resident bf16 bank (MTP draft): widen THIS expert's rows
13499                    // in place (exact) — the multi-token replay/prefill arm; the t == 1
13500                    // draft decode takes the grouped row-offset matvec path instead.
13501                    BankHalf::DeviceBf16(bytes) => {
13502                        let row_bytes = out_f * in_f * 2;
13503                        let view = bytes.slice(expert * row_bytes..(expert + 1) * row_bytes);
13504                        Ok((Some(e.bf16_to_f32(&view, out_f * in_f)?), 0))
13505                    }
13506                }
13507            };
13508            let ((gate_owned, gate_base), (up_owned, up_base), (down_owned, down_base)) =
13509                prof_section(e, "moe.dequant", || {
13510                    Ok((
13511                        resolve(&moe.bank.gate, ff, hidden)?,
13512                        resolve(&moe.bank.up, ff, hidden)?,
13513                        resolve(&moe.bank.down, hidden, ff)?,
13514                    ))
13515                })?;
13516            let gate_view = match (&moe.bank.gate, &gate_owned) {
13517                (_, Some(owned)) => owned.slice(0..ff * hidden),
13518                (BankHalf::F32(bank), None) => bank.slice(gate_base..gate_base + ff * hidden),
13519                (
13520                    BankHalf::Nvfp4 { .. } | BankHalf::HostBf16(_) | BankHalf::DeviceBf16(_),
13521                    None,
13522                ) => {
13523                    unreachable!("quantized/host/device-bf16 halves always resolve owned")
13524                }
13525            };
13526            let up_view = match (&moe.bank.up, &up_owned) {
13527                (_, Some(owned)) => owned.slice(0..ff * hidden),
13528                (BankHalf::F32(bank), None) => bank.slice(up_base..up_base + ff * hidden),
13529                (
13530                    BankHalf::Nvfp4 { .. } | BankHalf::HostBf16(_) | BankHalf::DeviceBf16(_),
13531                    None,
13532                ) => {
13533                    unreachable!("quantized/host/device-bf16 halves always resolve owned")
13534                }
13535            };
13536            let down_view = match (&moe.bank.down, &down_owned) {
13537                (_, Some(owned)) => owned.slice(0..hidden * ff),
13538                (BankHalf::F32(bank), None) => bank.slice(down_base..down_base + hidden * ff),
13539                (
13540                    BankHalf::Nvfp4 { .. } | BankHalf::HostBf16(_) | BankHalf::DeviceBf16(_),
13541                    None,
13542                ) => {
13543                    unreachable!("quantized/host/device-bf16 halves always resolve owned")
13544                }
13545            };
13546            prof_section(e, "moe.expert_gemms", || {
13547                let down_out =
13548                    run_routed_expert(e, &xg, &gate_view, &up_view, &down_view, m_e, hidden, ff)?;
13549                e.scatter_slot(
13550                    &down_out, &tok_dev, &slot_dev, &w_dev, &mut slots, &mut wbuf, hidden,
13551                    selected, m_e,
13552                )
13553            })?;
13554        }
13555        let out = prof_section(e, "moe.reduce", || {
13556            let mut out = e.zeros(t * hidden)?;
13557            e.reduce_slots(&slots, &wbuf, &mut out, hidden, selected, t)?;
13558            Ok(out)
13559        })?;
13560        self.moe_shared_tail(e, ws, moe, mixed, out, t)
13561    }
13562
13563    /// Shared expert, sigmoid input gate (Qwen3NextSparseMoeBlock convention) — the
13564    /// common tail of both routed-expert executors.
13565    fn moe_shared_tail(
13566        &self,
13567        e: &Engine,
13568        ws: &mut StepPool,
13569        moe: &MoeW,
13570        mixed: &CudaSlice<f32>,
13571        mut out: CudaSlice<f32>,
13572        t: usize,
13573    ) -> Res<CudaSlice<f32>> {
13574        let hidden = self.hidden;
13575        let sff = moe
13576            .plan
13577            .shared
13578            .as_ref()
13579            .map(|s| s.intermediate_size as usize)
13580            .unwrap_or(0);
13581        if sff > 0 {
13582            prof_section(e, "moe.shared", || {
13583                // hcmicro: the shared-expert mats ride the bf16 trunk residency (their
13584                // f32 reads were ~2.5 GB/token); OFF keeps the f32 cuBLASLt chain.
13585                let none: Option<CudaSlice<u8>> = None;
13586                let (gu, db) = if micro_shexp_on() {
13587                    (&moe.shared_gu_b16, &moe.shared_down_b16)
13588                } else {
13589                    (&none, &none)
13590                };
13591                let mut gate = ws.take_f32(e, "moe.sh_gate", t * sff, 0)?;
13592                let mut up = ws.take_f32(e, "moe.sh_up", t * sff, 0)?;
13593                // Proj stack (round 4): shared gate/up in ONE launch (bit-identical
13594                // rows; OFF arm = row-offset views of the same stack).
13595                if let (true, Some(stack)) =
13596                    (t == 1 && proj_stack_on() && trunk_bf16_on(), gu.as_ref())
13597                {
13598                    launch_qmatvec_bf16w_multi4(
13599                        e,
13600                        stack,
13601                        mixed,
13602                        &[(&gate, sff), (&up, sff)],
13603                        hidden,
13604                    )?;
13605                } else {
13606                    linear_trunk_stacked_into(
13607                        e,
13608                        &moe.shared_gate,
13609                        gu,
13610                        0,
13611                        mixed,
13612                        &mut gate,
13613                        t,
13614                        hidden,
13615                        sff,
13616                    )?;
13617                    linear_trunk_stacked_into(
13618                        e,
13619                        &moe.shared_up,
13620                        gu,
13621                        sff,
13622                        mixed,
13623                        &mut up,
13624                        t,
13625                        hidden,
13626                        sff,
13627                    )?;
13628                }
13629                let mut act = ws.take_f32(e, "moe.sh_act", t * sff, 0)?;
13630                e.silu_mul(&gate, &up, &mut act, t * sff)?;
13631                let mut shared = ws.take_f32(e, "moe.sh_down", t * hidden, 0)?;
13632                linear_trunk_into(e, &moe.shared_down, db, &act, &mut shared, t, sff, hidden)?;
13633                if let Some(input_gate) = moe.shared_input_gate.as_ref() {
13634                    // Into-variant (same kernel, same launch shape as `sigmoid_dot_rows`;
13635                    // the owned form allocates per call — graph capture forbids that).
13636                    let mut g = ws.take_f32(e, "moe.g", t, 0)?;
13637                    e.sigmoid_dot_rows_into(mixed, input_gate, &mut g, hidden, t)?;
13638                    e.add_scaled_rows(&shared, &g, &mut out, hidden, t)?;
13639                    ws.put_f32("moe.g", g);
13640                } else {
13641                    let mut view = out.slice_mut(0..t * hidden);
13642                    e.axpy_into(&shared, 1.0, &mut view, t * hidden)?;
13643                }
13644                ws.put_f32("moe.sh_gate", gate);
13645                ws.put_f32("moe.sh_up", up);
13646                ws.put_f32("moe.sh_act", act);
13647                ws.put_f32("moe.sh_down", shared);
13648                Ok(())
13649            })?;
13650        }
13651        Ok(out)
13652    }
13653
13654    /// PLE block (`ple_block` twin): host n-gram hashing + host gather from the
13655    /// host-resident table, H2D of the gathered rows, device projections / grouped norms /
13656    /// dilated depthwise conv, host signed-sqrt sigmoid gate scalars.
13657    #[allow(clippy::too_many_arguments)]
13658    fn ple_block(
13659        &self,
13660        e: &Engine,
13661        layer: &LayerW,
13662        ple: &PleW,
13663        table: &NgramTable,
13664        ple_state: &mut PleState,
13665        planes: &mut [CudaSlice<f32>],
13666        tokens: &[u32],
13667        t: usize,
13668        // Verify-exact rows: per-token cuBLASLt launches (m == 1, the decode shape) so
13669        // chunk rows stay bit-identical to decode; `stash` retains the pre-chunk conv
13670        // history + the chunk's normed rows (the rewind rebuild inputs).
13671        exact: bool,
13672        mut stash: Option<&mut PleStash>,
13673    ) -> Res<()> {
13674        let hidden = self.hidden;
13675        let streams = self.streams;
13676        let plan = &ple.plan;
13677        let heads = plan.ngram_heads as usize;
13678        let head_dim = plan.head_embed_dim as usize;
13679        let embed_dim = plan.embed_dim as usize;
13680        let kernel = plan.conv_kernel as usize;
13681        let max_ngram = plan.max_ngram as usize;
13682        let dilation = max_ngram;
13683        let pad = (kernel - 1) * dilation;
13684        let eps = layer.eps_attn;
13685
13686        // Host n-gram ids over the FULL history (exact segment semantics), last t rows.
13687        let gathered = prof_section(e, "ple.host_ngram_gather", || {
13688            let total_heads = heads;
13689            // `plecache`: extend the state's id cache instead of rebuilding the whole
13690            // history's hashes. `ids` owns the vector only on the OFF arm; on the ON arm the
13691            // chunk rows are read in place out of the state (no O(context) clone).
13692            let mut ids: Vec<i64> = Vec::new();
13693            if ple_cache_on() {
13694                host_ngram_ids_cached(
13695                    &mut ple_state.ngram_ids,
13696                    &mut ple_state.ngram_history,
13697                    &mut ple_state.ngram_last_eos,
13698                    tokens,
13699                    &ple.multipliers,
13700                    &ple.sizes,
13701                    &ple.offsets,
13702                    max_ngram,
13703                    heads / (max_ngram - 1),
13704                    plan.eos_token_id,
13705                );
13706                if ple_cache_audit_on() {
13707                    let twin = host_ngram_ids(
13708                        tokens,
13709                        &ple.multipliers,
13710                        &ple.sizes,
13711                        &ple.offsets,
13712                        max_ngram,
13713                        heads / (max_ngram - 1),
13714                        plan.eos_token_id,
13715                    );
13716                    let from = (tokens.len() - t) * total_heads;
13717                    let mism = twin[from..]
13718                        .iter()
13719                        .zip(&ple_state.ngram_ids[from..])
13720                        .filter(|(a, b)| a != b)
13721                        .count() as u64;
13722                    PLE_CACHE_AUDIT_ROWS.fetch_add(t as u64, std::sync::atomic::Ordering::Relaxed);
13723                    PLE_CACHE_AUDIT_MISMATCH.fetch_add(mism, std::sync::atomic::Ordering::Relaxed);
13724                    PLE_CACHE_AUDIT_MAX_FILL
13725                        .fetch_max(tokens.len() as u64, std::sync::atomic::Ordering::Relaxed);
13726                    if mism > 0 {
13727                        return Err(format!(
13728                            "plecache audit: {mism} cached n-gram ids differ from the full twin \
13729                             at history {} (t={t})",
13730                            tokens.len()
13731                        )
13732                        .into());
13733                    }
13734                }
13735            } else {
13736                ids = host_ngram_ids(
13737                    tokens,
13738                    &ple.multipliers,
13739                    &ple.sizes,
13740                    &ple.offsets,
13741                    max_ngram,
13742                    heads / (max_ngram - 1),
13743                    plan.eos_token_id,
13744                );
13745            }
13746            let all_ids: &[i64] = if ple_cache_on() {
13747                &ple_state.ngram_ids
13748            } else {
13749                &ids
13750            };
13751            let chunk_ids = &all_ids[(tokens.len() - t) * total_heads..];
13752            let table_rows = table.rows(head_dim);
13753            let mut gathered = vec![0.0f32; t * embed_dim];
13754            for token in 0..t {
13755                for head in 0..heads {
13756                    let id = chunk_ids[token * total_heads + head];
13757                    if id < 0 || id as usize >= table_rows {
13758                        return Err("qwen4exp_gpu: n-gram id outside the embedding table".into());
13759                    }
13760                    table.gather_into(
13761                        id as usize,
13762                        head_dim,
13763                        &mut gathered[token * embed_dim + head * head_dim
13764                            ..token * embed_dim + (head + 1) * head_dim],
13765                    );
13766                }
13767            }
13768            Ok(gathered)
13769        })?;
13770        let emb = prof_section(e, "ple.h2d", || e.htod(&gathered))?;
13771
13772        // Per-token cuBLASLt twin (verify-exact): every m == 1 launch matches the
13773        // decode dispatch for that projection, so chunk rows equal decode rows bitwise.
13774        let lin_rows = |x: &CudaSlice<f32>,
13775                        w: &CudaSlice<f32>,
13776                        in_f: usize,
13777                        out_f: usize|
13778         -> Res<CudaSlice<f32>> {
13779            let mut out = e.uninit(t * out_f)?;
13780            if exact && t > 1 {
13781                let wv = w.slice(0..w.len());
13782                for tok in 0..t {
13783                    let xv = x.slice(tok * in_f..(tok + 1) * in_f);
13784                    let mut yv = out.slice_mut(tok * out_f..(tok + 1) * out_f);
13785                    e.linear_device_into(&xv, &wv, &mut yv, 1, in_f, out_f)?;
13786                }
13787            } else {
13788                e.linear_device_into(x, w, &mut out, t, in_f, out_f)?;
13789            }
13790            Ok(out)
13791        };
13792        let (value, mut dots_host) = prof_section(e, "ple.key_gate", || {
13793            let value = lin_rows(&emb, &ple.value_proj, embed_dim, hidden)?;
13794            let ones = e.htod(&vec![1.0f32; hidden])?;
13795            let mut dots_host = vec![0.0f32; streams * t];
13796            for s in 0..streams {
13797                let key = lin_rows(&emb, &ple.key_proj[s], embed_dim, hidden)?;
13798                let mut key_normed = e.uninit(t * hidden)?;
13799                e.rms_norm(&key, &ple.norm_key[s], &mut key_normed, hidden, t, eps)?;
13800                let mut query = e.uninit(t * hidden)?;
13801                e.rms_norm(&planes[s], &ple.norm_query[s], &mut query, hidden, t, eps)?;
13802                let mut prod = e.uninit(t * hidden)?;
13803                e.mul(&key_normed, &query, &mut prod, t * hidden)?;
13804                let dots = lin_rows(&prod, &ones, hidden, 1)?;
13805                dots_host[s * t..(s + 1) * t].copy_from_slice(&e.dtoh(&dots)?);
13806            }
13807            Ok((value, dots_host))
13808        })?;
13809        // signed sqrt + sigmoid (modular L770; torch sign(0) = 0) — host scalars.
13810        for dot in dots_host.iter_mut() {
13811            let gate = *dot / (hidden as f32).sqrt();
13812            let magnitude = gate.abs().max(1e-6).sqrt();
13813            let signed = if gate > 0.0 {
13814                magnitude
13815            } else if gate < 0.0 {
13816                -magnitude
13817            } else {
13818                0.0
13819            };
13820            *dot = host_sigmoid(signed);
13821        }
13822
13823        prof_section(e, "ple.conv_write", || {
13824            for s in 0..streams {
13825                let g = e.htod(&dots_host[s * t..(s + 1) * t])?;
13826                let mut gated = e.zeros(t * hidden)?;
13827                e.add_scaled_rows(&value, &g, &mut gated, hidden, t)?;
13828                let mut normed = e.uninit(t * hidden)?;
13829                e.rms_norm(&gated, &ple.norm_conv[s], &mut normed, hidden, t, eps)?;
13830                // Verify stash: pre-chunk history + this chunk's normed rows (rewind
13831                // rebuild inputs; pure retains).
13832                if let Some(st) = stash.as_deref_mut() {
13833                    e.copy_range_into(
13834                        &mut st.hist_pre[s],
13835                        0,
13836                        &ple_state.conv_hist[s],
13837                        0,
13838                        pad * hidden,
13839                    )?;
13840                    e.copy_range_into(&mut st.normed_rows[s], 0, &normed, 0, t * hidden)?;
13841                }
13842                // out = gated + silu(dilated causal conv(normed)) — dwconv mode 2 adds in place.
13843                launch_dwconv(
13844                    e,
13845                    &normed,
13846                    &ple_state.conv_hist[s],
13847                    &ple.conv_w[s],
13848                    &mut gated,
13849                    t,
13850                    pad,
13851                    hidden,
13852                    kernel,
13853                    dilation,
13854                    2,
13855                )?;
13856                // conv history <- last `pad` NORMED rows.
13857                let hist = &mut ple_state.conv_hist[s];
13858                if t >= pad {
13859                    e.copy_range_into(hist, 0, &normed, (t - pad) * hidden, pad * hidden)?;
13860                } else {
13861                    let keep = pad - t;
13862                    let mut tmp = e.uninit(keep * hidden)?;
13863                    e.copy_range_into(&mut tmp, 0, hist, t * hidden, keep * hidden)?;
13864                    e.copy_range_into(hist, 0, &tmp, 0, keep * hidden)?;
13865                    e.copy_range_into(hist, keep * hidden, &normed, 0, t * hidden)?;
13866                }
13867                // wide stream gains the PLE output BEFORE the attention read gate.
13868                let mut view = planes[s].slice_mut(0..t * hidden);
13869                e.axpy_into(&gated, 1.0, &mut view, t * hidden)?;
13870            }
13871            Ok(())
13872        })
13873    }
13874}
13875
13876// ---------------------------------------------------------------- MTP draft (mtp-spec lane)
13877
13878/// The MTP draft's persistent state: its own QSA KV rows + indexer raw-key cache + a
13879/// dedicated step workspace. DRAFT CACHE ROW i HOLDS TARGET POSITION i + 1 (position 0
13880/// never enters the draft — its first input pairs token x_1 with trunk hidden h_0), so
13881/// every spec-loop forward runs at `pos_off = 1`; the reference-parity gate runs at
13882/// `pos_off = 0` to match the reference executor's row-indexed positions.
13883pub struct MtpDraftState {
13884    mixer: MixerState,
13885    /// Rows currently in the cache (committed + speculative chain rows).
13886    rows: usize,
13887    /// Rows whose inputs were TRUE trunk hidden states (survive a round). The spec loop
13888    /// truncates to here and replays accepted tokens with verify-produced hiddens.
13889    pub committed: usize,
13890    capacity: usize,
13891    ws: StepPool,
13892}
13893
13894impl MtpDraftState {
13895    pub fn rows(&self) -> usize {
13896        self.rows
13897    }
13898}
13899
13900/// The draft forward's token source (mtp11): host ids (the mtp10 program), host ids
13901/// GATHERED ON DEVICE from the full-vocab chain table (the defer arm's prefill/replay
13902/// shape — a 4t-byte htod replaces t 10 KB pageable embed rows, the spec.rs
13903/// embed_gather_device_t precedent), or ONE device slot holding the previous chain
13904/// step's RAW argmax (the deferred chain).
13905#[derive(Clone, Copy)]
13906enum DraftTokSrc<'a> {
13907    Host(&'a [u32]),
13908    HostDev(&'a [u32]),
13909    DevSlot(&'a CudaSlice<u32>, usize),
13910}
13911
13912impl Qwen4ExpGpu {
13913    pub fn has_mtp(&self) -> bool {
13914        self.mtp.is_some()
13915    }
13916
13917    /// Card-1 draft placement armed? (`load_from_dir_dev1` — the draft's device tensors
13918    /// live on `mtp_dev1.dev`, and every draft call must present an engine there.)
13919    pub fn mtp_on_dev1(&self) -> bool {
13920        self.mtp_dev1.is_some()
13921    }
13922
13923    /// The draft's device tensors were built on ONE engine; a call presenting another
13924    /// engine would launch kernels on the wrong context (UVA would make it "work"
13925    /// slowly instead of failing). Enforced, never assumed.
13926    fn check_draft_engine(&self, e: &Engine) -> Res<()> {
13927        if let Some(d) = self.mtp_dev1.as_ref() {
13928            if e.ctx().ordinal() != d.dev {
13929                return Err(format!(
13930                    "qwen4exp_gpu: the draft lives on device {} (card-1 placement); \
13931                     this call presented device {}",
13932                    d.dev,
13933                    e.ctx().ordinal()
13934                )
13935                .into());
13936            }
13937        }
13938        Ok(())
13939    }
13940
13941    /// Allocate the draft's persistent state (its own KV plane; `capacity` rows).
13942    /// With the card-1 placement, `e` must be the DRAFT engine.
13943    pub fn mtp_state(&self, e: &Engine, capacity: usize) -> Res<MtpDraftState> {
13944        self.check_draft_engine(e)?;
13945        let mtp = self
13946            .mtp
13947            .as_ref()
13948            .ok_or("qwen4exp_gpu: no MTP block loaded (LoadOptions::load_mtp)")?;
13949        let MixerW::Qsa(qsa) = &mtp.layer.mixer else {
13950            return Err("qwen4exp_gpu: MTP mixer is not QSA".into());
13951        };
13952        let kv_width = qsa.attn.kv_heads as usize * qsa.attn.key_head_dim as usize;
13953        let v_width = qsa.attn.kv_heads as usize * qsa.attn.value_head_dim as usize;
13954        // kvq/idxq: the draft's QSA cache follows the same latched formats as the trunk
13955        // (uniform storage; the spec byte-identity gates run same-config on both arms).
13956        let kv = if kv_quant_on() {
13957            QsaKvStore::Q8Q5 {
13958                k: e.alloc_u8(capacity * q8_row_bytes(kv_width))?,
13959                v: e.alloc_u8(capacity * q5_row_bytes(v_width))?,
13960            }
13961        } else {
13962            QsaKvStore::F32 {
13963                k: e.zeros(capacity * kv_width)?,
13964                v: e.zeros(capacity * v_width)?,
13965            }
13966        };
13967        Ok(MtpDraftState {
13968            mixer: MixerState::Qsa {
13969                kv,
13970                raw_keys: IdxRawCache::new(idxq_mode()),
13971                pooled_keys: Vec::new(),
13972                pooled_dev: None,
13973                pooled_dev_rows: 0,
13974                raw_dev: None,
13975                raw_dev_rows: 0,
13976                idx_audit: None,
13977            },
13978            rows: 0,
13979            committed: 0,
13980            capacity,
13981            ws: StepPool::default(),
13982        })
13983    }
13984
13985    /// Truncate the draft cache to `rows` (speculative chain rows die; KV rows are
13986    /// overwritten in place by the next append, the host raw-key cache truncates).
13987    pub fn mtp_rewind(&self, dstate: &mut MtpDraftState, rows: usize) -> Res<()> {
13988        if rows > dstate.rows {
13989            return Err("qwen4exp_gpu: mtp_rewind past the cache".into());
13990        }
13991        let mtp = self.mtp.as_ref().ok_or("qwen4exp_gpu: no MTP block")?;
13992        let MixerW::Qsa(qsa) = &mtp.layer.mixer else {
13993            return Err("qwen4exp_gpu: MTP mixer is not QSA".into());
13994        };
13995        let MixerState::Qsa {
13996            raw_keys,
13997            pooled_keys,
13998            pooled_dev_rows,
13999            raw_dev_rows,
14000            ..
14001        } = &mut dstate.mixer
14002        else {
14003            return Err("qwen4exp_gpu: MTP state is not QSA".into());
14004        };
14005        let idx_dim = qsa.overlay.head_dim as usize;
14006        raw_keys.truncate_rows(rows, idx_dim);
14007        let block = qsa.overlay.block_size as usize;
14008        pooled_keys.truncate((rows / block) * idx_dim);
14009        // The device mirror's row count MUST follow the host truncation, or the next
14010        // scorer call skips the H2D of rebuilt rows and scores STALE keys (caught by the
14011        // spec byte-identity arms).
14012        *pooled_dev_rows = (*pooled_dev_rows).min(pooled_keys.len() / idx_dim);
14013        // Device raw-key cache (idxcache): clamp to the ABSOLUTE kept row count — the
14014        // host cache may legitimately lag below it (the lazy materialization).
14015        *raw_dev_rows = (*raw_dev_rows).min(rows);
14016        dstate.rows = rows;
14017        dstate.committed = dstate.committed.min(rows);
14018        Ok(())
14019    }
14020
14021    /// One MTP draft forward over `t` rows (SEMANTICS.md §MTP): fused input =
14022    /// `fc_embedding(norm(embed(tok)))` broadcast over streams + per-stream
14023    /// `fc_hidden(FLAT norm(wide hidden))`; ONE QSA+MoE decoder layer on the draft's own
14024    /// cache; exit through the draft mixer into the SHARED lm_head. Returns
14025    /// `(logits [t, vocab], carrier [t, wide])` — the carrier is the POST-LAYER wide
14026    /// state, the K > 1 multi-step seed. Recycle both via `mtp_recycle`.
14027    ///
14028    /// `hidden_wide` rows start at row `wide_off` of the given buffer; row r seeds
14029    /// token r. `pos_off` = 1 in the spec loop (draft row i ↔ target position i+1),
14030    /// 0 in the reference-parity gate.
14031    #[allow(clippy::too_many_arguments)]
14032    pub fn mtp_draft_forward(
14033        &self,
14034        e: &Engine,
14035        tokens: &[u32],
14036        hidden_wide: &CudaSlice<f32>,
14037        wide_off: usize,
14038        dstate: &mut MtpDraftState,
14039        pos_off: usize,
14040        // true => logits for EVERY row (the parity gates); false => the LAST row only
14041        // (the spec loop's shape — earlier rows exist for the KV cache + carrier, and
14042        // the full-vocab head must not scale with the replay length).
14043        logits_all: bool,
14044    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
14045        self.mtp_draft_forward_impl(
14046            e,
14047            DraftTokSrc::Host(tokens),
14048            hidden_wide,
14049            wide_off,
14050            dstate,
14051            pos_off,
14052            logits_all,
14053        )
14054    }
14055
14056    /// One DEFERRED chain step (mtp11): the input token is the previous step's device
14057    /// argmax, read from `toks[slot]` (RAW draft-index space; embeds through the armed
14058    /// chain table). t == 1 by construction; `pos_off` is the spec loop's 1.
14059    fn mtp_draft_forward_devslot(
14060        &self,
14061        e: &Engine,
14062        toks: &CudaSlice<u32>,
14063        slot: usize,
14064        hidden_wide: &CudaSlice<f32>,
14065        wide_off: usize,
14066        dstate: &mut MtpDraftState,
14067    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
14068        self.mtp_draft_forward_impl(
14069            e,
14070            DraftTokSrc::DevSlot(toks, slot),
14071            hidden_wide,
14072            wide_off,
14073            dstate,
14074            1,
14075            false,
14076        )
14077    }
14078
14079    /// Spec-loop host-token draft forward (prefill / bootstrap / replay shapes):
14080    /// `dev_embed` keys the defer arm's device-gather embed (full-vocab chain table)
14081    /// vs the mtp10 host embed — the control arm stays byte- AND structure-frozen.
14082    fn mtp_draft_forward_spec(
14083        &self,
14084        e: &Engine,
14085        tokens: &[u32],
14086        dev_embed: bool,
14087        hidden_wide: &CudaSlice<f32>,
14088        wide_off: usize,
14089        dstate: &mut MtpDraftState,
14090    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
14091        let src = if dev_embed {
14092            DraftTokSrc::HostDev(tokens)
14093        } else {
14094            DraftTokSrc::Host(tokens)
14095        };
14096        self.mtp_draft_forward_impl(e, src, hidden_wide, wide_off, dstate, 1, false)
14097    }
14098
14099    /// `mtp_draft_forward_spec` over RING-slotted seed rows: absolute seed row
14100    /// `first_row + i` lives at slot `(first_row + i) % ring`, and a range crossing the
14101    /// ring seam splits into two draft calls. The split changes the draft GEMM shape on
14102    /// seam rounds (drafted tokens may differ there — acceptance-only; commits are
14103    /// always the target rows, so spec byte-identity is untouched by construction).
14104    /// Returns the LAST piece's (logits row, carrier, piece length).
14105    fn draft_consume_ring(
14106        &self,
14107        de: &Engine,
14108        tokens: &[u32],
14109        dev_embed: bool,
14110        seed: &CudaSlice<f32>,
14111        ring: usize,
14112        first_row: usize,
14113        dstate: &mut MtpDraftState,
14114    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>, usize)> {
14115        let mut out: Option<(CudaSlice<f32>, CudaSlice<f32>, usize)> = None;
14116        let mut done = 0usize;
14117        while done < tokens.len() {
14118            let slot = (first_row + done) % ring;
14119            let len = (tokens.len() - done).min(ring - slot);
14120            let (l, c) = self.mtp_draft_forward_spec(
14121                de,
14122                &tokens[done..done + len],
14123                dev_embed,
14124                seed,
14125                slot,
14126                dstate,
14127            )?;
14128            if let Some((pl, pc, _)) = out.take() {
14129                self.mtp_recycle(dstate, pl, pc);
14130            }
14131            out = Some((l, c, len));
14132            done += len;
14133        }
14134        out.ok_or("qwen4exp_gpu: empty draft consume".into())
14135    }
14136
14137    #[allow(clippy::too_many_arguments)]
14138    fn mtp_draft_forward_impl(
14139        &self,
14140        e: &Engine,
14141        tok_src: DraftTokSrc<'_>,
14142        hidden_wide: &CudaSlice<f32>,
14143        wide_off: usize,
14144        dstate: &mut MtpDraftState,
14145        pos_off: usize,
14146        logits_all: bool,
14147    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
14148        self.check_draft_engine(e)?;
14149        let mtp = self
14150            .mtp
14151            .as_ref()
14152            .ok_or("qwen4exp_gpu: no MTP block loaded (LoadOptions::load_mtp)")?;
14153        let t = match tok_src {
14154            DraftTokSrc::Host(tokens) | DraftTokSrc::HostDev(tokens) => tokens.len(),
14155            DraftTokSrc::DevSlot(..) => 1,
14156        };
14157        let hidden = self.hidden;
14158        let streams = self.streams;
14159        let wide = streams * hidden;
14160        if t == 0 {
14161            return Err("qwen4exp_gpu: empty draft input".into());
14162        }
14163        if dstate.rows + t > dstate.capacity {
14164            return Err("qwen4exp_gpu: draft state capacity exceeded".into());
14165        }
14166        if hidden_wide.len() < (wide_off + t) * wide {
14167            return Err("qwen4exp_gpu: draft hidden seed rows out of range".into());
14168        }
14169        let base = dstate.rows;
14170        let ws = &mut dstate.ws;
14171        let cap = dstate.capacity;
14172
14173        // ---- input fusion
14174        let mut planes = prof_section(e, "mtp.fuse", || {
14175            let emb = match tok_src {
14176                DraftTokSrc::Host(tokens) => {
14177                    let mut embedded = vec![0.0f32; t * hidden];
14178                    for (row, &token) in tokens.iter().enumerate() {
14179                        let token = token as usize;
14180                        if token >= self.vocab {
14181                            return Err(
14182                                format!("qwen4exp_gpu: draft token {token} out of range").into()
14183                            );
14184                        }
14185                        embedded[row * hidden..(row + 1) * hidden].copy_from_slice(
14186                            &self.embed_host[token * hidden..(token + 1) * hidden],
14187                        );
14188                    }
14189                    ws.take_f32_h2d(e, "mtp.emb", &embedded, cap * hidden)?
14190                }
14191                DraftTokSrc::HostDev(tokens) => {
14192                    // Defer arm's prefill/replay embed (mtp11): host ids validated
14193                    // here, then a 4t-byte htod + device gather from the FULL-VOCAB
14194                    // chain table — bit-identical rows (ChainEmbed contract), no
14195                    // t x 10 KB pageable h2d. The caller keys this on a full-vocab
14196                    // table (a trim table cannot embed arbitrary target ids).
14197                    let ce = self
14198                        .chain_embed
14199                        .as_ref()
14200                        .filter(|ce| !ce.for_trim && ce.rows == self.vocab)
14201                        .ok_or("qwen4exp_gpu: HostDev embed needs the full-vocab chain table")?;
14202                    for &token in tokens {
14203                        if token as usize >= self.vocab {
14204                            return Err(
14205                                format!("qwen4exp_gpu: draft token {token} out of range").into()
14206                            );
14207                        }
14208                    }
14209                    let tok_d = e.gpu.stream().clone_htod(tokens)?;
14210                    let mut emb = ws.take_f32(e, "mtp.emb", t * hidden, cap * hidden)?;
14211                    let tv = tok_d.slice(0..t);
14212                    embed_gather_rows_into(
14213                        e,
14214                        &ce.table,
14215                        &tv,
14216                        &mut emb,
14217                        t,
14218                        hidden,
14219                        ce.qt,
14220                        ce.row_bytes,
14221                    )?;
14222                    emb
14223                }
14224                DraftTokSrc::DevSlot(toks, slot) => {
14225                    // Deferred chain (mtp11): gather THE row for the RAW draft index
14226                    // in `toks[slot]` from the armed chain table — bit-identical to
14227                    // the host row (ChainEmbed contract), no host round trip of the
14228                    // token id, no pageable h2d. Index bound is by construction:
14229                    // the argmax that wrote the slot scanned exactly `rows` columns.
14230                    let ce = self
14231                        .chain_embed
14232                        .as_ref()
14233                        .ok_or("qwen4exp_gpu: deferred draft step without arm_spec_devchain")?;
14234                    let mut emb = ws.take_f32(e, "mtp.emb", hidden, cap * hidden)?;
14235                    let tv = toks.slice(slot..slot + 1);
14236                    embed_gather_rows_into(
14237                        e,
14238                        &ce.table,
14239                        &tv,
14240                        &mut emb,
14241                        1,
14242                        hidden,
14243                        ce.qt,
14244                        ce.row_bytes,
14245                    )?;
14246                    emb
14247                }
14248            };
14249            let mut enorm = ws.take_f32(e, "mtp.enorm", t * hidden, 0)?;
14250            e.rms_norm(
14251                &emb,
14252                &mtp.pre_norm_embed,
14253                &mut enorm,
14254                hidden,
14255                t,
14256                mtp.eps_embed,
14257            )?;
14258            let mut evec = ws.take_f32(e, "mtp.evec", t * hidden, 0)?;
14259            linear_trunk_into(
14260                e,
14261                &mtp.fc_embed,
14262                &mtp.fc_embed_b16,
14263                &enorm,
14264                &mut evec,
14265                t,
14266                hidden,
14267                hidden,
14268            )?;
14269            // Stage the seed rows at offset 0 (exact copy), then FLAT-norm the whole
14270            // wide vector per token (GemmaRMSNorm_wide — SEMANTICS.md §MTP).
14271            let mut hin = ws.take_f32(e, "mtp.hin", t * wide, 0)?;
14272            e.copy_range_into(&mut hin, 0, hidden_wide, wide_off * wide, t * wide)?;
14273            let mut hnorm = ws.take_f32(e, "mtp.hnorm", t * wide, 0)?;
14274            e.rms_norm(
14275                &hin,
14276                &mtp.pre_norm_hidden,
14277                &mut hnorm,
14278                wide,
14279                t,
14280                mtp.eps_hidden,
14281            )?;
14282            // fc_hidden per stream = the same [H, H] mat over every (token, stream) row
14283            // of the normed wide buffer viewed [t*streams, H].
14284            let mut fused = ws.take_f32(e, "mtp.fused", t * wide, 0)?;
14285            linear_trunk_into(
14286                e,
14287                &mtp.fc_hidden,
14288                &mtp.fc_hidden_b16,
14289                &hnorm,
14290                &mut fused,
14291                t * streams,
14292                hidden,
14293                hidden,
14294            )?;
14295            let mut planes: Vec<CudaSlice<f32>> = Vec::with_capacity(streams);
14296            for s in 0..streams {
14297                let mut plane = ws.take_f32(e, PLANE_SLOTS[s], t * hidden, cap * hidden)?;
14298                for tok in 0..t {
14299                    e.copy_range_into(
14300                        &mut plane,
14301                        tok * hidden,
14302                        &fused,
14303                        (tok * streams + s) * hidden,
14304                        hidden,
14305                    )?;
14306                }
14307                let mut view = plane.slice_mut(0..t * hidden);
14308                e.axpy_into(&evec, 1.0, &mut view, t * hidden)?;
14309                planes.push(plane);
14310            }
14311            ws.put_f32("mtp.emb", emb);
14312            ws.put_f32("mtp.enorm", enorm);
14313            ws.put_f32("mtp.evec", evec);
14314            ws.put_f32("mtp.hin", hin);
14315            ws.put_f32("mtp.hnorm", hnorm);
14316            ws.put_f32("mtp.fused", fused);
14317            Ok(planes)
14318        })?;
14319
14320        let ptr_vals: Vec<u64> = {
14321            let stream = e.gpu.stream();
14322            planes.iter().map(|p| p.device_ptr(&stream).0).collect()
14323        };
14324        let ptrs = ws.take_u64_h2d(e, "hc.ptrs", &ptr_vals, 0)?;
14325
14326        // ---- the one decoder layer (trunk program, draft weights/cache)
14327        let layer = &mtp.layer;
14328        let (mixed, inject) = prof_section(e, "mtp.hyper.read", || {
14329            self.gate_read(
14330                e,
14331                ws,
14332                &ptrs,
14333                &layer.attn_gate,
14334                &planes,
14335                t,
14336                layer.eps_attn,
14337                false,
14338            )
14339        })?;
14340        let MixerW::Qsa(qsa) = &layer.mixer else {
14341            return Err("qwen4exp_gpu: MTP mixer is not QSA".into());
14342        };
14343        let block_out = prof_section(e, "mtp.qsa", || {
14344            self.qsa_forward(
14345                e,
14346                ws,
14347                layer,
14348                qsa,
14349                &mixed,
14350                &mut dstate.mixer,
14351                base,
14352                t,
14353                pos_off,
14354                false,
14355            )
14356        })?;
14357        ws.put_f32("hc.mixed", mixed);
14358        prof_section(e, "mtp.hyper.write", || {
14359            self.gate_write(e, &mut planes, &ptrs, &block_out, &inject, t)
14360        })?;
14361        ws.put_f32("mixer.out", block_out);
14362        put_inject(ws, inject);
14363        let (mixed, inject) = prof_section(e, "mtp.hyper.read", || {
14364            self.gate_read(
14365                e,
14366                ws,
14367                &ptrs,
14368                &layer.mlp_gate,
14369                &planes,
14370                t,
14371                layer.eps_mlp,
14372                false,
14373            )
14374        })?;
14375        let mlp = prof_section(e, "mtp.moe", || {
14376            // Rows mode for chain/replay shapes; the big draft PREFILL takes the
14377            // per-expert executor (each expert's rows widen once for all its tokens).
14378            self.moe_forward(e, ws, &layer.moe, &mixed, t, t <= 32, layer.index)
14379        })?;
14380        ws.put_f32("hc.mixed", mixed);
14381        prof_section(e, "mtp.hyper.write", || {
14382            self.gate_write(e, &mut planes, &ptrs, &mlp, &inject, t)
14383        })?;
14384        ws.put_f32("moe.out", mlp);
14385        put_inject(ws, inject);
14386
14387        // ---- carrier (post-layer wide state, PRE exit mixer — the K>1 seed)
14388        let mut carrier = ws.take_f32(e, "mtp.carrier", t * wide, 0)?;
14389        for (s, plane) in planes.iter().enumerate() {
14390            for tok in 0..t {
14391                e.copy_range_into(
14392                    &mut carrier,
14393                    tok * wide + s * hidden,
14394                    plane,
14395                    tok * hidden,
14396                    hidden,
14397                )?;
14398            }
14399        }
14400
14401        // ---- exit: the draft's own mixer read (no inject) -> shared lm_head.
14402        // Only the LAST row's logits are ever consumed (chain steps run t == 1; the
14403        // replay/prefill rows exist for the KV cache and the carrier), so the head
14404        // reads one hidden row — the full-vocab matvec is the draft's single largest
14405        // cost (mtp4 profile) and must not scale with the replay length.
14406        let x = prof_section(e, "mtp.exit", || {
14407            Ok(self
14408                .gate_read_inner(
14409                    e,
14410                    ws,
14411                    &ptrs,
14412                    &mtp.mixer,
14413                    &planes,
14414                    t,
14415                    self.exit_eps,
14416                    false,
14417                    false,
14418                )?
14419                .0)
14420        })?;
14421        ws.put_u64("hc.ptrs", ptrs);
14422        // The head is the SHARED trunk head, or its FR-Spec trimmed gather when the draft
14423        // trim is armed (mtp9): out_f drops from the 248,320 vocab to N, which is the
14424        // draft's single largest cost. Same bytes either way — a trimmed row's logit is
14425        // bit-identical to its full-vocab twin.
14426        let trim = self.draft_trim.as_ref();
14427        let out_f = trim.map_or(self.vocab, |t| t.n);
14428        // Card-1 placement reads its private head copy (same bytes, same program);
14429        // otherwise the shared trunk head. Trim + dev1 is refused at build time.
14430        let (head_w, head_b16) = match self.mtp_dev1.as_ref() {
14431            Some(d) => (&d.output, &d.output_b16),
14432            None => (&self.output, &self.output_b16),
14433        };
14434        let head_into =
14435            |e: &Engine, x: &CudaSlice<f32>, y: &mut CudaSlice<f32>, rows: usize| -> Res<()> {
14436                match trim {
14437                    Some(trim) => linear_trim_into(e, trim, x, y, rows, hidden),
14438                    None => linear_trunk_into(e, head_w, head_b16, x, y, rows, hidden, self.vocab),
14439                }
14440            };
14441        let logits = prof_section(e, "mtp.lm_head", || {
14442            if logits_all {
14443                let mut logits = ws.take_f32(e, "mtp.logits", t * out_f, 0)?;
14444                head_into(e, &x, &mut logits, t)?;
14445                return Ok(logits);
14446            }
14447            let mut logits = ws.take_f32(e, "mtp.logits", out_f, 0)?;
14448            let mut x_last = ws.take_f32(e, "mtp.xlast", hidden, 0)?;
14449            e.copy_range_into(&mut x_last, 0, &x, (t - 1) * hidden, hidden)?;
14450            head_into(e, &x_last, &mut logits, 1)?;
14451            ws.put_f32("mtp.xlast", x_last);
14452            Ok(logits)
14453        })?;
14454        ws.put_f32("hc.mixed", x);
14455        for (s, plane) in planes.into_iter().enumerate() {
14456            ws.put_f32(PLANE_SLOTS[s], plane);
14457        }
14458        dstate.rows += t;
14459        Ok((logits, carrier))
14460    }
14461
14462    /// Return a draft step's logits/carrier buffers to the draft workspace (address
14463    /// reuse across the hot loop).
14464    pub fn mtp_recycle(
14465        &self,
14466        dstate: &mut MtpDraftState,
14467        logits: CudaSlice<f32>,
14468        carrier: CudaSlice<f32>,
14469    ) {
14470        dstate.ws.put_f32("mtp.logits", logits);
14471        dstate.ws.put_f32("mtp.carrier", carrier);
14472    }
14473}
14474
14475// ---------------------------------------------------------------- spec decode (mtp-spec lane)
14476
14477/// Vendor-default sampling config for the SAMPLED spec run (the serving law's probe
14478/// shape): temp 1.0 / top_p 0.95 / top_k 20 on qwen4_exp. Greedy (None) stays the
14479/// byte-identity instrument.
14480#[derive(Clone, Copy)]
14481pub struct SpecSamplerCfg {
14482    pub temperature: f32,
14483    pub top_p: f32,
14484    pub top_k: usize,
14485    pub seed: u64,
14486}
14487
14488/// xorshift64* — deterministic, seedable, dependency-free (receipt reproducibility).
14489struct SpecRng(u64);
14490
14491impl SpecRng {
14492    fn next_f32(&mut self) -> f32 {
14493        let mut x = self.0;
14494        x ^= x >> 12;
14495        x ^= x << 25;
14496        x ^= x >> 27;
14497        self.0 = x;
14498        let bits = (x.wrapping_mul(0x2545_F491_4F6C_DD1D) >> 40) as u32;
14499        bits as f32 / (1u64 << 24) as f32
14500    }
14501}
14502
14503/// Host top-k/top-p/temperature sample over one logits row.
14504fn sample_row(cfg: &SpecSamplerCfg, rng: &mut SpecRng, row: &[f32]) -> u32 {
14505    let k = cfg.top_k.max(1).min(row.len());
14506    let mut idx: Vec<u32> = (0..row.len() as u32).collect();
14507    idx.select_nth_unstable_by(k - 1, |&a, &b| row[b as usize].total_cmp(&row[a as usize]));
14508    let mut top: Vec<(u32, f32)> = idx[..k].iter().map(|&i| (i, row[i as usize])).collect();
14509    top.sort_by(|a, b| b.1.total_cmp(&a.1));
14510    let temp = cfg.temperature.max(1e-6);
14511    let mx = top[0].1;
14512    let mut probs: Vec<f32> = top.iter().map(|&(_, v)| ((v - mx) / temp).exp()).collect();
14513    let sum: f32 = probs.iter().sum();
14514    for p in &mut probs {
14515        *p /= sum;
14516    }
14517    // top_p nucleus over the sorted tail.
14518    let mut cut = probs.len();
14519    let mut acc = 0.0f32;
14520    for (i, &p) in probs.iter().enumerate() {
14521        acc += p;
14522        if acc >= cfg.top_p {
14523            cut = i + 1;
14524            break;
14525        }
14526    }
14527    let renorm: f32 = probs[..cut].iter().sum();
14528    let draw = rng.next_f32() * renorm;
14529    let mut acc = 0.0f32;
14530    for (i, &p) in probs[..cut].iter().enumerate() {
14531        acc += p;
14532        if draw < acc {
14533            return top[i].0;
14534        }
14535    }
14536    top[cut - 1].0
14537}
14538
14539/// Host argmax with the plain chain's tie rule (strictly-greater keeps the smallest
14540/// index) — bit-identical to the device 2-pass argmax (argmax-gate contract), which is
14541/// what lets the trace and plain-tail paths commit host argmaxes without moving a chain.
14542fn host_argmax(row: &[f32]) -> usize {
14543    let mut best = 0usize;
14544    for (i, &v) in row.iter().enumerate() {
14545        if v > row[best] {
14546            best = i;
14547        }
14548    }
14549    best
14550}
14551
14552/// P2P-copy `t` wide rows at row offset `off` from the card-0 verify wide stash into
14553/// the card-1 mirror (mtp10 dev1 draft placement), issued on the DRAFT engine's stream
14554/// and host-synced — the sync is where the crossing is TIMED, and the draft's next
14555/// kernels queue behind the copy on the same stream either way. Host ordering
14556/// guarantees the source rows are complete: every call site sits after a `forward`
14557/// whose host dtoh (logits or argmax) synced card 0's stream.
14558/// Ring-contiguous pieces of an absolute wide-row range [off, off+t): (slot_off, len)
14559/// per piece — one piece unless the range crosses the ring seam (then two). Identity
14560/// slots when ring >= off + t never wraps (the historical whole-history stash).
14561fn ring_pieces(ring: usize, off: usize, t: usize) -> Vec<(usize, usize)> {
14562    debug_assert!(t <= ring, "wide-ring consumer wider than the ring");
14563    let slot = off % ring;
14564    if slot + t <= ring {
14565        vec![(slot, t)]
14566    } else {
14567        vec![(slot, ring - slot), (0, t - (ring - slot))]
14568    }
14569}
14570
14571fn cross_wide_rows(
14572    e: &Engine,
14573    de: &Engine,
14574    src: &CudaSlice<f32>,
14575    dst: &mut CudaSlice<f32>,
14576    off: usize,
14577    t: usize,
14578    wide: usize,
14579) -> Res<f64> {
14580    let t0 = std::time::Instant::now();
14581    let stream = de.gpu.stream();
14582    let bytes = t * wide * 4;
14583    let byte_off = (off * wide * 4) as u64;
14584    let (sp, _g0) = src.device_ptr(&stream);
14585    let (dp, _g1) = dst.device_ptr_mut(&stream);
14586    unsafe {
14587        cudarc::driver::result::memcpy_peer_async(
14588            de.ctx().cu_ctx(),
14589            dp + byte_off,
14590            e.ctx().cu_ctx(),
14591            sp + byte_off,
14592            bytes,
14593            stream.cu_stream(),
14594        )?;
14595    }
14596    stream.synchronize()?;
14597    Ok(t0.elapsed().as_secs_f64() * 1e3)
14598}
14599
14600/// Launch `embed_gather_u32_t` for ONE device-slot token into the pooled `mtp.emb`
14601/// buffer (mtp11 deferred chain). Same kernel as the lib.rs `embed_gather_device_*`
14602/// family — bit-identical rows by the same per-dtype deq contract. Lives here (not as
14603/// an Engine method) because the deferred chain is this module's machinery.
14604fn embed_gather_rows_into(
14605    e: &Engine,
14606    table: &CudaSlice<u8>,
14607    tok_v: &CudaView<u32>,
14608    x_out: &mut CudaSlice<f32>,
14609    t: usize,
14610    n_embd: usize,
14611    qtype: i32,
14612    row_bytes: usize,
14613) -> Res<()> {
14614    let f = e.func("embed_gather_u32_t");
14615    let cfg = LaunchConfig {
14616        grid_dim: (((n_embd as u32).div_ceil(256)).max(1), t as u32, 1),
14617        block_dim: (256, 1, 1),
14618        shared_mem_bytes: 0,
14619    };
14620    let (ne, qt, rb, ti) = (n_embd as i32, qtype, row_bytes as i64, t as i32);
14621    let stream = e.gpu.stream();
14622    let mut b = stream.launch_builder(&f);
14623    b.arg(table)
14624        .arg(tok_v)
14625        .arg(x_out)
14626        .arg(&ne)
14627        .arg(&qt)
14628        .arg(&rb)
14629        .arg(&ti);
14630    unsafe {
14631        b.launch(cfg)?;
14632    }
14633    Ok(())
14634}
14635
14636/// One spec run's counters (the accept-length table's source).
14637#[derive(Debug, Default, Clone)]
14638pub struct SpecReport {
14639    pub tokens: Vec<u32>,
14640    pub rounds: usize,
14641    pub drafted: u64,
14642    pub accepted: u64,
14643    /// hist[a] = rounds that accepted exactly `a` drafts (a in 0..=k).
14644    pub accept_hist: Vec<u64>,
14645    pub draft_ms: f64,
14646    pub verify_ms: f64,
14647    pub prefill_ms: f64,
14648    pub total_ms: f64,
14649    /// draft_ms split (the round-cost identity table): the K-step chain, the accepted-
14650    /// token catch-up replay, and the one-time draft prefill. draft_ms is their sum.
14651    pub chain_ms: f64,
14652    pub replay_ms: f64,
14653    pub draft_prefill_ms: f64,
14654    /// Card-1 crossing cost (mtp10 dev1 placement): wall time and bytes of the P2P
14655    /// wide-row copies (prefill seed + per-round replay seeds). 0 on one card.
14656    pub cross_ms: f64,
14657    pub cross_bytes: u64,
14658    /// Dynamic-K admission (mtp10): every decay as (round, new_k). Empty = K never moved.
14659    pub k_decays: Vec<(usize, usize)>,
14660    /// Token count at which the policy turned spec fully OFF (k reached 0); the rest of
14661    /// the generation ran plain decode steps (counted in `plain_steps`, not `rounds`).
14662    pub spec_off_at: Option<usize>,
14663    pub plain_steps: usize,
14664    /// Per-round wall samples: (tokens committed so far, ms since generation start),
14665    /// appended after every round/plain step — lets a caller derive N timing sub-rounds
14666    /// from ONE generation (the x3-rounds protocol where a fresh prefill per timing
14667    /// round is prohibitive, e.g. the 1M ladder).
14668    pub round_wall: Vec<(usize, f64)>,
14669    /// p-min guard accounting: rounds that drafted NOTHING (verify = plain t==1 step)
14670    /// and chain steps cut short (the sub-threshold token discarded uncounted).
14671    pub zero_draft_rounds: usize,
14672    pub guard_stops: usize,
14673}
14674
14675/// Bounded shape-aware spec admission (mtp10): rolling-accept-driven K decay. Every
14676/// round pushes its accept count into a window of the last `window` rounds; when the
14677/// window is full and its mean accept < `thr` (draft tokens per round, 0..=k), K steps
14678/// DOWN by one (never up — decay only, bounded and monotone) and the window resets so
14679/// decays are at least `window` rounds apart. At K = `k_floor` the decay stops; with
14680/// `k_floor` = 0 reaching it turns spec OFF for the REST of the generation (plain
14681/// greedy decode steps — the draft cost is what the collapsed shape was paying for).
14682/// Byte identity is untouched BY CONSTRUCTION at every K: committed tokens are always
14683/// the target rows' argmax, and the plain tail IS the plain program.
14684#[derive(Clone, Copy, Debug)]
14685pub struct DynKCfg {
14686    pub window: usize,
14687    pub thr: f64,
14688    pub k_floor: usize,
14689}
14690
14691/// Spec-round admission options (mtp10). Every knob defaults OFF; each is a bounded
14692/// policy that can only shrink the drafted window — the committed output is the target
14693/// rows' argmax at every setting, so byte identity is untouched by construction.
14694#[derive(Clone, Copy, Debug, Default)]
14695pub struct SpecOpts {
14696    /// Rolling-window K decay (the last-resort shape bound). See `DynKCfg`.
14697    pub dynk: Option<DynKCfg>,
14698    /// Adaptive per-round window (the dflash MEMRA_DFLASH_ADAPT "accepted+1" recipe):
14699    /// next round drafts clamp(last_accept + 1, k_lo, k). `Some(k_lo)` arms it.
14700    pub adapt_k_lo: Option<usize>,
14701    /// p-min draft-confidence guard (the MEMRA_SPEC_PMIN mechanism, sub-threshold token
14702    /// DISCARDED UNCOUNTED — the reference engines' normalization). Applies at j == 0
14703    /// too (the MEMRA_SPEC_PMIN0 zero-draft-round semantics): a low-confidence round
14704    /// drafts NOTHING and its verify is a plain t == 1 step that still commits one
14705    /// token — unpredictable stretches never pay draft + verify-column overhead.
14706    /// 0.0 = off.
14707    pub pmin: f32,
14708    /// Deferred round readback (mtp11, the spec.rs slice-2 structure ported): the
14709    /// chain's argmax feeds the next step ON DEVICE through the armed chain-embed
14710    /// table (`arm_spec_devchain` required), the guard's confidences land in device
14711    /// slots, and the chain drains ONCE per round before the verify (the PLE host
14712    /// n-gram gather needs the chunk's token ids, so this family's floor is a 2-drain
14713    /// round, not spec.rs's 1). t == 1 steps take the device-argmax fast path and the
14714    /// prefill dtoh shrinks to one row. Committed bytes identical BY CONSTRUCTION
14715    /// (same kernels, same picks; spec-gate arbitrates). Default OFF (flags law);
14716    /// mutually exclusive with `trace` (trace reads per-step host rows).
14717    pub defer: bool,
14718    /// With `defer` + `pmin`: keep the guard SEQUENTIAL — one 4-byte prob dtoh per
14719    /// chain step, the chain stops exactly at the sub-threshold step (today's cost
14720    /// shape). Default OFF = the deferred guard: probabilities drain with the chain
14721    /// and truncate at the FIRST sub-threshold step — same picks and counters
14722    /// bit-for-bit, but the dispatched suffix past the stop is work the sequential
14723    /// arm never paid. The guard-forces-a-readback A/B the owner asked to measure.
14724    pub defer_guard_sync: bool,
14725    /// Long-context lane: chunked co-prefill (trunk chunk forward with the head
14726    /// skipped, then the draft consumes that chunk's wide rows) instead of the one-shot
14727    /// prompt forward — the one-shot shape at 500k+ would materialize chunk-sized
14728    /// transients per plane AND a [n, vocab] logits block. `None` = the historical
14729    /// one-shot (byte-stable receipts).
14730    pub prefill_chunk: Option<usize>,
14731    /// Long-context lane: RING-bounded wide stash rows (`spec_arm_ring`) — at 1M
14732    /// capacity the whole-history stash is ~41 GB/card. Requires `prefill_chunk` (the
14733    /// co-prefill consumes each chunk before the ring overwrites it) and must be
14734    /// >= 2 * prefill_chunk. `None` = whole-history (the historical layout).
14735    pub wide_ring: Option<usize>,
14736}
14737
14738/// The deferred guard's drain-time truncation (mtp11): the FIRST sub-threshold
14739/// confidence (predicate `p < pmin` — the host chain's exact stop rule, boundary
14740/// p == pmin PASSES) ends the drafted window; picks before it survive, the
14741/// sub-threshold pick is discarded uncounted, everything after is dispatch the
14742/// sequential arm never paid. Pure so the tiny gate can pin the walk on arbitrary
14743/// windows: mid-chain dips are unreachable on the deterministic tiny fixture
14744/// (intra-round confidence never crosses a passed threshold there), so this pin plus
14745/// the real-model `--defer-ab` counter identity are the mid-chain coverage.
14746pub fn spec_guard_trunc(probs: &[f32], pmin: f32) -> usize {
14747    probs.iter().position(|&p| p < pmin).unwrap_or(probs.len())
14748}
14749
14750/// One traced spec round (the mtp10 thinkon-decay diagnosis instrument). Trace mode
14751/// changes NOTHING the accept walk sees — it only reads: draft logit rows, carrier
14752/// seeds, and the verify's captured wide rows come to host for margin/drift stats.
14753/// (Greedy trace runs with host-argmax targets — the same argmax the plain chain uses,
14754/// proven equal to the device walk by the spec-gate.)
14755#[derive(Debug, Default, Clone)]
14756pub struct SpecTraceRound {
14757    pub round: usize,
14758    /// Committed generation length BEFORE this round (position within the generation).
14759    pub gen_pos: usize,
14760    /// Trunk committed rows before the round (the tip's absolute position).
14761    pub base: usize,
14762    pub k: usize,
14763    pub a: usize,
14764    pub drafts: Vec<u32>,
14765    /// k+1 target rows (the committed prefix is targets[0..=a]).
14766    pub targets: Vec<u32>,
14767    /// Fork-row stats (row `a`, present when a < k): the draft's top-2 logits, the
14768    /// draft's logit and rank of the token the TARGET wanted, the target's top-2 logits,
14769    /// the target's logit of the token the DRAFT proposed, and the target row's softmax
14770    /// entropy (nats). NaN/0 when the round accepted everything (no fork).
14771    pub draft_top1: f32,
14772    pub draft_top2: f32,
14773    pub draft_tgt_logit: f32,
14774    pub draft_tgt_rank: usize,
14775    pub target_top1: f32,
14776    pub target_top2: f32,
14777    pub target_draft_logit: f32,
14778    pub target_entropy: f64,
14779    /// Carrier drift per carrier-seeded chain step j = 1..k-1: the seed the draft used
14780    /// (its own predicted wide for position base+j-1) vs the trunk's TRUE wide row at
14781    /// that position (captured by the verify chunk). rel_l2 = ||seed-true||/||true||.
14782    pub carrier_rel_l2: Vec<f32>,
14783    pub carrier_cos: Vec<f32>,
14784}
14785
14786impl SpecReport {
14787    pub fn accept_rate(&self) -> f64 {
14788        if self.drafted == 0 {
14789            0.0
14790        } else {
14791            self.accepted as f64 / self.drafted as f64
14792        }
14793    }
14794    /// Mean committed tokens per round (accepted + bonus).
14795    pub fn mean_accept_len(&self) -> f64 {
14796        if self.rounds == 0 {
14797            0.0
14798        } else {
14799            self.tokens.len() as f64 / self.rounds as f64
14800        }
14801    }
14802}
14803
14804impl Qwen4ExpGpu {
14805    /// Arm the verify instrument on `state`: absolute-position wide capture (the
14806    /// draft's hidden seeds) + per-column GDN/PLE stashes for chunks up to `k_cap`
14807    /// columns. Idempotent for the same k_cap.
14808    pub fn spec_arm(&self, e: &Engine, state: &mut Qwen4ExpState, k_cap: usize) -> Res<()> {
14809        self.spec_arm_ring(e, state, k_cap, state.capacity)
14810    }
14811
14812    /// `spec_arm` with a RING-bounded wide stash (long-context lane): the stash holds the
14813    /// last `ring_rows` wide rows (slot = row % ring_rows) instead of `capacity` rows —
14814    /// at 1M capacity the full stash is ~41 GB/card, the ring ~0.7 GB. Every consumer
14815    /// reads rows within `ring_rows` of the write head (chunked co-prefill consumes each
14816    /// chunk before the next lands; rounds read the last k+2 rows), asserted at the read
14817    /// helpers. `spec_arm` (ring = capacity) keeps the historical byte-stable layout.
14818    pub fn spec_arm_ring(
14819        &self,
14820        e: &Engine,
14821        state: &mut Qwen4ExpState,
14822        k_cap: usize,
14823        ring_rows: usize,
14824    ) -> Res<()> {
14825        let ring_rows = ring_rows.min(state.capacity).max(k_cap + 2);
14826        if let Some(v) = state.verify.as_ref() {
14827            if v.k_cap == k_cap && v.ring_rows == ring_rows {
14828                return Ok(());
14829            }
14830        }
14831        let wide = self.streams * self.hidden;
14832        let mut gdn = Vec::with_capacity(self.layers.len());
14833        let mut ple = Vec::with_capacity(self.layers.len());
14834        for layer in &self.layers {
14835            gdn.push(match &layer.mixer {
14836                MixerW::Gdn(g) => {
14837                    let p = &g.plan;
14838                    let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
14839                    let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
14840                    let conv_dim = 2 * nk * hk + nv * hv;
14841                    let pad = p.conv_kernel as usize - 1;
14842                    Some(GdnStash {
14843                        states: e.zeros(k_cap * nv * hv * hk)?,
14844                        conv_pre: e.zeros(pad * conv_dim)?,
14845                        qkv_rows: e.zeros(k_cap * conv_dim)?,
14846                        scan_graph: None,
14847                        scan_warm: None,
14848                    })
14849                }
14850                MixerW::Qsa(_) => None,
14851            });
14852            ple.push(match layer.ple.as_ref() {
14853                Some(pw) => {
14854                    let pad = (pw.plan.conv_kernel as usize - 1) * pw.plan.max_ngram as usize;
14855                    let mut hist_pre = Vec::with_capacity(self.streams);
14856                    let mut normed_rows = Vec::with_capacity(self.streams);
14857                    for _ in 0..self.streams {
14858                        hist_pre.push(e.zeros(pad * self.hidden)?);
14859                        normed_rows.push(e.zeros(k_cap * self.hidden)?);
14860                    }
14861                    Some(PleStash {
14862                        hist_pre,
14863                        normed_rows,
14864                    })
14865                }
14866                None => None,
14867            });
14868        }
14869        state.verify = Some(VerifyStash {
14870            k_cap,
14871            chunk: None,
14872            fused_chunk: None,
14873            gdn,
14874            ple,
14875            wide: e.zeros(ring_rows * wide)?,
14876            ring_rows,
14877            wide_dev1: None,
14878            argmax: Vec::new(),
14879            toks: unsafe { e.gpu.stream().alloc::<u32>(k_cap)? },
14880            want_argmax: false,
14881            want_argmax_t1: false,
14882            last_row_only: false,
14883        });
14884        Ok(())
14885    }
14886
14887    pub fn spec_disarm(&self, state: &mut Qwen4ExpState) {
14888        state.verify = None;
14889    }
14890
14891    pub fn set_verify_want_argmax(&self, state: &mut Qwen4ExpState, on: bool) -> Res<()> {
14892        state
14893            .verify
14894            .as_mut()
14895            .ok_or("qwen4exp_gpu: verify not armed")?
14896            .want_argmax = on;
14897        Ok(())
14898    }
14899
14900    /// The last exact chunk's per-row device-argmax tokens (want_argmax mode).
14901    pub fn verify_argmax_rows<'s>(&self, state: &'s Qwen4ExpState) -> Res<&'s [u32]> {
14902        Ok(&state
14903            .verify
14904            .as_ref()
14905            .ok_or("qwen4exp_gpu: verify not armed")?
14906            .argmax)
14907    }
14908
14909    /// Rewind the trunk state to the first `keep` rows of the live verify chunk:
14910    /// bookkeeping truncation + GDN state restore from the per-column snapshots + GDN/
14911    /// PLE conv-history rebuild from the stashed pre-chunk history and chunk rows.
14912    /// `keep == t` is the all-accepted fast path (state already correct).
14913    pub fn verify_rewind(&self, e: &Engine, state: &mut Qwen4ExpState, keep: usize) -> Res<()> {
14914        let Some(v) = state.verify.as_mut() else {
14915            return Err("qwen4exp_gpu: verify not armed".into());
14916        };
14917        let Some((base, t)) = v.chunk.take() else {
14918            if let Some((fb, ft)) = v.fused_chunk.take() {
14919                return Err(format!(
14920                    "qwen4exp_gpu: verify chunk (base {fb}, t {ft}) ran the FUSED program \
14921                     (`vfuse` cost instrument) — no per-column GDN/PLE stash exists, so it \
14922                     cannot be rewound. vfuse is a timing probe on a throwaway state; drop \
14923                     the seam to run a spec loop."
14924                )
14925                .into());
14926            }
14927            return Err("qwen4exp_gpu: no live verify chunk to rewind".into());
14928        };
14929        if keep == 0 || keep > t {
14930            return Err("qwen4exp_gpu: rewind keep out of range".into());
14931        }
14932        if keep == t {
14933            return Ok(());
14934        }
14935        state.pos = base + keep;
14936        state.tokens.truncate(base + keep);
14937        for (li, (layer, lstate)) in self.layers.iter().zip(state.layers.iter_mut()).enumerate() {
14938            match (&layer.mixer, &mut lstate.mixer) {
14939                (
14940                    MixerW::Qsa(qsa),
14941                    MixerState::Qsa {
14942                        raw_keys,
14943                        pooled_keys,
14944                        pooled_dev_rows,
14945                        raw_dev_rows,
14946                        idx_audit,
14947                        ..
14948                    },
14949                ) => {
14950                    let idx_dim = qsa.overlay.head_dim as usize;
14951                    raw_keys.truncate_rows(base + keep, idx_dim);
14952                    let block = qsa.overlay.block_size as usize;
14953                    pooled_keys.truncate(((base + keep) / block) * idx_dim);
14954                    // Device mirror follows the host truncation (see mtp_rewind).
14955                    *pooled_dev_rows = (*pooled_dev_rows).min(pooled_keys.len() / idx_dim);
14956                    // Device raw-key cache (idxcache): clamp to the ABSOLUTE kept row
14957                    // count (the host cache may lag below it — lazy materialization).
14958                    *raw_dev_rows = (*raw_dev_rows).min(base + keep);
14959                    // The audit twin tracks the cache rows exactly (instrument).
14960                    if let Some(audit) = idx_audit.as_deref_mut() {
14961                        audit.raw_f32.truncate_rows(base + keep, idx_dim);
14962                        audit.pooled_f32.truncate(((base + keep) / block) * idx_dim);
14963                    }
14964                }
14965                (MixerW::Gdn(g), MixerState::Gdn { conv, state: rec }) => {
14966                    let st = v.gdn[li]
14967                        .as_mut()
14968                        .ok_or("qwen4exp_gpu: GDN layer without a verify stash")?;
14969                    let p = &g.plan;
14970                    let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
14971                    let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
14972                    let conv_dim = 2 * nk * hk + nv * hv;
14973                    let pad = p.conv_kernel as usize - 1;
14974                    let state_len = nv * hv * hk;
14975                    e.copy_range_into(rec, 0, &st.states, (keep - 1) * state_len, state_len)?;
14976                    if keep >= pad {
14977                        e.copy_range_into(
14978                            conv,
14979                            0,
14980                            &st.qkv_rows,
14981                            (keep - pad) * conv_dim,
14982                            pad * conv_dim,
14983                        )?;
14984                    } else {
14985                        let keep_hist = pad - keep;
14986                        e.copy_range_into(
14987                            conv,
14988                            0,
14989                            &st.conv_pre,
14990                            keep * conv_dim,
14991                            keep_hist * conv_dim,
14992                        )?;
14993                        e.copy_range_into(
14994                            conv,
14995                            keep_hist * conv_dim,
14996                            &st.qkv_rows,
14997                            0,
14998                            keep * conv_dim,
14999                        )?;
15000                    }
15001                }
15002                _ => return Err("qwen4exp_gpu: mixer/state mismatch in rewind".into()),
15003            }
15004            if let (Some(pw), Some(ps)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
15005                let st = v.ple[li]
15006                    .as_mut()
15007                    .ok_or("qwen4exp_gpu: PLE layer without a verify stash")?;
15008                let pad = (pw.plan.conv_kernel as usize - 1) * pw.plan.max_ngram as usize;
15009                let hidden = self.hidden;
15010                for s in 0..self.streams {
15011                    let hist = &mut ps.conv_hist[s];
15012                    if keep >= pad {
15013                        e.copy_range_into(
15014                            hist,
15015                            0,
15016                            &st.normed_rows[s],
15017                            (keep - pad) * hidden,
15018                            pad * hidden,
15019                        )?;
15020                    } else {
15021                        let keep_hist = pad - keep;
15022                        e.copy_range_into(
15023                            hist,
15024                            0,
15025                            &st.hist_pre[s],
15026                            keep * hidden,
15027                            keep_hist * hidden,
15028                        )?;
15029                        e.copy_range_into(
15030                            hist,
15031                            keep_hist * hidden,
15032                            &st.normed_rows[s],
15033                            0,
15034                            keep * hidden,
15035                        )?;
15036                    }
15037                }
15038            }
15039        }
15040        Ok(())
15041    }
15042
15043    /// Device argmax of ONE draft-logits row (4-byte dtoh), returned as a TARGET vocab
15044    /// id: the row width is the trim width when armed and the winning row maps back
15045    /// through d2t (identity when the trim is off). `conf` (the p-min guard, prior art
15046    /// MEMRA_SPEC_PMIN / gemma confidence-adaptive draft depth — the SAME
15047    /// prob_of_token kernels) additionally returns the head's softmax confidence in its
15048    /// own pick: one extra 2-pass sum-exp launch + a 4-byte dtoh. Under a trim the
15049    /// confidence reads the TRIMMED row (inflated vs full softmax — thresholds are
15050    /// per-configuration, stated in the receipt).
15051    fn draft_row_argmax(
15052        &self,
15053        e: &Engine,
15054        logits: &CudaSlice<f32>,
15055        row: usize,
15056        conf: bool,
15057    ) -> Res<(u32, f32)> {
15058        let width = self.draft_logits_width();
15059        let mut tok = unsafe { e.gpu.stream().alloc::<u32>(1)? };
15060        e.argmax_token_device_col(logits, row, width, &mut tok, 0)?;
15061        let p = if conf {
15062            if row != 0 {
15063                // The chain shape is single-row; prob_of_token reads logits[0..width].
15064                return Err("qwen4exp_gpu: draft confidence reads row 0 (the chain shape)".into());
15065            }
15066            let pd = e.prob_of_token_device(logits, &tok, width)?;
15067            e.gpu.stream().clone_dtoh(&pd)?[0]
15068        } else {
15069            1.0
15070        };
15071        Ok((self.draft_token(e.gpu.stream().clone_dtoh(&tok)?[0])?, p))
15072    }
15073
15074    /// MTP speculative decode (mtp-spec lane): prefill, draft-prefill the MTP block
15075    /// over the prompt, then rounds of K-token drafting (single-layer draft, carrier-
15076    /// chained) + ONE trunk verify chunk (t = K+1, every row bit-identical to the
15077    /// t == 1 decode program) + greedy accept walk + replay-free partial rewind.
15078    ///
15079    /// Greedy (sampler None) is the byte-identity instrument: output must equal the
15080    /// spec-off greedy chain token for token. `Some(cfg)` runs the vendor-default
15081    /// sampled shape: targets are SAMPLED per verify row (draft accepted on exact
15082    /// match — distribution-preserving), the serving law's probe.
15083    ///
15084    /// This wrapper is the single-card, no-admission, no-trace shape; the full seam is
15085    /// `spec_generate_ext`.
15086    #[allow(clippy::too_many_arguments)]
15087    pub fn spec_generate(
15088        &self,
15089        e: &Engine,
15090        prompt: &[u32],
15091        max_new: usize,
15092        k: usize,
15093        state: &mut Qwen4ExpState,
15094        dstate: &mut MtpDraftState,
15095        sampler: Option<SpecSamplerCfg>,
15096    ) -> Res<SpecReport> {
15097        self.spec_generate_ext(
15098            e,
15099            e,
15100            prompt,
15101            max_new,
15102            k,
15103            state,
15104            dstate,
15105            sampler,
15106            SpecOpts::default(),
15107            None,
15108        )
15109    }
15110
15111    /// `spec_generate` with the mtp10 seams:
15112    /// - `de` — the DRAFT engine. Same card as `e` by default; the card-1 placement
15113    ///   (`load_from_dir_dev1`) requires the dev1 engine here and P2P-crosses the wide
15114    ///   seed rows per round (timed into `report.cross_ms`).
15115    /// - `opts` — bounded spec admission (p-min guard / adaptive K / dyn-K decay), all
15116    ///   default OFF. Every knob only shrinks the drafted window; commits are always
15117    ///   the target rows, so byte identity holds at every setting by construction.
15118    /// - `trace` — per-round diagnosis records (accept positions, fork margins, carrier
15119    ///   drift). Trace mode only ADDS reads (dtoh) and swaps the device accept-argmax
15120    ///   for the bit-identical host argmax; the committed chain is unchanged.
15121    #[allow(clippy::too_many_arguments)]
15122    pub fn spec_generate_ext(
15123        &self,
15124        e: &Engine,
15125        de: &Engine,
15126        prompt: &[u32],
15127        max_new: usize,
15128        k: usize,
15129        state: &mut Qwen4ExpState,
15130        dstate: &mut MtpDraftState,
15131        sampler: Option<SpecSamplerCfg>,
15132        opts: SpecOpts,
15133        mut trace: Option<&mut Vec<SpecTraceRound>>,
15134    ) -> Res<SpecReport> {
15135        use std::time::Instant;
15136        if k == 0 {
15137            return Err("qwen4exp_gpu: spec needs k >= 1".into());
15138        }
15139        let n = prompt.len();
15140        if n < 2 {
15141            return Err("qwen4exp_gpu: spec needs a >= 2 token prompt".into());
15142        }
15143        if state.pos != 0 || dstate.rows != 0 {
15144            return Err("qwen4exp_gpu: spec_generate wants FRESH trunk + draft states".into());
15145        }
15146        if state.capacity < n + max_new + k + 2 || dstate.capacity < n + max_new + k + 2 {
15147            return Err("qwen4exp_gpu: state capacity too small for prompt + max_new + k".into());
15148        }
15149        self.check_draft_engine(de)?;
15150        let dev1 = self.mtp_dev1.is_some();
15151        if !dev1 && de.ctx().ordinal() != e.ctx().ordinal() {
15152            return Err(
15153                "qwen4exp_gpu: draft engine on another card, but the draft was not \
15154                 built there (load_from_dir_dev1)"
15155                    .into(),
15156            );
15157        }
15158        let vocab = self.vocab;
15159        let wide_w = self.streams * self.hidden;
15160        let greedy = sampler.is_none();
15161        let tracing = trace.is_some();
15162        let guard = opts.pmin > 0.0;
15163        let deferred = opts.defer;
15164        if deferred && tracing {
15165            return Err(
15166                "qwen4exp_gpu: spec defer + trace are mutually exclusive (the trace \
15167                 instrument reads per-step host rows); run the trace on the host-chain arm"
15168                    .into(),
15169            );
15170        }
15171        if deferred {
15172            let ce = self.chain_embed.as_ref().ok_or(
15173                "qwen4exp_gpu: SpecOpts::defer needs arm_spec_devchain on the draft engine",
15174            )?;
15175            if ce.dev != de.ctx().ordinal() {
15176                return Err(format!(
15177                    "qwen4exp_gpu: the chain-embed table lives on device {} but the \
15178                     draft engine is device {} — re-arm arm_spec_devchain",
15179                    ce.dev,
15180                    de.ctx().ordinal()
15181                )
15182                .into());
15183            }
15184            if ce.for_trim != self.draft_trim.is_some() || ce.rows != self.draft_logits_width() {
15185                return Err(
15186                    "qwen4exp_gpu: the chain-embed table was armed for a different trim \
15187                     state — re-arm arm_spec_devchain after trim changes"
15188                        .into(),
15189                );
15190            }
15191        }
15192        // Deferred-round device slots (ONE alloc per generation, on the draft engine):
15193        // chain picks in RAW draft-index space + the guard's per-step confidence.
15194        let (mut chain_toks_d, mut chain_probs_d) = if deferred {
15195            (
15196                Some(unsafe { de.gpu.stream().alloc::<u32>(k)? }),
15197                Some(de.zeros(k)?),
15198            )
15199        } else {
15200            (None, None)
15201        };
15202        let mut rng = sampler
15203            .as_ref()
15204            .map(|cfg| SpecRng(cfg.seed | 1))
15205            .unwrap_or(SpecRng(1));
15206        let t_total = Instant::now();
15207        let mut report = SpecReport {
15208            accept_hist: vec![0; k + 1],
15209            ..Default::default()
15210        };
15211
15212        match opts.wide_ring {
15213            Some(ring) => {
15214                let chunk = opts
15215                    .prefill_chunk
15216                    .ok_or("qwen4exp_gpu: SpecOpts::wide_ring needs prefill_chunk")?;
15217                if ring < 2 * chunk || ring < 2 * (k + 2) {
15218                    return Err("qwen4exp_gpu: wide_ring must cover 2 prefill chunks".into());
15219                }
15220                self.spec_arm_ring(e, state, k + 1, ring)?;
15221            }
15222            None => self.spec_arm(e, state, k + 1)?,
15223        }
15224        self.set_verify_want_argmax(state, false)?;
15225        if let Some(v) = state.verify.as_mut() {
15226            // mtp11 deferred seam: t == 1 steps commit through the device argmax
15227            // (greedy only) and big-t prefills dtoh one row instead of the block.
15228            v.want_argmax_t1 = deferred && greedy && !tracing;
15229            v.last_row_only = deferred;
15230        }
15231        // Card-1 mirror of the wide stash (the draft's seed source on the dev1 route) —
15232        // ring-sized like the stash itself (same slot addressing on both cards).
15233        let ring = state.verify.as_ref().expect("armed above").ring_rows;
15234        if dev1 {
15235            let v = state.verify.as_mut().expect("armed above");
15236            if v.wide_dev1.as_ref().is_none_or(|m| m.len() < ring * wide_w) {
15237                v.wide_dev1 = Some(de.zeros(ring * wide_w)?);
15238            }
15239        }
15240        // Defer arm's draft-side embed route: device gather from the full-vocab chain
15241        // table (a trim table cannot embed arbitrary target/prompt ids — host embed
15242        // stays the trim fallback, stated). Control arm (defer off): host embed,
15243        // structure-frozen.
15244        let dev_embed = deferred
15245            && self
15246                .chain_embed
15247                .as_ref()
15248                .is_some_and(|ce| !ce.for_trim && ce.rows == self.vocab);
15249        let t_prefill = Instant::now();
15250        let mut draft_prefill_ms = 0f64;
15251        let x0: u32 = match opts.prefill_chunk {
15252            // ---- Long-context CO-PREFILL (chunked): trunk chunk forward with the head
15253            // skipped (LastRow on the final chunk — a [n, vocab] logits block at 500k
15254            // would be hundreds of GB), then the dev1 crossing + the draft consuming
15255            // THAT chunk's wide rows before the ring overwrites them. Piece boundaries
15256            // keep the final piece past k_cap so no prefill chunk takes the verify-exact
15257            // path.
15258            Some(chunk) if n > chunk => {
15259                let mut b = 0usize;
15260                let mut last = Vec::new();
15261                // The spec arm banks ONE receipt row per rung, at the end. A long
15262                // co-prefill therefore looks identical to a hang from the outside, which
15263                // is exactly what happened in memra#53: two cells were killed by an
15264                // operator (45 min, 113 min) with no way to tell "slow route" from
15265                // "stuck". Progress prints on the non-spec ladder's cadence (every 8
15266                // chunks, plus the last) so a rung in flight is always observable.
15267                let mut chunks = 0usize;
15268                while b < n {
15269                    let mut t = chunk.min(n - b);
15270                    // Never leave a <= k_cap remainder as its own final piece.
15271                    if n - (b + t) > 0 && n - (b + t) <= k + 1 {
15272                        t = n - b;
15273                    }
15274                    let is_last = b + t == n;
15275                    let head = if is_last {
15276                        HeadMode::LastRow
15277                    } else {
15278                        HeadMode::Skip
15279                    };
15280                    let piece = self.forward_with(e, &prompt[b..b + t], state, None, head)?;
15281                    let t_draft = Instant::now();
15282                    if dev1 {
15283                        let v = state.verify.as_mut().expect("armed above");
15284                        let VerifyStash {
15285                            wide, wide_dev1, ..
15286                        } = v;
15287                        let mirror = wide_dev1.as_mut().expect("allocated above");
15288                        for (slot, len) in ring_pieces(ring, b, t) {
15289                            report.cross_ms +=
15290                                cross_wide_rows(e, de, wide, mirror, slot, len, wide_w)?;
15291                        }
15292                        report.cross_bytes += (t * wide_w * 4) as u64;
15293                    }
15294                    // Draft rows for positions [max(b,1), b+t): token p seeds wide[p-1]
15295                    // (the previous chunk's last row stays live: ring >= 2 chunks).
15296                    let p0 = b.max(1);
15297                    if b + t > p0 {
15298                        let v = state.verify.as_ref().expect("armed above");
15299                        let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
15300                        let (ld, cd, _) = self.draft_consume_ring(
15301                            de,
15302                            &prompt[p0..b + t],
15303                            dev_embed,
15304                            seed,
15305                            ring,
15306                            p0 - 1,
15307                            dstate,
15308                        )?;
15309                        self.mtp_recycle(dstate, ld, cd);
15310                    }
15311                    draft_prefill_ms += t_draft.elapsed().as_secs_f64() * 1e3;
15312                    b += t;
15313                    chunks += 1;
15314                    if chunks % 8 == 0 || is_last {
15315                        println!(
15316                            "# spec-prefill-progress\tfill={b}/{n}\tchunks={chunks}\t\
15317                             elapsed_s={:.1}\tdraft_s={:.1}",
15318                            t_prefill.elapsed().as_secs_f64(),
15319                            draft_prefill_ms / 1e3,
15320                        );
15321                    }
15322                    if is_last {
15323                        last = piece;
15324                    }
15325                }
15326                dstate.committed = n - 1;
15327                // Prefill is over and nothing wider than k + 1 rows runs again in this
15328                // generation: hand the t = 2,048 workspace back before the decode phase
15329                // asks for its own buffers (see `StepPool::shed`). Graphs bake slot
15330                // addresses, so they are invalidated here for the same reason a growing
15331                // multi-token chunk invalidates them — at this point they are already
15332                // default, because every t > 1 chunk reset them.
15333                let shed_bytes = state.ws.shed();
15334                state.graphs = StepGraphs::default();
15335                println!(
15336                    "# spec-prefill-shed\tworkspace_mib={:.1}\tchunks={chunks}",
15337                    shed_bytes as f64 / (1024.0 * 1024.0),
15338                );
15339                debug_assert_eq!(last.len(), vocab);
15340                match sampler.as_ref() {
15341                    None => host_argmax(&last) as u32,
15342                    Some(cfg) => sample_row(cfg, &mut rng, &last),
15343                }
15344            }
15345            // ---- Historical one-shot prefill (byte-stable receipts).
15346            _ => {
15347                let prefill = self.forward(e, prompt, state, None)?;
15348                // Shape-agnostic last-row read: the deferred seam's prefill dtoh is ONE
15349                // row (last_row_only), the control arm's is the full block; both end at
15350                // the row x0 reads. (A prompt shorter than k+2 runs the prefill as an
15351                // exact chunk and returns full rows on both arms.)
15352                let last = &prefill[prefill.len() - vocab..];
15353                let x0 = match sampler.as_ref() {
15354                    None => host_argmax(last) as u32,
15355                    Some(cfg) => sample_row(cfg, &mut rng, last),
15356                };
15357                let t_draft0 = Instant::now();
15358                if dev1 {
15359                    let v = state.verify.as_mut().expect("armed above");
15360                    let VerifyStash {
15361                        wide, wide_dev1, ..
15362                    } = v;
15363                    let mirror = wide_dev1.as_mut().expect("allocated above");
15364                    for (slot, len) in ring_pieces(ring, 0, n) {
15365                        report.cross_ms += cross_wide_rows(e, de, wide, mirror, slot, len, wide_w)?;
15366                    }
15367                    report.cross_bytes += (n * wide_w * 4) as u64;
15368                }
15369                {
15370                    let v = state.verify.as_ref().expect("armed above");
15371                    let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
15372                    if n >= 2 {
15373                        let (ld, cd, _) = self.draft_consume_ring(
15374                            de,
15375                            &prompt[1..],
15376                            dev_embed,
15377                            seed,
15378                            ring,
15379                            0,
15380                            dstate,
15381                        )?;
15382                        self.mtp_recycle(dstate, ld, cd);
15383                    }
15384                    dstate.committed = n - 1;
15385                }
15386                draft_prefill_ms += t_draft0.elapsed().as_secs_f64() * 1e3;
15387                x0
15388            }
15389        };
15390        report.prefill_ms = t_prefill.elapsed().as_secs_f64() * 1e3 - draft_prefill_ms;
15391        // Trace mode keeps the full verify-logits dtoh (want_argmax off) so fork
15392        // margins can be read; targets then come from the bit-identical host argmax.
15393        self.set_verify_want_argmax(state, greedy && !tracing)?;
15394        // x0 is the first generated token (parity with the plain chain's first argmax).
15395        report.tokens.push(x0);
15396
15397        // Bootstrap tip row: (x0 at position n, hidden wide[n-1]).
15398        let t_boot = Instant::now();
15399        let (mut tip_logits, mut tip_carrier) = {
15400            let v = state.verify.as_ref().expect("armed above");
15401            let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
15402            self.mtp_draft_forward_spec(de, &[x0], dev_embed, seed, (n - 1) % ring, dstate)?
15403        };
15404        let mut tip_rows = 1usize;
15405        dstate.committed = dstate.rows;
15406        report.draft_prefill_ms = draft_prefill_ms + t_boot.elapsed().as_secs_f64() * 1e3;
15407        report.draft_ms += report.draft_prefill_ms;
15408        // Prefills are done: a rounds-only profile starts HERE (see prof::split_prefill).
15409        prof::split_prefill();
15410
15411        let mut m = n; // trunk committed rows; tip sits at position m
15412        let mut tip = x0;
15413        // Admission state: k_cur = the dyn-K ceiling (decay-only), k_next = the
15414        // adaptive per-round window (accepted+1 recipe), window = the dyn-K ring.
15415        let mut k_cur = k;
15416        let mut k_next = k;
15417        let mut window: Vec<usize> = Vec::new();
15418        let mut round_idx = 0usize;
15419        while report.tokens.len() < max_new {
15420            if k_cur == 0 {
15421                // Dyn-K floored at 0: spec OFF for the remainder. Plain decode steps
15422                // (host argmax = the plain program — byte identity by construction);
15423                // the draft never runs again, which is exactly the saved cost.
15424                let row = self.forward(e, &[tip], state, None)?;
15425                let next: u32 = match sampler.as_ref() {
15426                    // Deferred seam: the plain step's token is the device argmax
15427                    // (bit-identical, argmax-gate contract); `row` is empty here.
15428                    None if deferred => self.verify_argmax_rows(state)?[0],
15429                    None => host_argmax(&row) as u32,
15430                    Some(cfg) => sample_row(cfg, &mut rng, &row),
15431                };
15432                report.tokens.push(next);
15433                report.plain_steps += 1;
15434                report
15435                    .round_wall
15436                    .push((report.tokens.len(), t_total.elapsed().as_secs_f64() * 1e3));
15437                m += 1;
15438                tip = next;
15439                continue;
15440            }
15441            let k_round = k_next.min(k_cur).max(1);
15442            // ---- draft chain: d1 from the tip row; steps 2..k_round carrier-chained.
15443            // The p-min guard stops the chain at the first sub-threshold pick (token
15444            // discarded uncounted); at j == 0 that makes a ZERO-draft round whose
15445            // verify is a plain t == 1 step.
15446            let t_draft = Instant::now();
15447            let mut drafts: Vec<u32> = Vec::with_capacity(k_round);
15448            let mut chain_rows_h: Vec<Vec<f32>> = Vec::new(); // trace: draft logit rows
15449            let mut seeds_h: Vec<Vec<f32>> = Vec::new(); // trace: carrier seeds used
15450            if let (Some(toks), Some(probs)) = (chain_toks_d.as_mut(), chain_probs_d.as_mut()) {
15451                // ---- DEFERRED chain (mtp11): picks and confidences stay in device
15452                // slots; the next step's embed gathers from the chain table, so host
15453                // dispatch of step j+1 overlaps device execution of step j and the
15454                // round drains ONCE (below) instead of blocking 2 dtoh per step.
15455                let width = self.draft_logits_width();
15456                de.argmax_token_device_col(&tip_logits, 0, width, toks, 0)?;
15457                if guard {
15458                    de.prob_of_token_device_col(&tip_logits, toks, 0, probs, 0, width)?;
15459                }
15460                let mut prev_logits = tip_logits;
15461                let mut prev_carrier = tip_carrier;
15462                let mut prev_rows = tip_rows;
15463                // Device slots holding a pick so far (guard_sync: a CHECKED pick).
15464                let mut drafted = 1usize;
15465                let mut stopped = false;
15466                if guard && opts.defer_guard_sync {
15467                    // Sequential-guard sub-arm: one 4-byte prob dtoh per step, the
15468                    // chain stops exactly where the host arm would (the discarded
15469                    // sub-threshold pick stays in its slot, uncounted).
15470                    let p = de.gpu.stream().clone_dtoh(&probs.slice(0..1))?[0];
15471                    if p < opts.pmin {
15472                        drafted = 0;
15473                        stopped = true;
15474                        report.guard_stops += 1;
15475                    }
15476                }
15477                while !stopped && drafted < k_round {
15478                    let (l2, c2) = self.mtp_draft_forward_devslot(
15479                        de,
15480                        toks,
15481                        drafted - 1,
15482                        &prev_carrier,
15483                        prev_rows - 1,
15484                        dstate,
15485                    )?;
15486                    self.mtp_recycle(dstate, prev_logits, prev_carrier);
15487                    prev_logits = l2;
15488                    prev_carrier = c2;
15489                    prev_rows = 1;
15490                    de.argmax_token_device_col(&prev_logits, 0, width, toks, drafted)?;
15491                    if guard {
15492                        de.prob_of_token_device_col(
15493                            &prev_logits,
15494                            toks,
15495                            drafted,
15496                            probs,
15497                            drafted,
15498                            width,
15499                        )?;
15500                        if opts.defer_guard_sync {
15501                            let p = de
15502                                .gpu
15503                                .stream()
15504                                .clone_dtoh(&probs.slice(drafted..drafted + 1))?[0];
15505                            if p < opts.pmin {
15506                                report.guard_stops += 1;
15507                                break;
15508                            }
15509                        }
15510                    }
15511                    drafted += 1;
15512                }
15513                self.mtp_recycle(dstate, prev_logits, prev_carrier);
15514                // ---- the round's ONE chain drain: the picks (and the deferred
15515                // guard's confidences) cross together; raw indices map to target ids
15516                // through draft_token, and the deferred guard truncates at the FIRST
15517                // sub-threshold step — the same discard the sequential arm makes.
15518                if drafted > 0 {
15519                    let raw = de.gpu.stream().clone_dtoh(&toks.slice(0..drafted))?;
15520                    let trunc = if guard && !opts.defer_guard_sync {
15521                        let pw = de.gpu.stream().clone_dtoh(&probs.slice(0..drafted))?;
15522                        let trunc = spec_guard_trunc(&pw, opts.pmin);
15523                        if trunc < drafted {
15524                            report.guard_stops += 1;
15525                        }
15526                        trunc
15527                    } else {
15528                        drafted
15529                    };
15530                    for &r in raw.iter().take(trunc) {
15531                        drafts.push(self.draft_token(r)?);
15532                    }
15533                }
15534            } else {
15535                let (d1, c1) = self.draft_row_argmax(de, &tip_logits, 0, guard)?;
15536                if !(guard && c1 < opts.pmin) {
15537                    drafts.push(d1);
15538                    if tracing {
15539                        chain_rows_h
15540                            .push(de.dtoh_view(&tip_logits.slice(0..self.draft_logits_width()))?);
15541                    }
15542                } else {
15543                    report.guard_stops += 1;
15544                }
15545                let mut prev_logits = tip_logits;
15546                let mut prev_carrier = tip_carrier;
15547                let mut prev_rows = tip_rows;
15548                while !drafts.is_empty() && drafts.len() < k_round {
15549                    if tracing {
15550                        seeds_h.push(de.dtoh_view(
15551                            &prev_carrier.slice((prev_rows - 1) * wide_w..prev_rows * wide_w),
15552                        )?);
15553                    }
15554                    let lastd = *drafts.last().expect("non-empty");
15555                    let (l2, c2) = self.mtp_draft_forward(
15556                        de,
15557                        &[lastd],
15558                        &prev_carrier,
15559                        prev_rows - 1,
15560                        dstate,
15561                        1,
15562                        false,
15563                    )?;
15564                    self.mtp_recycle(dstate, prev_logits, prev_carrier);
15565                    prev_logits = l2;
15566                    prev_carrier = c2;
15567                    prev_rows = 1;
15568                    let (dn, cn) = self.draft_row_argmax(de, &prev_logits, 0, guard)?;
15569                    if guard && cn < opts.pmin {
15570                        report.guard_stops += 1;
15571                        break;
15572                    }
15573                    drafts.push(dn);
15574                    if tracing {
15575                        chain_rows_h
15576                            .push(de.dtoh_view(&prev_logits.slice(0..self.draft_logits_width()))?);
15577                    }
15578                }
15579                self.mtp_recycle(dstate, prev_logits, prev_carrier);
15580            }
15581            let chain_ms = t_draft.elapsed().as_secs_f64() * 1e3;
15582            report.chain_ms += chain_ms;
15583            report.draft_ms += chain_ms;
15584
15585            // ---- verify chunk [tip, d1..] at base m (t == 1 on a zero-draft round —
15586            // a plain decode step that still commits one token).
15587            let t_ver = Instant::now();
15588            let mut chunk = Vec::with_capacity(drafts.len() + 1);
15589            chunk.push(tip);
15590            chunk.extend_from_slice(&drafts);
15591            let tlen = chunk.len();
15592            let host_logits = self.forward(e, &chunk, state, None)?;
15593            // Deferred seam: the t == 1 zero-draft verify also commits through the
15594            // device argmax (want_argmax_t1) — no [1, vocab] row + host scan.
15595            let targets: Vec<u32> = if greedy && !tracing && (tlen > 1 || deferred) {
15596                self.verify_argmax_rows(state)?.to_vec()
15597            } else if greedy {
15598                (0..tlen)
15599                    .map(|row| host_argmax(&host_logits[row * vocab..(row + 1) * vocab]) as u32)
15600                    .collect()
15601            } else {
15602                let cfg = sampler.as_ref().expect("sampled mode");
15603                (0..tlen)
15604                    .map(|row| {
15605                        sample_row(cfg, &mut rng, &host_logits[row * vocab..(row + 1) * vocab])
15606                    })
15607                    .collect()
15608            };
15609            report.verify_ms += t_ver.elapsed().as_secs_f64() * 1e3;
15610            if targets.len() != tlen {
15611                return Err("qwen4exp_gpu: verify produced the wrong row count".into());
15612            }
15613
15614            // ---- greedy accept walk (exact match to the target row).
15615            let mut a = 0usize;
15616            while a < drafts.len() && drafts[a] == targets[a] {
15617                a += 1;
15618            }
15619            report.rounds += 1;
15620            report.drafted += drafts.len() as u64;
15621            report.accepted += a as u64;
15622            report.accept_hist[a] += 1;
15623            if drafts.is_empty() {
15624                report.zero_draft_rounds += 1;
15625            }
15626            report.tokens.extend_from_slice(&targets[0..=a]);
15627
15628            // ---- trace record (fork margins from the stashed rows; carrier drift vs
15629            // the verify chunk's TRUE wide rows).
15630            if let Some(tr) = trace.as_deref_mut() {
15631                let mut rec = SpecTraceRound {
15632                    round: round_idx,
15633                    gen_pos: report.tokens.len() - (a + 1),
15634                    base: m,
15635                    k: drafts.len(),
15636                    a,
15637                    drafts: drafts.clone(),
15638                    targets: targets.clone(),
15639                    draft_top1: f32::NAN,
15640                    draft_top2: f32::NAN,
15641                    draft_tgt_logit: f32::NAN,
15642                    draft_tgt_rank: 0,
15643                    target_top1: f32::NAN,
15644                    target_top2: f32::NAN,
15645                    target_draft_logit: f32::NAN,
15646                    target_entropy: 0.0,
15647                    carrier_rel_l2: Vec::new(),
15648                    carrier_cos: Vec::new(),
15649                };
15650                if a < drafts.len() {
15651                    let drow = &chain_rows_h[a];
15652                    let trow = &host_logits[a * vocab..(a + 1) * vocab];
15653                    let tgt = targets[a] as usize;
15654                    let dtok = drafts[a] as usize;
15655                    let (mut d1v, mut d2v) = (f32::NEG_INFINITY, f32::NEG_INFINITY);
15656                    let mut rank = 0usize;
15657                    let dt = drow[tgt];
15658                    for &v in drow.iter() {
15659                        if v > d1v {
15660                            d2v = d1v;
15661                            d1v = v;
15662                        } else if v > d2v {
15663                            d2v = v;
15664                        }
15665                        if v > dt {
15666                            rank += 1;
15667                        }
15668                    }
15669                    let (mut t1v, mut t2v) = (f32::NEG_INFINITY, f32::NEG_INFINITY);
15670                    for &v in trow.iter() {
15671                        if v > t1v {
15672                            t2v = t1v;
15673                            t1v = v;
15674                        } else if v > t2v {
15675                            t2v = v;
15676                        }
15677                    }
15678                    // Softmax entropy of the target row (nats), f64 accumulation.
15679                    let mx = t1v as f64;
15680                    let mut z = 0.0f64;
15681                    let mut sxl = 0.0f64;
15682                    for &v in trow.iter() {
15683                        let ev = ((v as f64) - mx).exp();
15684                        z += ev;
15685                        sxl += ev * ((v as f64) - mx);
15686                    }
15687                    rec.draft_top1 = d1v;
15688                    rec.draft_top2 = d2v;
15689                    rec.draft_tgt_logit = dt;
15690                    rec.draft_tgt_rank = rank;
15691                    rec.target_top1 = t1v;
15692                    rec.target_top2 = t2v;
15693                    rec.target_draft_logit = trow[dtok];
15694                    rec.target_entropy = z.ln() - sxl / z;
15695                }
15696                let v = state.verify.as_ref().expect("armed above");
15697                for (j, seed) in seeds_h.iter().enumerate() {
15698                    let slot = (m + j) % ring;
15699                    let truth = e.dtoh_view(&v.wide.slice(slot * wide_w..(slot + 1) * wide_w))?;
15700                    let mut dd = 0.0f64;
15701                    let mut tt = 0.0f64;
15702                    let mut st = 0.0f64;
15703                    let mut ss = 0.0f64;
15704                    for (&s, &t) in seed.iter().zip(truth.iter()) {
15705                        let (s, t) = (s as f64, t as f64);
15706                        dd += (s - t) * (s - t);
15707                        tt += t * t;
15708                        st += s * t;
15709                        ss += s * s;
15710                    }
15711                    rec.carrier_rel_l2
15712                        .push((dd.sqrt() / tt.sqrt().max(1e-30)) as f32);
15713                    rec.carrier_cos
15714                        .push((st / (ss.sqrt() * tt.sqrt()).max(1e-30)) as f32);
15715                }
15716                tr.push(rec);
15717            }
15718
15719            // ---- rewind trunk to the accepted rows; draft catch-up replay.
15720            if tlen > 1 {
15721                self.verify_rewind(e, state, a + 1)?;
15722            }
15723            self.mtp_rewind(dstate, m)?;
15724            let t_draft2 = Instant::now();
15725            let x_next = targets[a];
15726            let mut replay: Vec<u32> = drafts[0..a].to_vec();
15727            replay.push(x_next);
15728            if dev1 {
15729                let v = state.verify.as_mut().expect("armed above");
15730                let VerifyStash {
15731                    wide, wide_dev1, ..
15732                } = v;
15733                let mirror = wide_dev1.as_mut().expect("allocated above");
15734                for (slot, len) in ring_pieces(ring, m, replay.len()) {
15735                    report.cross_ms += cross_wide_rows(e, de, wide, mirror, slot, len, wide_w)?;
15736                }
15737                report.cross_bytes += (replay.len() * wide_w * 4) as u64;
15738            }
15739            let (l, c, last_len) = {
15740                let v = state.verify.as_ref().expect("armed above");
15741                let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
15742                self.draft_consume_ring(de, &replay, dev_embed, seed, ring, m, dstate)?
15743            };
15744            tip_logits = l;
15745            tip_carrier = c;
15746            tip_rows = last_len;
15747            dstate.committed = dstate.rows;
15748            let replay_ms = t_draft2.elapsed().as_secs_f64() * 1e3;
15749            report.replay_ms += replay_ms;
15750            report.draft_ms += replay_ms;
15751            m += a + 1;
15752            tip = x_next;
15753            report
15754                .round_wall
15755                .push((report.tokens.len(), t_total.elapsed().as_secs_f64() * 1e3));
15756
15757            // ---- bounded admission updates (both decay-only within the round budget).
15758            if let Some(lo) = opts.adapt_k_lo {
15759                k_next = (a + 1).clamp(lo.max(1), k);
15760            }
15761            if let Some(cfg) = opts.dynk {
15762                window.push(a);
15763                if window.len() >= cfg.window.max(1) {
15764                    let mean = window.iter().sum::<usize>() as f64 / window.len() as f64;
15765                    if mean < cfg.thr {
15766                        let new_k = k_cur.saturating_sub(1).max(cfg.k_floor);
15767                        if new_k < k_cur {
15768                            k_cur = new_k;
15769                            report.k_decays.push((round_idx, k_cur));
15770                            if k_cur == 0 {
15771                                report.spec_off_at = Some(report.tokens.len());
15772                            }
15773                        }
15774                    }
15775                    window.clear();
15776                }
15777            }
15778            round_idx += 1;
15779        }
15780        report.tokens.truncate(max_new);
15781        report.total_ms = t_total.elapsed().as_secs_f64() * 1e3;
15782        Ok(report)
15783    }
15784}
15785
15786// ---------------------------------------------------------------- checkpoint loading
15787//
15788// The pack/plan/contract walk over an HF safetensors dir. The loader PROBES the artifact
15789// for its routed-expert dialect (ExpertDialect: the BF16 export's fused 3D banks, or the
15790// NVFP4 mint's per-expert modelopt projections — census receipt
15791// research/qwen4exp-bringup-20260829/raw/nvfp4-census-names.tsv) and binds through the
15792// pack's dialect contract. Trunk + globals materialize into reference-layout weights; the
15793// n-gram table stays host-resident (sharded or the mint's single tensor); expert banks
15794// admit BF16 (dequantized) or modelopt NVFP4 (as-stored device residency). `input_scale`
15795// (modelopt static activation scale) is contract-declared as an auxiliary, VALIDATED here
15796// (F32 scalar) and deliberately UNUSED: the eager arm is W4A16-class (weights dequantize
15797// to f32, activations stay f32), so the scale has no consumer until the W4A4 kernel lane
15798// quantizes activations — the dsv4 precedent ("W4A8 activation scale, unused for decode").
15799// MTP and vision tensors are validated owners but not materialized — the eager arm
15800// executes neither (module header).
15801
15802/// One expert bank tensor (one PROJECTION: gate, up, or down), assembled across experts.
15803enum BankTensorSrc {
15804    /// Dequantized f32, logical [n_expert, out_f, in_f].
15805    F32(Vec<f32>),
15806    /// modelopt NVFP4: e2m1 codes [E, out, in/2], e4m3 scales [E, out, in/16],
15807    /// per-expert finite macro scales (the real mint's are amax-derived non-pow2), and
15808    /// the projection's STATIC ACTIVATION scale — the max of the per-expert
15809    /// `input_scale` siblings. RECORDED-ONLY by owner order (2026-08-30): activation
15810    /// quantization is retired as a serving lever (it measurably moved decode argmax —
15811    /// perf22 seam-gate receipt, PROFILE-4 §W4A4); no compute path consumes this value,
15812    /// and no future lane re-proposes consuming it without a fresh owner ruling.
15813    Nvfp4 {
15814        codes: Vec<u8>,
15815        scales: Vec<u8>,
15816        macros: Vec<f32>,
15817        act_scale: Option<f32>,
15818    },
15819    /// Raw bf16 bytes at the logical shape [n_expert, out_f, in_f] — kept when
15820    /// `LoadOptions::host_bf16_banks` asks for the host-resident gate residency.
15821    Bf16(Vec<u8>),
15822}
15823
15824struct BankSrc {
15825    gate: BankTensorSrc, // logical [E, ff, H]
15826    up: BankTensorSrc,   // logical [E, ff, H]
15827    down: BankTensorSrc, // logical [E, H, ff]
15828    n_expert: usize,
15829    ff: usize,
15830    hidden: usize,
15831}
15832
15833/// One fused bank tensor's read address: the artifact name plus the contract shape the
15834/// walk already validated it against ([E, out_f, in_f], logical).
15835struct FusedTensorPlan {
15836    name: String,
15837    shape: [usize; 3],
15838}
15839
15840/// One PER-EXPERT projection's read addresses, in EXPERT ORDER 0..E. The walk builds this
15841/// from a numerically-keyed map and checks contiguity there, so this vector's index IS the
15842/// expert id — the lexicographic-arrival trap (`experts.10` before `experts.2`) is already
15843/// absorbed before anything is read.
15844struct PerExpertPlan {
15845    names: Vec<String>, // expert order 0..E
15846    out_f: usize,
15847    in_f: usize,
15848    quant: memra_gguf::tensor_contract::QuantConstraint,
15849}
15850
15851enum BankPlanSrc {
15852    /// FusedBanks dialect: the fused [E, 2ff, H] gate_up tensor + the [E, H, ff] down.
15853    Fused {
15854        gate_up: FusedTensorPlan,
15855        down: FusedTensorPlan,
15856        /// Residency decided at WALK time, exactly as before
15857        /// (`LoadOptions::host_bf16_banks`, or an MTP bank at index >= n_trunk): a bf16
15858        /// bank keeps raw bytes instead of dequantizing to f32. Fused-only — the
15859        /// per-expert modelopt rows are F32 or NVFP4 by geometry, never a bf16 arm.
15860        keep_bf16: bool,
15861    },
15862    /// PerExpertModelopt dialect: one name list per projection.
15863    PerExpert {
15864        gate: PerExpertPlan,
15865        up: PerExpertPlan,
15866        down: PerExpertPlan,
15867    },
15868}
15869
15870/// WHERE one layer's expert bank lives in the artifact and HOW to bind it — everything
15871/// `BankSrc` needs except the bytes.
15872///
15873/// This is the streaming seam. The walk validates names/shapes/dtypes/geometry/expert
15874/// contiguity and records this plan; the bytes are read one LAYER at a time inside the
15875/// consuming loop (`from_loaded_checkpoint_dual`, `build_tp2_shard`,
15876/// `into_reference_weights`) straight off the safetensors mmap, uploaded, and dropped.
15877/// Pre-materializing all 48 layers cost the whole artifact in host anon memory at once
15878/// (~72 GB of banks on top of the 102 GB n-gram table and ~20 GB of trunk f32), which
15879/// OOM-killed the real gate at 179.7 GB anon-RSS on a 180 GB-RAM box — the cheapest
15880/// 2-card class. Nothing about the BYTES changes: the same
15881/// `read_bank_tensor`/`read_per_expert`/`assemble_per_expert_bank`/`split_fused_gate_up`
15882/// chain runs on the same file offsets in the same expert order, just later.
15883struct BankPlan {
15884    n_expert: usize,
15885    ff: usize,
15886    hidden: usize,
15887    src: BankPlanSrc,
15888}
15889
15890impl BankPlan {
15891    /// Read + assemble THIS layer's bank off the mmap. Peak host cost is one layer's bank
15892    /// (~1.5 GB on the real mint), not the artifact.
15893    fn read(&self, model: &memra_gguf::safetensors::StModel) -> Res<BankSrc> {
15894        let (gate, up, down) = match &self.src {
15895            BankPlanSrc::Fused {
15896                gate_up,
15897                down,
15898                keep_bf16,
15899            } => {
15900                let fused = read_bank_tensor(
15901                    model,
15902                    &gate_up.name,
15903                    gate_up.shape[0],
15904                    gate_up.shape[1],
15905                    gate_up.shape[2],
15906                    *keep_bf16,
15907                )?;
15908                let (gate, up) = split_fused_gate_up(fused, self.n_expert, self.ff, self.hidden)?;
15909                let down = read_bank_tensor(
15910                    model,
15911                    &down.name,
15912                    down.shape[0],
15913                    down.shape[1],
15914                    down.shape[2],
15915                    *keep_bf16,
15916                )?;
15917                (gate, up, down)
15918            }
15919            BankPlanSrc::PerExpert { gate, up, down } => (
15920                read_per_expert_bank(model, gate)?,
15921                read_per_expert_bank(model, up)?,
15922                read_per_expert_bank(model, down)?,
15923            ),
15924        };
15925        Ok(BankSrc {
15926            gate,
15927            up,
15928            down,
15929            n_expert: self.n_expert,
15930            ff: self.ff,
15931            hidden: self.hidden,
15932        })
15933    }
15934}
15935
15936/// WALK-time refusal for a bank tensor whose PAYLOAD is read later: the name must exist in
15937/// the census and carry a dtype the bank readers admit.
15938///
15939/// `StModel::info` is header-only, so this faults no weight page and costs no host memory.
15940/// It keeps the contract walk's "every declared name exists" property — a mint missing a
15941/// projection is refused before the 102 GB table is allocated and before one byte reaches
15942/// the device. Shape, scale siblings, macro finiteness and `input_scale` validity are
15943/// checked by `read_bank_tensor`/`read_per_expert` when the layer is read, which is still
15944/// load time (before any forward), just per layer instead of all at once.
15945fn check_bank_header(model: &memra_gguf::safetensors::StModel, name: &str) -> Res<()> {
15946    let info = model
15947        .info(name)
15948        .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
15949    match info.dtype.as_str() {
15950        "BF16" | "F32" | "U8" => Ok(()),
15951        other => Err(format!("qwen4exp_gpu: {name} bank dtype {other} unsupported").into()),
15952    }
15953}
15954
15955/// Read one per-expert projection in expert order and stack it — the deferred half of the
15956/// old walk's `read_per_expert` + `assemble_per_expert_bank` pair, byte-for-byte.
15957fn read_per_expert_bank(
15958    model: &memra_gguf::safetensors::StModel,
15959    plan: &PerExpertPlan,
15960) -> Res<BankTensorSrc> {
15961    let mut experts = Vec::with_capacity(plan.names.len());
15962    for name in &plan.names {
15963        experts.push(read_per_expert(
15964            model, name, plan.out_f, plan.in_f, plan.quant,
15965        )?);
15966    }
15967    assemble_per_expert_bank(experts)
15968}
15969
15970/// A checkpoint materialized through the pack contract: reference-layout weights for the
15971/// trunk + globals (effective norms — the (1+w) fold applied per the module-header rule),
15972/// plus the table carrier that stays out of `ReferenceWeights` and the LAZY bank plans.
15973///
15974/// The open safetensors mmap is part of the value: expert banks are read from it per layer
15975/// at consume time (see `BankPlan`). It stays mapped until the checkpoint is dropped, so a
15976/// consumer must not outlive it — every consumer here is a constructor that finishes
15977/// uploading before returning.
15978pub struct LoadedCheckpoint {
15979    pub plan: ModelPlan,
15980    pub weights: ReferenceWeights,
15981    model: memra_gguf::safetensors::StModel,
15982    bank_plans: std::collections::BTreeMap<u32, BankPlan>,
15983    tables: std::collections::BTreeMap<u32, Vec<u8>>, // bf16 bytes, [rows, head_dim]
15984}
15985
15986/// (1+w) fold rule for checkpoint norm rows — the qwen35 receipt (hf_mapping.rs,
15987/// qwen.py:302-303): every `*norm*.weight` EXCEPT `linear_attn.norm` (RMSNormGated binds
15988/// raw weights; SEMANTICS.md §GDN keeps the qwen3_5 GDN program). VERIFY vs the goldens
15989/// lane for the indexer layernorms (assumed the family (1+w) class — the zero-init
15990/// receipt, modular L860).
15991fn norm_fold_add_one(name: &str) -> bool {
15992    name.contains("norm") && name.ends_with(".weight") && !name.ends_with("linear_attn.norm.weight")
15993}
15994
15995/// The QSA indexer's q/k layernorm rows — the SEMANTICS.md VERIFY subject. The default
15996/// fold treats them as family (1+w); `LoadOptions::indexer_norm_raw` binds them raw so
15997/// the real-checkpoint per-layer gate can measure both arms and settle the question.
15998fn indexer_layernorm(name: &str) -> bool {
15999    name.contains(".indexer.")
16000        && (name.ends_with("q_layernorm.weight") || name.ends_with("k_layernorm.weight"))
16001}
16002
16003/// Real-checkpoint loader knobs (defaults = the tiny-gate behavior).
16004#[derive(Default, Clone, Copy)]
16005pub struct LoadOptions {
16006    /// Keep BF16 expert banks HOST-resident (raw bf16) and upload+upcast per ROUTED
16007    /// expert at forward time. Gate-mode residency for artifacts whose f32 banks
16008    /// exceed device memory; value chain identical to the f32 device arm (bf16→f32
16009    /// is exact). Never a serving configuration.
16010    pub host_bf16_banks: bool,
16011    /// Bind the indexer q/k layernorms RAW (skip the (1+w) fold) — the two-arm probe
16012    /// for the SEMANTICS.md VERIFY marker. Default keeps the family fold.
16013    pub indexer_norm_raw: bool,
16014    /// Materialize the mtp.* namespace (the NextN draft block) — the mtp-spec lane.
16015    /// The MTP expert bank keeps its raw BF16 bytes at read time and goes DEVICE
16016    /// bf16-resident at build (`BankHalf::DeviceBf16`, ~5 GB beside the NVFP4 trunk).
16017    /// Default OFF: the plain eager arm executes no draft.
16018    pub load_mtp: bool,
16019}
16020
16021fn bridge_transform(
16022    transform: memra_gguf::tensor_contract::TensorTransform,
16023) -> Res<memra_gguf::hf_mapping::TransformKind> {
16024    use memra_gguf::hf_mapping::TransformKind as K;
16025    use memra_gguf::tensor_contract::TensorTransform as T;
16026    Ok(match transform {
16027        T::Identity => K::Identity,
16028        T::NormAddOne => K::NormPlusOne,
16029        T::QkvVReorderRows => K::QkvVReorderRows,
16030        T::ZReorderRows => K::ZReorderRows,
16031        T::AbReorderRows => K::AbReorderRows,
16032        T::NegExpReorderHeads => K::NegExpReorderHeads,
16033        T::ReorderHeads => K::ReorderHeads,
16034        T::Conv1dSqueezeReorder => K::Conv1dSqueezeReorder,
16035        T::OutReorderColumns => K::OutReorderCols,
16036        other => return Err(format!("qwen4exp_gpu: unsupported transform {other:?}").into()),
16037    })
16038}
16039
16040fn dequant_float(
16041    name: &str,
16042    info: &memra_gguf::safetensors::StInfo,
16043    bytes: &[u8],
16044) -> Res<Vec<f32>> {
16045    let elements: usize = info.shape.iter().map(|&d| d as usize).product();
16046    match info.dtype.as_str() {
16047        "BF16" | "F32" => Ok(memra_gguf::dequant::dequantize(
16048            info.ggml_type()
16049                .map_err(|error| format!("qwen4exp_gpu: {name}: {error}"))?,
16050            bytes,
16051            elements,
16052        )),
16053        other => Err(format!("qwen4exp_gpu: {name} has unsupported float dtype {other}").into()),
16054    }
16055}
16056
16057fn read_i64(name: &str, info: &memra_gguf::safetensors::StInfo, bytes: &[u8]) -> Res<Vec<i64>> {
16058    if info.dtype != "I64" {
16059        return Err(format!("qwen4exp_gpu: {name} must be I64, got {}", info.dtype).into());
16060    }
16061    Ok(bytes
16062        .chunks_exact(8)
16063        .map(|chunk| i64::from_le_bytes(chunk.try_into().unwrap()))
16064        .collect())
16065}
16066
16067/// Macro-scale validation. The dsv4 pow2 law does NOT apply here: this module's dequant
16068/// chain applies the macro post-upcast in f32 (`dequant_nvfp4_expert_f32`), which is
16069/// exact-then-single-rounding for ANY finite positive macro — and the real qwen4_exp
16070/// mint ships modelopt's amax-derived NON-pow2 `weight_scale_2` (first value refused by
16071/// the inherited pow2 assert on the fleet box, 2026-08-29: 5.9945243e-5 on
16072/// layers.0.mlp.experts.0.down_proj). Refusal is reserved for values that poison the
16073/// arithmetic outright.
16074fn validate_macro(stem: &str, value: f32) -> Res<()> {
16075    if !(value.is_finite() && value > 0.0) {
16076        return Err(format!(
16077            "qwen4exp_gpu: {stem}.weight_scale_2 carries a non-finite/non-positive \
16078             macro {value}"
16079        )
16080        .into());
16081    }
16082    Ok(())
16083}
16084
16085/// Read one STACKED expert bank (FusedBanks dialect): BF16 at the declared logical shape,
16086/// or the modelopt-NVFP4 stacked triplet whose validation mirrors
16087/// `find_nvfp4_stacked_native` (source.rs): U8 codes [E, out, in/2] + F8_E4M3
16088/// `weight_scale` [E, out, in/16] + optional F32 `weight_scale_2` [E] (absent -> 1.0).
16089fn read_bank_tensor(
16090    model: &memra_gguf::safetensors::StModel,
16091    name: &str,
16092    n_expert: usize,
16093    out_f: usize,
16094    in_f: usize,
16095    host_bf16: bool,
16096) -> Res<BankTensorSrc> {
16097    let (info, bytes) = model
16098        .raw(name)
16099        .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16100    match info.dtype.as_str() {
16101        "BF16" | "F32" => {
16102            if info.shape != [n_expert as u64, out_f as u64, in_f as u64] {
16103                return Err(format!("qwen4exp_gpu: {name} bank shape mismatch").into());
16104            }
16105            if host_bf16 && info.dtype == "BF16" {
16106                if bytes.len() != n_expert * out_f * in_f * 2 {
16107                    return Err(format!("qwen4exp_gpu: {name} bank byte-length mismatch").into());
16108                }
16109                return Ok(BankTensorSrc::Bf16(bytes.to_vec()));
16110            }
16111            Ok(BankTensorSrc::F32(dequant_float(name, info, bytes)?))
16112        }
16113        "U8" => {
16114            if in_f % 16 != 0
16115                || info.shape != [n_expert as u64, out_f as u64, (in_f / 2) as u64]
16116                || bytes.len() != n_expert * out_f * in_f / 2
16117            {
16118                return Err(format!("qwen4exp_gpu: {name} NVFP4 code shape mismatch").into());
16119            }
16120            let stem = name.strip_suffix(".weight").unwrap_or(name);
16121            let scale_name = format!("{stem}.weight_scale");
16122            let (scale_info, scale_bytes) = model
16123                .raw(&scale_name)
16124                .ok_or_else(|| format!("qwen4exp_gpu: missing {scale_name}"))?;
16125            if scale_info.dtype != "F8_E4M3"
16126                || scale_info.shape != [n_expert as u64, out_f as u64, (in_f / 16) as u64]
16127                || scale_bytes.len() != n_expert * out_f * in_f / 16
16128            {
16129                return Err(format!("qwen4exp_gpu: {scale_name} shape mismatch").into());
16130            }
16131            let macros = match model.raw(&format!("{stem}.weight_scale_2")) {
16132                Some((macro_info, macro_bytes))
16133                    if macro_info.dtype == "F32" && macro_bytes.len() == n_expert * 4 =>
16134                {
16135                    macro_bytes
16136                        .chunks_exact(4)
16137                        .map(|chunk| f32::from_le_bytes(chunk.try_into().unwrap()))
16138                        .collect()
16139                }
16140                None => vec![1.0; n_expert],
16141                _ => return Err(format!("qwen4exp_gpu: {stem}.weight_scale_2 malformed").into()),
16142            };
16143            for &m in &macros {
16144                validate_macro(stem, m)?;
16145            }
16146            // Optional stacked input_scale [E] (the per-expert mint carries scalars via
16147            // the PerExpertModelopt path; a stacked artifact may carry the vector) —
16148            // reduced to the per-layer max for the W4A4 activation quantization.
16149            let act_scale = match model.raw(&format!("{stem}.input_scale")) {
16150                Some((is_info, is_bytes))
16151                    if is_info.dtype == "F32" && is_bytes.len() == n_expert * 4 =>
16152                {
16153                    let mut mx = 0.0f32;
16154                    for chunk in is_bytes.chunks_exact(4) {
16155                        let v = f32::from_le_bytes(chunk.try_into().unwrap());
16156                        if !(v.is_finite() && v > 0.0) {
16157                            return Err(format!(
16158                                "qwen4exp_gpu: {stem}.input_scale carries a non-finite/\
16159                                 non-positive value {v}"
16160                            )
16161                            .into());
16162                        }
16163                        mx = mx.max(v);
16164                    }
16165                    Some(mx)
16166                }
16167                Some(_) => {
16168                    return Err(format!("qwen4exp_gpu: {stem}.input_scale malformed").into());
16169                }
16170                None => None,
16171            };
16172            Ok(BankTensorSrc::Nvfp4 {
16173                codes: bytes.to_vec(),
16174                scales: scale_bytes.to_vec(),
16175                macros,
16176                act_scale,
16177            })
16178        }
16179        other => Err(format!("qwen4exp_gpu: {name} bank dtype {other} unsupported").into()),
16180    }
16181}
16182
16183/// Split a FUSED gate_up source ([E, 2ff, H], gate rows first per expert) into per-
16184/// projection gate/up sources. F32 splits data rows; NVFP4 splits code/scale byte rows
16185/// (row-granular, byte-clean) and duplicates the per-expert macro to both halves.
16186fn split_fused_gate_up(
16187    fused: BankTensorSrc,
16188    n_expert: usize,
16189    ff: usize,
16190    hidden: usize,
16191) -> Res<(BankTensorSrc, BankTensorSrc)> {
16192    match fused {
16193        BankTensorSrc::F32(data) => {
16194            if data.len() != n_expert * 2 * ff * hidden {
16195                return Err("qwen4exp_gpu: fused gate_up bank size mismatch".into());
16196            }
16197            let mut gate = Vec::with_capacity(n_expert * ff * hidden);
16198            let mut up = Vec::with_capacity(n_expert * ff * hidden);
16199            for expert in 0..n_expert {
16200                let base = expert * 2 * ff * hidden;
16201                gate.extend_from_slice(&data[base..base + ff * hidden]);
16202                up.extend_from_slice(&data[base + ff * hidden..base + 2 * ff * hidden]);
16203            }
16204            Ok((BankTensorSrc::F32(gate), BankTensorSrc::F32(up)))
16205        }
16206        BankTensorSrc::Bf16(bytes) => {
16207            let row = hidden * 2; // bf16 bytes per fused row
16208            if bytes.len() != n_expert * 2 * ff * row {
16209                return Err("qwen4exp_gpu: fused bf16 gate_up bank size mismatch".into());
16210            }
16211            let mut gate = Vec::with_capacity(n_expert * ff * row);
16212            let mut up = Vec::with_capacity(n_expert * ff * row);
16213            for expert in 0..n_expert {
16214                let base = expert * 2 * ff * row;
16215                gate.extend_from_slice(&bytes[base..base + ff * row]);
16216                up.extend_from_slice(&bytes[base + ff * row..base + 2 * ff * row]);
16217            }
16218            Ok((BankTensorSrc::Bf16(gate), BankTensorSrc::Bf16(up)))
16219        }
16220        BankTensorSrc::Nvfp4 {
16221            codes,
16222            scales,
16223            macros,
16224            act_scale,
16225        } => {
16226            let code_row = hidden / 2;
16227            let scale_row = hidden / 16;
16228            let mut gate_codes = Vec::with_capacity(n_expert * ff * code_row);
16229            let mut up_codes = Vec::with_capacity(n_expert * ff * code_row);
16230            let mut gate_scales = Vec::with_capacity(n_expert * ff * scale_row);
16231            let mut up_scales = Vec::with_capacity(n_expert * ff * scale_row);
16232            for expert in 0..n_expert {
16233                let cbase = expert * 2 * ff * code_row;
16234                gate_codes.extend_from_slice(&codes[cbase..cbase + ff * code_row]);
16235                up_codes
16236                    .extend_from_slice(&codes[cbase + ff * code_row..cbase + 2 * ff * code_row]);
16237                let sbase = expert * 2 * ff * scale_row;
16238                gate_scales.extend_from_slice(&scales[sbase..sbase + ff * scale_row]);
16239                up_scales
16240                    .extend_from_slice(&scales[sbase + ff * scale_row..sbase + 2 * ff * scale_row]);
16241            }
16242            Ok((
16243                BankTensorSrc::Nvfp4 {
16244                    codes: gate_codes,
16245                    scales: gate_scales,
16246                    macros: macros.clone(),
16247                    act_scale,
16248                },
16249                BankTensorSrc::Nvfp4 {
16250                    codes: up_codes,
16251                    scales: up_scales,
16252                    macros,
16253                    act_scale,
16254                },
16255            ))
16256        }
16257    }
16258}
16259
16260/// One PER-EXPERT projection (PerExpertModelopt dialect): the modelopt sibling schema
16261/// (`nvfp4_quant`'s modelopt arm, source.rs — weight U8 [out, in/2] + weight_scale +
16262/// scalar weight_scale_2), or a plain BF16 row where geometry forbids per-16 groups.
16263/// `input_scale` is validated (F32 scalar) and dropped — see the section header.
16264enum PerExpertSrc {
16265    F32(Vec<f32>),
16266    Nvfp4 {
16267        codes: Vec<u8>,
16268        scales: Vec<u8>,
16269        macro_scale: f32,
16270        input_scale: Option<f32>,
16271    },
16272}
16273
16274fn read_per_expert(
16275    model: &memra_gguf::safetensors::StModel,
16276    name: &str,
16277    out_f: usize,
16278    in_f: usize,
16279    quant: memra_gguf::tensor_contract::QuantConstraint,
16280) -> Res<PerExpertSrc> {
16281    use memra_gguf::tensor_contract::QuantConstraint;
16282    let (info, bytes) = model
16283        .raw(name)
16284        .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16285    match quant {
16286        QuantConstraint::ExactFloat(_) => {
16287            if info.shape != [out_f as u64, in_f as u64] {
16288                return Err(format!("qwen4exp_gpu: {name} shape mismatch").into());
16289            }
16290            Ok(PerExpertSrc::F32(dequant_float(name, info, bytes)?))
16291        }
16292        QuantConstraint::Nvfp4 => {
16293            if info.dtype != "U8"
16294                || in_f % 16 != 0
16295                || info.shape != [out_f as u64, (in_f / 2) as u64]
16296                || bytes.len() != out_f * in_f / 2
16297            {
16298                return Err(format!("qwen4exp_gpu: {name} NVFP4 code shape mismatch").into());
16299            }
16300            let stem = name.strip_suffix(".weight").unwrap_or(name);
16301            let (scale_info, scale_bytes) = model
16302                .raw(&format!("{stem}.weight_scale"))
16303                .ok_or_else(|| format!("qwen4exp_gpu: missing {stem}.weight_scale"))?;
16304            if scale_info.dtype != "F8_E4M3"
16305                || scale_info.shape != [out_f as u64, (in_f / 16) as u64]
16306                || scale_bytes.len() != out_f * in_f / 16
16307            {
16308                return Err(format!("qwen4exp_gpu: {stem}.weight_scale shape mismatch").into());
16309            }
16310            let macro_scale = match model.raw(&format!("{stem}.weight_scale_2")) {
16311                Some((macro_info, macro_bytes))
16312                    if macro_info.dtype == "F32" && macro_bytes.len() == 4 =>
16313                {
16314                    f32::from_le_bytes(macro_bytes.try_into().unwrap())
16315                }
16316                None => 1.0,
16317                _ => return Err(format!("qwen4exp_gpu: {stem}.weight_scale_2 malformed").into()),
16318            };
16319            validate_macro(stem, macro_scale)?;
16320            // input_scale: modelopt's STATIC ACTIVATION scale (= calibrated amax /
16321            // (448*6)) — validated AND consumed since round 4: the W4A4 expert path
16322            // quantizes activations against the per-layer max of these (see
16323            // BankTensorSrc::Nvfp4::act_scale).
16324            let input_scale = match model.raw(&format!("{stem}.input_scale")) {
16325                Some((input_info, input_bytes)) => {
16326                    if input_info.dtype != "F32" || input_bytes.len() != 4 {
16327                        return Err(format!("qwen4exp_gpu: {stem}.input_scale malformed").into());
16328                    }
16329                    let v = f32::from_le_bytes(input_bytes.try_into().unwrap());
16330                    if !(v.is_finite() && v > 0.0) {
16331                        return Err(format!(
16332                            "qwen4exp_gpu: {stem}.input_scale carries a non-finite/non-positive \
16333                             value {v}"
16334                        )
16335                        .into());
16336                    }
16337                    Some(v)
16338                }
16339                None => None,
16340            };
16341            Ok(PerExpertSrc::Nvfp4 {
16342                codes: bytes.to_vec(),
16343                scales: scale_bytes.to_vec(),
16344                macro_scale,
16345                input_scale,
16346            })
16347        }
16348        other => Err(format!("qwen4exp_gpu: per-expert quant {other:?} unsupported").into()),
16349    }
16350}
16351
16352/// Concatenate per-expert sources (expert order 0..E) into one stacked BankTensorSrc.
16353/// Kinds must be uniform across a projection (the census derives them per geometry).
16354fn assemble_per_expert_bank(experts: Vec<PerExpertSrc>) -> Res<BankTensorSrc> {
16355    let mut f32_data: Vec<f32> = Vec::new();
16356    let mut codes: Vec<u8> = Vec::new();
16357    let mut scales: Vec<u8> = Vec::new();
16358    let mut macros: Vec<f32> = Vec::new();
16359    let mut act_scale: Option<f32> = None;
16360    let mut act_scale_complete = true;
16361    let mut kinds = (false, false);
16362    for expert in experts {
16363        match expert {
16364            PerExpertSrc::F32(data) => {
16365                kinds.0 = true;
16366                f32_data.extend_from_slice(&data);
16367            }
16368            PerExpertSrc::Nvfp4 {
16369                codes: c,
16370                scales: s,
16371                macro_scale,
16372                input_scale,
16373            } => {
16374                kinds.1 = true;
16375                codes.extend_from_slice(&c);
16376                scales.extend_from_slice(&s);
16377                macros.push(macro_scale);
16378                match input_scale {
16379                    Some(v) => act_scale = Some(act_scale.map_or(v, |a: f32| a.max(v))),
16380                    None => act_scale_complete = false,
16381                }
16382            }
16383        }
16384    }
16385    match kinds {
16386        (true, false) => Ok(BankTensorSrc::F32(f32_data)),
16387        (false, true) => Ok(BankTensorSrc::Nvfp4 {
16388            codes,
16389            scales,
16390            macros,
16391            act_scale: if act_scale_complete { act_scale } else { None },
16392        }),
16393        _ => Err("qwen4exp_gpu: mixed per-expert kinds within one projection".into()),
16394    }
16395}
16396
16397/// Trunk layer index of a family-keyed requirement (`trunk.layers.{il}. ...`).
16398fn family_layer_index(key: &str) -> Option<u32> {
16399    key.strip_prefix("trunk.layers.")?
16400        .split('.')
16401        .next()?
16402        .parse()
16403        .ok()
16404}
16405
16406/// Walk the pack contract over an HF safetensors dir and materialize the eager arm's
16407/// weight set. The expert dialect is PROBED from the artifact (per-expert names present
16408/// => the NVFP4 mint layout). Fails loudly on any missing name, shape/dtype mismatch, or
16409/// unsupported transform — nothing is skipped silently except the declared MTP/vision
16410/// owners.
16411/// Resolve a layer plan by GLOBAL index: trunk layers [0, n_trunk), then MTP blocks at
16412/// n_trunk + depth (the pack's mtp.layers.* mapping).
16413fn plan_layer_at(plan: &ModelPlan, index: u32) -> Option<&memra_gguf::model_plan::LayerPlan> {
16414    let n_trunk = plan.layers.len() as u32;
16415    if index < n_trunk {
16416        plan.layers.get(index as usize)
16417    } else {
16418        plan.mtp_blocks
16419            .iter()
16420            .find(|block| block.layer.index == index)
16421            .map(|block| &block.layer)
16422    }
16423}
16424
16425pub fn read_checkpoint(dir: &std::path::Path) -> Res<LoadedCheckpoint> {
16426    read_checkpoint_with(dir, LoadOptions::default())
16427}
16428
16429/// `read_checkpoint` with real-checkpoint loader knobs (`LoadOptions`).
16430pub fn read_checkpoint_with(dir: &std::path::Path, opts: LoadOptions) -> Res<LoadedCheckpoint> {
16431    use memra_gguf::model_packs::qwen4_exp::{ExpertDialect, tensor_contract_for};
16432    use memra_gguf::tensor_contract::{TensorMatch, TensorOwner};
16433    let config = std::fs::read_to_string(dir.join("config.json"))?;
16434    let cfg =
16435        memra_gguf::config::ModelConfig::from_hf(&memra_gguf::config::HfConfig::parse(&config));
16436    let pack = memra_gguf::model_packs::for_config(&cfg)
16437        .ok_or("qwen4exp_gpu: no model pack matches this config")?;
16438    if pack.family != "qwen4_exp" {
16439        return Err(format!("qwen4exp_gpu: config resolves to pack {}", pack.family).into());
16440    }
16441    let plan = pack.compile_plan(&cfg)?;
16442    let model = memra_gguf::safetensors::StModel::open(dir)?;
16443    // Dialect probe: layer 0 is always MoE; the mint un-fuses its experts.
16444    let dialect = if model
16445        .raw("model.language_model.layers.0.mlp.experts.0.gate_proj.weight")
16446        .is_some()
16447    {
16448        ExpertDialect::PerExpertModelopt
16449    } else {
16450        ExpertDialect::FusedBanks
16451    };
16452    let contract = tensor_contract_for(&cfg, &plan, dialect)?;
16453
16454    let mut weights = ReferenceWeights::new();
16455    let mut gate_up_banks: std::collections::BTreeMap<u32, FusedTensorPlan> = Default::default();
16456    // Keyed by numeric expert index: the contract iterates the census BTreeMap in
16457    // LEXICOGRAPHIC name order (experts.10 before experts.2), so per-expert rows arrive
16458    // out of numeric order on any E > 9 — assembly must not assume arrival order.
16459    let mut per_expert: std::collections::BTreeMap<
16460        (u32, u8),
16461        std::collections::BTreeMap<
16462            u32,
16463            (
16464                String,
16465                usize,
16466                usize,
16467                memra_gguf::tensor_contract::QuantConstraint,
16468            ),
16469        >,
16470    > = Default::default();
16471    let mut down_banks: std::collections::BTreeMap<u32, FusedTensorPlan> = Default::default();
16472    let mut tables: std::collections::BTreeMap<u32, Vec<u8>> = Default::default();
16473    let n_trunk = plan.layers.len() as u32;
16474
16475    for requirement in &contract.requirements {
16476        match requirement.owner {
16477            // The eager trunk executes neither; vision rows stay contract-declared for
16478            // the census/checkpoint-parity gates but are never materialized here. MTP
16479            // rows materialize when the mtp-spec lane asks (`LoadOptions::load_mtp`).
16480            TensorOwner::Mtp(_) if !opts.load_mtp => continue,
16481            TensorOwner::Vision(_) => continue,
16482            TensorOwner::Global | TensorOwner::Layer(_) | TensorOwner::Mtp(_) => {}
16483        }
16484        // The n-gram shard bank: one semantic tensor, `names` in shard order (pack sorts).
16485        if requirement.match_mode == TensorMatch::All {
16486            let TensorId::Family { key, .. } = &requirement.id else {
16487                return Err("qwen4exp_gpu: unexpected All-mode requirement".into());
16488            };
16489            let layer =
16490                family_layer_index(key).ok_or("qwen4exp_gpu: n-gram bank outside a trunk layer")?;
16491            let mut bytes = Vec::new();
16492            for name in &requirement.names {
16493                let (info, shard) = model
16494                    .raw(name)
16495                    .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16496                if info.dtype != "BF16" || info.shape != requirement.shape {
16497                    return Err(format!("qwen4exp_gpu: {name} shard shape/dtype mismatch").into());
16498                }
16499                bytes.extend_from_slice(shard);
16500            }
16501            tables.insert(layer, bytes);
16502            continue;
16503        }
16504        let name = &requirement.names[0];
16505        // The mint's UNSHARDED table: same Family bank id, one BF16 tensor — read raw
16506        // bytes (a host f32 materialization of 51B rows is not a thing).
16507        if let TensorId::Family { key, .. } = &requirement.id {
16508            if key.ends_with(".ple_embedding.ngram_embedding") {
16509                let layer = family_layer_index(key)
16510                    .ok_or("qwen4exp_gpu: n-gram table outside a trunk layer")?;
16511                let (info, bytes) = model
16512                    .raw(name)
16513                    .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16514                if info.dtype != "BF16" || info.shape != requirement.shape {
16515                    return Err(format!("qwen4exp_gpu: {name} table shape/dtype mismatch").into());
16516                }
16517                tables.insert(layer, bytes.to_vec());
16518                continue;
16519            }
16520        }
16521        // Per-expert projections (PerExpertModelopt).
16522        if let TensorId::Expert {
16523            layer,
16524            expert,
16525            tensor,
16526        } = requirement.id
16527        {
16528            let (out_f, in_f) = (requirement.shape[0] as usize, requirement.shape[1] as usize);
16529            check_bank_header(&model, name)?;
16530            let proj = match tensor {
16531                memra_gguf::tensor_contract::ExpertTensor::Gate => 0u8,
16532                memra_gguf::tensor_contract::ExpertTensor::Up => 1,
16533                memra_gguf::tensor_contract::ExpertTensor::Down => 2,
16534            };
16535            if per_expert
16536                .entry((layer, proj))
16537                .or_default()
16538                .insert(expert, (name.clone(), out_f, in_f, requirement.quant))
16539                .is_some()
16540            {
16541                return Err(format!(
16542                    "qwen4exp_gpu: duplicate per-expert row layer {layer} expert {expert}"
16543                )
16544                .into());
16545            }
16546            continue;
16547        }
16548        // Fused expert banks (FusedBanks) bypass ReferenceWeights (device residency).
16549        if let TensorId::Layer { index, tensor } = requirement.id {
16550            if matches!(
16551                tensor,
16552                LayerTensor::MoeExpertGateUpBank | LayerTensor::MoeExpertDownBank
16553            ) {
16554                let shape = [
16555                    requirement.shape[0] as usize,
16556                    requirement.shape[1] as usize,
16557                    requirement.shape[2] as usize,
16558                ];
16559                check_bank_header(&model, name)?;
16560                let address = FusedTensorPlan {
16561                    name: name.clone(),
16562                    shape,
16563                };
16564                if tensor == LayerTensor::MoeExpertGateUpBank {
16565                    gate_up_banks.insert(index, address);
16566                } else {
16567                    down_banks.insert(index, address);
16568                }
16569                continue;
16570            }
16571        }
16572        let (info, bytes) = model
16573            .raw(name)
16574            .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16575        if info.shape != requirement.shape {
16576            return Err(format!(
16577                "qwen4exp_gpu: {name} shape {:?} != contract {:?}",
16578                info.shape, requirement.shape
16579            )
16580            .into());
16581        }
16582        if info.dtype == "I64" {
16583            let ints = read_i64(name, info, bytes)?;
16584            let shape: Vec<usize> = info.shape.iter().map(|&d| d as usize).collect();
16585            weights.insert(
16586                requirement.id.clone(),
16587                ReferenceTensor::new_i64(shape, ints)?,
16588            );
16589            continue;
16590        }
16591        let mut data = dequant_float(name, info, bytes)?;
16592        if norm_fold_add_one(name) && !(opts.indexer_norm_raw && indexer_layernorm(name)) {
16593            for value in &mut data {
16594                *value += 1.0;
16595            }
16596        }
16597        let kind = bridge_transform(requirement.transform)?;
16598        let (ne_out, out_bytes) = kind.apply(&mut data, info.ne(), &cfg);
16599        let data: Vec<f32> = out_bytes
16600            .chunks_exact(4)
16601            .map(|chunk| f32::from_le_bytes(chunk.try_into().unwrap()))
16602            .collect();
16603        let mut shape: Vec<usize> = ne_out.iter().rev().map(|&d| d as usize).collect();
16604        // The PLE conv ships [wide, 1, K]; the reference executor (and the depthwise
16605        // kernel) consume the squeezed [wide, K] form — same bytes, GDN-conv precedent.
16606        if name.ends_with("ple.conv1d.weight") && shape.len() == 3 && shape[1] == 1 {
16607            shape = vec![shape[0], shape[2]];
16608        }
16609        // shared_expert_gate ships [1, H]; the reference binds the squeezed [H] row.
16610        if name.ends_with("mlp.shared_expert_gate.weight") && shape.len() == 2 && shape[0] == 1 {
16611            shape = vec![shape[1]];
16612        }
16613        weights.insert(requirement.id.clone(), ReferenceTensor::new(shape, data)?);
16614    }
16615
16616    let mut bank_plans = std::collections::BTreeMap::new();
16617    // FusedBanks: pair the fused gate_up with its down twin (trunk layers AND the MTP
16618    // block, whose layer plan lives at index n_trunk in plan.mtp_blocks). The fused split
16619    // itself happens per layer at read time (`BankPlan::read`).
16620    for (index, gate_up) in gate_up_banks {
16621        let down = down_banks
16622            .remove(&index)
16623            .ok_or_else(|| format!("qwen4exp_gpu: layer {index} has gate_up but no down bank"))?;
16624        let layer_plan = plan_layer_at(&plan, index)
16625            .ok_or_else(|| format!("qwen4exp_gpu: bank at unknown layer index {index}"))?;
16626        let MlpPlan::Moe(moe) = &layer_plan.mlp else {
16627            return Err(format!("qwen4exp_gpu: bank on non-MoE layer {index}").into());
16628        };
16629        bank_plans.insert(
16630            index,
16631            BankPlan {
16632                n_expert: moe.expert_count as usize,
16633                ff: moe.expert_intermediate_size as usize,
16634                hidden: plan.hidden_size as usize,
16635                src: BankPlanSrc::Fused {
16636                    gate_up,
16637                    down,
16638                    // The MTP bank (index >= n_trunk) keeps raw bf16 bytes: it goes DEVICE
16639                    // bf16-resident at build (never f32-expanded — 10 GB vs 5 GB).
16640                    keep_bf16: opts.host_bf16_banks || index >= n_trunk,
16641                },
16642            },
16643        );
16644    }
16645    if !down_banks.is_empty() {
16646        return Err("qwen4exp_gpu: down bank without a gate_up twin".into());
16647    }
16648    // PerExpertModelopt: order the per-projection name lists by expert index. The STACK
16649    // itself is read+concatenated per layer at consume time (`read_per_expert_bank`).
16650    let mut per_layer: std::collections::BTreeMap<u32, [Option<PerExpertPlan>; 3]> =
16651        Default::default();
16652    for ((layer, proj), experts) in per_expert {
16653        let layer_plan = plan_layer_at(&plan, layer)
16654            .ok_or_else(|| format!("qwen4exp_gpu: per-expert rows at unknown layer {layer}"))?;
16655        let MlpPlan::Moe(moe) = &layer_plan.mlp else {
16656            return Err(format!("qwen4exp_gpu: per-expert rows on non-MoE layer {layer}").into());
16657        };
16658        let count = moe.expert_count as usize;
16659        // Contiguity check: BTreeMap<u32, _> iteration is numeric order; every expert
16660        // index 0..E must be present exactly once.
16661        if experts.len() != count || experts.keys().last().copied() != Some(count as u32 - 1) {
16662            return Err(format!(
16663                "qwen4exp_gpu: layer {layer} proj {proj} has {} experts, plan says {count}",
16664                experts.len()
16665            )
16666            .into());
16667        }
16668        // Geometry is uniform across a projection (the census derives it per requirement);
16669        // the contiguity check above pins the map to exactly experts 0..E, so
16670        // `into_values` yields expert order and its index IS the expert id.
16671        let mut names = Vec::with_capacity(count);
16672        let mut geometry: Option<(usize, usize, memra_gguf::tensor_contract::QuantConstraint)> =
16673            None;
16674        for (name, out_f, in_f, quant) in experts.into_values() {
16675            match geometry {
16676                None => geometry = Some((out_f, in_f, quant)),
16677                Some((o, i, q)) if (o, i) == (out_f, in_f) && q == quant => {}
16678                Some((o, i, _)) => {
16679                    return Err(format!(
16680                        "qwen4exp_gpu: layer {layer} proj {proj} mixes expert geometry \
16681                         ({out_f}, {in_f}) vs ({o}, {i}) or quant classes"
16682                    )
16683                    .into());
16684                }
16685            }
16686            names.push(name);
16687        }
16688        let (out_f, in_f, quant) = geometry
16689            .ok_or_else(|| format!("qwen4exp_gpu: layer {layer} proj {proj} has no expert rows"))?;
16690        per_layer.entry(layer).or_default()[proj as usize] = Some(PerExpertPlan {
16691            names,
16692            out_f,
16693            in_f,
16694            quant,
16695        });
16696    }
16697    for (layer, mut projections) in per_layer {
16698        let MlpPlan::Moe(moe) = &plan_layer_at(&plan, layer).expect("checked above").mlp else {
16699            unreachable!("checked above");
16700        };
16701        let take = |slot: &mut Option<PerExpertPlan>, what: &str| -> Res<PerExpertPlan> {
16702            slot.take()
16703                .ok_or_else(|| format!("qwen4exp_gpu: layer {layer} missing {what} experts").into())
16704        };
16705        bank_plans.insert(
16706            layer,
16707            BankPlan {
16708                n_expert: moe.expert_count as usize,
16709                ff: moe.expert_intermediate_size as usize,
16710                hidden: plan.hidden_size as usize,
16711                src: BankPlanSrc::PerExpert {
16712                    gate: take(&mut projections[0], "gate")?,
16713                    up: take(&mut projections[1], "up")?,
16714                    down: take(&mut projections[2], "down")?,
16715                },
16716            },
16717        );
16718    }
16719    Ok(LoadedCheckpoint {
16720        plan,
16721        weights,
16722        model,
16723        bank_plans,
16724        tables,
16725    })
16726}
16727
16728/// One expert-bank projection's byte fingerprint — the loader's memory-ordering gate.
16729///
16730/// A change that only moves WHEN bank bytes are materialized has to leave WHICH bytes
16731/// untouched, and "untouched" is a digest, not an argument. `digest` is sha256 over the
16732/// projection's payload in device-upload order (NVFP4: codes then scales then the
16733/// little-endian macro row; f32/bf16: the raw uploaded bytes), so it pins the expert order,
16734/// the fused gate/up split, and the per-expert stack concatenation at once.
16735pub struct BankFingerprint {
16736    pub layer: u32,
16737    /// "gate" | "up" | "down".
16738    pub projection: &'static str,
16739    /// "f32" | "bf16" | "nvfp4".
16740    pub kind: &'static str,
16741    pub bytes: usize,
16742    /// Lowercase hex sha256.
16743    pub digest: String,
16744}
16745
16746impl LoadedCheckpoint {
16747    /// Read ONE layer's expert bank off the still-open mmap. The streaming seam every bank
16748    /// consumer goes through; the returned source is the caller's to drop.
16749    fn read_bank(&self, index: u32) -> Res<BankSrc> {
16750        self.bank_plans
16751            .get(&index)
16752            .ok_or_else(|| format!("qwen4exp_gpu: no bank source for layer {index}"))?
16753            .read(&self.model)
16754    }
16755
16756    /// Per-projection byte fingerprints for every bank, read one layer at a time (so this
16757    /// costs one layer of host memory, not the artifact). Gate instrument only — see
16758    /// `BankFingerprint`; the tiny-fixture gate compares these against banked goldens.
16759    pub fn bank_fingerprints(&self) -> Res<Vec<BankFingerprint>> {
16760        use sha2::{Digest, Sha256};
16761        let mut out = Vec::new();
16762        for (&layer, plan) in &self.bank_plans {
16763            let bank = plan.read(&self.model)?;
16764            for (projection, src) in [("gate", &bank.gate), ("up", &bank.up), ("down", &bank.down)]
16765            {
16766                let mut hasher = Sha256::new();
16767                let (kind, bytes) = match src {
16768                    // f32 bit patterns little-endian: the exact bytes `htod` uploads.
16769                    BankTensorSrc::F32(data) => {
16770                        for value in data {
16771                            hasher.update(value.to_le_bytes());
16772                        }
16773                        ("f32", data.len() * 4)
16774                    }
16775                    BankTensorSrc::Bf16(raw) => {
16776                        hasher.update(raw);
16777                        ("bf16", raw.len())
16778                    }
16779                    BankTensorSrc::Nvfp4 {
16780                        codes,
16781                        scales,
16782                        macros,
16783                        ..
16784                    } => {
16785                        hasher.update(codes);
16786                        hasher.update(scales);
16787                        for m in macros {
16788                            hasher.update(m.to_le_bytes());
16789                        }
16790                        ("nvfp4", codes.len() + scales.len() + macros.len() * 4)
16791                    }
16792                };
16793                out.push(BankFingerprint {
16794                    layer,
16795                    projection,
16796                    kind,
16797                    bytes,
16798                    digest: hasher
16799                        .finalize()
16800                        .iter()
16801                        .map(|b| format!("{b:02x}"))
16802                        .collect(),
16803                });
16804            }
16805        }
16806        Ok(out)
16807    }
16808
16809    /// Expand banks and n-gram tables into plain `ReferenceWeights` entries so
16810    /// memra-reference can execute the checkpoint. TINY/SIBLING SCALE ONLY — the real
16811    /// artifact's banks/table do not fit host f32; the GPU path never takes this.
16812    pub fn into_reference_weights(mut self) -> Res<ReferenceWeights> {
16813        let bank_plans = std::mem::take(&mut self.bank_plans);
16814        for (index, plan) in bank_plans {
16815            let bank = plan.read(&self.model)?;
16816            let gate = bank_to_f32(&bank.gate, bank.n_expert, bank.ff, bank.hidden)?;
16817            let up = bank_to_f32(&bank.up, bank.n_expert, bank.ff, bank.hidden)?;
16818            let down = bank_to_f32(&bank.down, bank.n_expert, bank.hidden, bank.ff)?;
16819            self.weights.insert(
16820                layer_id(index, LayerTensor::MoeExpertGateBank),
16821                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], gate)?,
16822            );
16823            self.weights.insert(
16824                layer_id(index, LayerTensor::MoeExpertUpBank),
16825                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], up)?,
16826            );
16827            self.weights.insert(
16828                layer_id(index, LayerTensor::MoeExpertDownBank),
16829                ReferenceTensor::new(vec![bank.n_expert, bank.hidden, bank.ff], down)?,
16830            );
16831        }
16832        for (index, bytes) in self.tables {
16833            let ple = self.plan.layers[index as usize]
16834                .ple
16835                .as_ref()
16836                .ok_or("qwen4exp_gpu: table on a non-PLE layer")?;
16837            let head_dim = ple.head_embed_dim as usize;
16838            let table = NgramTable::Bf16(bytes);
16839            let rows = table.rows(head_dim);
16840            let mut data = vec![0.0f32; rows * head_dim];
16841            for row in 0..rows {
16842                table.gather_into(
16843                    row,
16844                    head_dim,
16845                    &mut data[row * head_dim..(row + 1) * head_dim],
16846                );
16847            }
16848            self.weights.insert(
16849                family_id(format!(
16850                    "trunk.layers.{index}.ple.ple_embedding.ngram_embedding"
16851                )),
16852                ReferenceTensor::new(vec![rows, head_dim], data)?,
16853            );
16854        }
16855        Ok(self.weights)
16856    }
16857}
16858
16859impl LoadedCheckpoint {
16860    /// CLONE the float weights and expand ONLY the MTP bank(s) into `ReferenceWeights`
16861    /// entries — the real-checkpoint draft-parity instrument (mtp-spec lane): the host
16862    /// reference twin needs the mtp.* rows + embed/head, and must NOT expand the trunk
16863    /// banks (48 layers of f32 experts do not fit anywhere). Borrowing form so ONE
16864    /// checkpoint read serves both the engine model and the host twin.
16865    pub fn mtp_reference_weights(&self) -> Res<ReferenceWeights> {
16866        let mut weights = self.weights.clone();
16867        let n_trunk = self.plan.layers.len() as u32;
16868        for (index, plan) in &self.bank_plans {
16869            if *index < n_trunk {
16870                continue;
16871            }
16872            let bank = plan.read(&self.model)?;
16873            let gate = bank_to_f32(&bank.gate, bank.n_expert, bank.ff, bank.hidden)?;
16874            let up = bank_to_f32(&bank.up, bank.n_expert, bank.ff, bank.hidden)?;
16875            let down = bank_to_f32(&bank.down, bank.n_expert, bank.hidden, bank.ff)?;
16876            weights.insert(
16877                layer_id(*index, LayerTensor::MoeExpertGateBank),
16878                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], gate)?,
16879            );
16880            weights.insert(
16881                layer_id(*index, LayerTensor::MoeExpertUpBank),
16882                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], up)?,
16883            );
16884            weights.insert(
16885                layer_id(*index, LayerTensor::MoeExpertDownBank),
16886                ReferenceTensor::new(vec![bank.n_expert, bank.hidden, bank.ff], down)?,
16887            );
16888        }
16889        Ok(weights)
16890    }
16891}
16892
16893/// Host-dequant a bank tensor to f32 [E, out, in] (NVFP4 via the pub dsv4 decoder — the
16894/// same value chain the device kernel reproduces).
16895fn bank_to_f32(bank: &BankTensorSrc, n_expert: usize, out_f: usize, in_f: usize) -> Res<Vec<f32>> {
16896    match bank {
16897        BankTensorSrc::F32(data) => Ok(data.clone()),
16898        BankTensorSrc::Bf16(bytes) => Ok(bytes
16899            .chunks_exact(2)
16900            .map(|b| f32::from_bits(u32::from(u16::from_le_bytes([b[0], b[1]])) << 16))
16901            .collect()),
16902        BankTensorSrc::Nvfp4 {
16903            codes,
16904            scales,
16905            macros,
16906            ..
16907        } => {
16908            let mut out = Vec::with_capacity(n_expert * out_f * in_f);
16909            let wbytes = out_f * in_f / 2;
16910            let sbytes = out_f * in_f / 16;
16911            for expert in 0..n_expert {
16912                out.extend(memra_gguf::dsv4::dequant_nvfp4_expert(
16913                    &codes[expert * wbytes..(expert + 1) * wbytes],
16914                    &scales[expert * sbytes..(expert + 1) * sbytes],
16915                    macros[expert],
16916                    out_f,
16917                    in_f,
16918                ));
16919            }
16920            Ok(out)
16921        }
16922    }
16923}
16924
16925impl Qwen4ExpGpu {
16926    /// Load a qwen4_exp checkpoint dir (config.json + safetensors; the BF16 export or the
16927    /// per-expert modelopt NVFP4 mint) through the pack/plan/contract into engine-resident
16928    /// weights: trunk f32 on device, n-gram table host-resident bf16, NVFP4 expert banks
16929    /// as-stored on device.
16930    pub fn load_from_dir(e: &Engine, dir: &std::path::Path) -> Res<Self> {
16931        Self::from_loaded_checkpoint(e, read_checkpoint(dir)?)
16932    }
16933
16934    /// `load_from_dir` with real-checkpoint loader knobs (`LoadOptions`).
16935    pub fn load_from_dir_with(e: &Engine, dir: &std::path::Path, opts: LoadOptions) -> Res<Self> {
16936        Self::from_loaded_checkpoint(e, read_checkpoint_with(dir, opts)?)
16937    }
16938
16939    /// Card-1 draft placement (mtp10): the trunk builds on `e` (card 0) and the MTP
16940    /// draft block — weights, ~5 GB DeviceBf16 expert bank, private lm-head copy — on
16941    /// `draft_e` (card 1). Requires `opts.load_mtp` and P2P between the pair
16942    /// (`tp2_enable_p2p`); the spec loop's wide rows cross per round.
16943    pub fn load_from_dir_dev1(
16944        e: &Engine,
16945        draft_e: &Engine,
16946        dir: &std::path::Path,
16947        opts: LoadOptions,
16948    ) -> Res<Self> {
16949        Self::from_loaded_checkpoint_dual(e, Some(draft_e), read_checkpoint_with(dir, opts)?)
16950    }
16951
16952    /// Consume a `LoadedCheckpoint` into the engine-resident model. Banks and n-gram
16953    /// tables MOVE (the real artifact's 102 GB table must not be cloned).
16954    pub fn from_loaded_checkpoint(e: &Engine, checkpoint: LoadedCheckpoint) -> Res<Self> {
16955        Self::from_loaded_checkpoint_dual(e, None, checkpoint)
16956    }
16957
16958    /// `from_loaded_checkpoint` with the optional card-1 draft engine: the MTP bank
16959    /// (layer index >= n_trunk) uploads to `draft_e` when given; the trunk banks stay
16960    /// on `e` either way.
16961    pub fn from_loaded_checkpoint_dual(
16962        e: &Engine,
16963        draft_e: Option<&Engine>,
16964        checkpoint: LoadedCheckpoint,
16965    ) -> Res<Self> {
16966        let LoadedCheckpoint {
16967            plan,
16968            weights,
16969            model,
16970            bank_plans,
16971            tables,
16972        } = checkpoint;
16973        let mut parts = ExternalParts::default();
16974        let n_trunk = plan.layers.len() as u32;
16975        let upload_half = |e: &Engine, src: BankTensorSrc, device_bf16: bool| -> Res<BankHalf> {
16976            Ok(match src {
16977                BankTensorSrc::F32(data) => BankHalf::F32(e.htod(&data)?),
16978                BankTensorSrc::Nvfp4 {
16979                    codes,
16980                    scales,
16981                    macros,
16982                    ..
16983                } => BankHalf::Nvfp4 {
16984                    codes: e.htod_bytes(&codes)?,
16985                    scales: e.htod_bytes(&scales)?,
16986                    macros_dev: e.htod(&macros)?,
16987                    macros,
16988                },
16989                // Residency was decided at read time (LoadOptions::host_bf16_banks /
16990                // load_mtp): trunk bf16 stays host (gate-mode); the MTP draft bank goes
16991                // device-resident bf16 (the draft decode path reads it in place).
16992                BankTensorSrc::Bf16(bytes) if device_bf16 => {
16993                    BankHalf::DeviceBf16(e.htod_bytes(&bytes)?)
16994                }
16995                BankTensorSrc::Bf16(bytes) => BankHalf::HostBf16(bytes),
16996            })
16997        };
16998        // STREAMED: one layer's bank is read off the mmap, uploaded, and dropped before the
16999        // next is read. Peak host cost is ONE layer (~1.5 GB on the real mint) instead of
17000        // the whole ~72 GB stack, which is what let the real gate load on a 180 GB-RAM box
17001        // (receipt: research/qwen4exp-bringup-20260829/loader/LOADER-STREAM.md).
17002        // `upload_half` moves each projection into the device slice, so the host copy is
17003        // freed at the end of every iteration.
17004        for (index, bank_plan) in bank_plans {
17005            let bank = bank_plan.read(&model)?;
17006            let device_bf16 = index >= n_trunk;
17007            // The MTP bank follows the draft's placement (card 1 when dev1 is armed).
17008            let bank_e = if device_bf16 { draft_e.unwrap_or(e) } else { e };
17009            parts.expert_banks.insert(
17010                index,
17011                ExpertBank {
17012                    gate: upload_half(bank_e, bank.gate, device_bf16)?,
17013                    up: upload_half(bank_e, bank.up, device_bf16)?,
17014                    down: upload_half(bank_e, bank.down, device_bf16)?,
17015                },
17016            );
17017        }
17018        // The mmap has no more readers; the model's weights are device-resident and the
17019        // table below is host-owned bytes.
17020        drop(model);
17021        for (index, bytes) in tables {
17022            parts.ngram_tables.insert(index, NgramTable::Bf16(bytes));
17023        }
17024        Self::from_reference_weights_with(e, draft_e, &plan, &weights, parts)
17025    }
17026}
17027
17028// ==================================== TP2 (perf round 3) ====================================
17029//
17030// Two-card tensor-parallel DECODE over PCIe P2P (no NVLink) — the PROFILE-2 §TP2
17031// projection made real. Structure (the tp2-join-diet playbook, step37 lane):
17032//
17033// - The RESIDUAL IS REPLICATED: both cards hold the wide planes and run the entry embed,
17034//   PLE block, hyper-connection read/write gates, and exit mixer with bit-identical
17035//   weights on bit-identical inputs (replicated deterministic compute — kills every
17036//   broadcast except the two joins below). All replicated device math runs deterministic
17037//   kernels (bf16w matvecs, fused gates); TP2 therefore REQUIRES the bf16 trunk twins.
17038// - SPLIT: GDN by key-head blocks (card d owns orig key heads [d·nk/2, (d+1)·nk/2) and
17039//   the value heads mapping to them — compact per-card head order keeps kh = h % nk_h)),
17040//   QSA by head halves (12/12 query heads, 1/1 KV heads), MoE routed experts by expert-id
17041//   halves (card d owns experts [d·E/2, (d+1)·E/2); top-10 splits ~5/5 on average),
17042//   shared expert by ff halves, lm_head by vocab halves (card 0 reads the resident twin's
17043//   row prefix; card 1 holds the suffix copy).
17044// - JOINS: exactly 2 per layer (mixer out-proj partials, MoE+shared partials), each a
17045//   [hidden] f32 row pushed as a P2P kernel store into the peer's resident staging buffer
17046//   (`q4e_push_f32`, the direct-join mechanism) + one cross-device event wait each way;
17047//   BOTH cards then compute out = partial0 + partial1 in the SAME rank order, so the
17048//   replicated residual stays bit-identical across cards.
17049// - HOST twins unchanged: MoE routing (router GEMV + dtoh on card 0, top-k once, filtered
17050//   selection H2D to both), QSA indexer (card 0 projects + host mask, mask H2D to both),
17051//   PLE n-gram hashing (host, gathered rows H2D to both; the 102 GB table stays host-
17052//   resident and SHARED — the card-1 PLE replica carries no table).
17053// - Decode graphs stay OFF in TP2 (eager issue; the joins are the schedule). Prefill
17054//   stays single-card; the first `decode_step_tp2` migrates the mixer state into
17055//   per-card halves (host bounce, one-time) and the state is TP2-latched from then on.
17056//
17057// EXACTNESS CLASS (the gate statement): TP2 output matches single-card to TOLERANCE, not
17058// bit — the split out-projections sum row halves in a different association than the
17059// full GEMV, the expert combine becomes (Σ card-0 slots) + (Σ card-1 slots) instead of
17060// the slot-sequential chain, and the join add reorders those partial sums. Same
17061// accumulation class as every banked seam; gated by `--tp2-gate` per-row envelope +
17062// argmax vs the single-card twin, plus the greedy-divergence battery.
17063
17064/// Per-card compact GDN half (see the head-map comment on `tp2_gdn_head_map`).
17065struct GdnHalfW {
17066    nk_h: usize,
17067    nv_h: usize,
17068    hk: usize,
17069    hv: usize,
17070    kernel: usize,
17071    gate_activation: GdnGateActivation,
17072    /// Row-stacked [qkv; z; beta; alpha] half twin (proj-stack residency: per-mat
17073    /// launches read row-offset views; the seam launches the whole stack).
17074    proj_b16: CudaSlice<u8>,
17075    out_b16: CudaSlice<u8>, // [hidden, nv_h*hv] (compact column block)
17076    conv_w: CudaSlice<f32>, // [conv_dim_h, K]
17077    a: CudaSlice<f32>,      // [nv_h]
17078    dt: CudaSlice<f32>,     // [nv_h]
17079    norm: CudaSlice<f32>,   // [hv] (replicated)
17080}
17081
17082/// Per-card QSA half: query heads [d*nh_h, (d+1)*nh_h), KV heads [d*nkv_h, ...).
17083struct QsaHalfW {
17084    nh_h: usize,
17085    nkv_h: usize,
17086    hd: usize,
17087    n_rot: usize,
17088    rope_base: f32,
17089    scale: f32,
17090    /// Row-stacked [wq; wk; wv] half twin (proj-stack residency; wq rows are the fused
17091    /// [q|gate] block).
17092    proj_b16: CudaSlice<u8>,
17093    wo_b16: CudaSlice<u8>, // [hidden, nh_h*hd] (compact column block)
17094    q_norm: Option<CudaSlice<f32>>,
17095    k_norm: Option<CudaSlice<f32>>,
17096    /// YaRN tables on THIS half's card (long-context lane); `None` on the shipped config.
17097    yarn: Option<YarnRopeW>,
17098}
17099
17100enum MixerHalfW {
17101    Gdn(GdnHalfW),
17102    Qsa(QsaHalfW),
17103}
17104
17105/// Card-1 NVFP4 expert-bank half (experts [E/2, E), local ids 0..E/2).
17106struct Nvfp4Half {
17107    codes: CudaSlice<u8>,
17108    scales: CudaSlice<u8>,
17109    macros_dev: CudaSlice<f32>,
17110}
17111
17112struct MoeHalfW {
17113    /// Card-1 bank halves (card 0 addresses the resident full bank with original ids).
17114    gate1: Nvfp4Half,
17115    up1: Nvfp4Half,
17116    down1: Nvfp4Half,
17117    /// Shared expert: card 0 reads the resident full twins' ROW PREFIX (gate/up) and its
17118    /// own compact down-column block; card 1 holds suffix/compact copies.
17119    shared_down0: CudaSlice<u8>, // card0 [hidden, sff_h]
17120    shared_down1: CudaSlice<u8>,                // card1 [hidden, sff_h]
17121    shared_input_gate1: Option<CudaSlice<f32>>, // card1 [hidden]
17122    /// Row-stacked [gate_half; up_half] twins (proj-stack residency): card 0 stacks the
17123    /// ROW PREFIXES of the full mats (not contiguous in the resident full stack), card 1
17124    /// its suffix copies. Per-mat launches read row-offset views (0 / sff_h).
17125    shared_gu0_b16: CudaSlice<u8>,
17126    shared_gu1_b16: CudaSlice<u8>,
17127}
17128
17129struct Tp2LayerW {
17130    attn_gate1: GateW,
17131    mlp_gate1: GateW,
17132    mixer0: MixerHalfW,
17133    mixer1: MixerHalfW,
17134    moe: MoeHalfW,
17135    ple1: Option<PleW>,
17136    /// This layer's resolved expert placement — the SAME object that chose which expert
17137    /// rows were gathered into `moe`'s card-1 bank. One source of truth for the upload
17138    /// and for the route split is what keeps a placement from being applied to one and
17139    /// not the other (the failure mode that would read as a model bug, not a config bug).
17140    place: LayerPlacement,
17141}
17142
17143/// The TP2 shard: card-1 replicas + both cards' split halves + join plumbing.
17144pub struct Tp2Shard {
17145    layers: Vec<Tp2LayerW>,
17146    exit_gate1: GateW,
17147    lm_head1: CudaSlice<u8>, // card1 bf16 [vocab - vsplit, hidden]
17148    vsplit: usize,
17149    /// Join staging, TWO buffers per direction alternating by join parity. Two is
17150    /// provably enough: the overwrite of buffer (j+2 mod 2) is transitively ordered
17151    /// after the peer's read at join j (the peer's push at j+1 follows its add at j on
17152    /// its in-order stream, and our wait on that push precedes our overwrite).
17153    stage0: [CudaSlice<f32>; 2], // card0 staging (receives card1 partials)
17154    stage1: [CudaSlice<f32>; 2], // card1 staging (receives card0 partials)
17155    stage0_raw: [u64; 2],
17156    stage1_raw: [u64; 2],
17157    ev0: [cudarc::driver::CudaEvent; 2], // card0 push done, by join parity
17158    ev1: [cudarc::driver::CudaEvent; 2], // card1 push done, by join parity
17159}
17160
17161enum MixerHalfState {
17162    Gdn {
17163        conv: CudaSlice<f32>,  // [pad, conv_dim_h]
17164        state: CudaSlice<f32>, // [nv_h, hv, hk]
17165    },
17166    Qsa {
17167        /// This card's KV half [cap, nkv_h*hd] — f32 or the kvq q8_0/q5_1 byte caches
17168        /// (format follows the single-card store; head halves are 32-block aligned at
17169        /// hd % 32 == 0, so quantized migration gathers BYTES verbatim).
17170        kv: QsaKvStore,
17171    },
17172}
17173
17174struct Tp2LayerState {
17175    m0: MixerHalfState,
17176    m1: MixerHalfState,
17177    ple1: Option<PleState>,
17178}
17179
17180struct Tp2State {
17181    ws1: StepPool,
17182    layers: Vec<Tp2LayerState>,
17183    graphs: Tp2Graphs,
17184    /// TP2-PREFILL join staging (chunk-sized [t*hidden] per direction, two buffers per
17185    /// direction by join parity — the decode stage buffers' proof carries over
17186    /// verbatim). Lazily sized at the first `forward_tp2` chunk; `raw` = the peer's
17187    /// UVA pointers baked for `launch_push`.
17188    pf_stage0: Option<[CudaSlice<f32>; 2]>, // on card0 (receives card1 partials)
17189    pf_stage1: Option<[CudaSlice<f32>; 2]>,
17190    pf_stage0_raw: [u64; 2],
17191    pf_stage1_raw: [u64; 2],
17192    pf_rows: usize,
17193}
17194
17195/// Captured TP2 decode segments per card (the single-card StepGraphs pattern applied
17196/// per rank): `a[d][li]` = attn gate_read + GDN half + join push, `b[d][li]` = join add +
17197/// gate_write + mlp gate_read (+ card1 shared-half prestage), `exit[d]` = exit mixer +
17198/// lm_head half. GDN layers without PLE only; QSA/PLE layers, the router boundary,
17199/// the variable-shape MoE tail, and the MoE join stay eager. Event records/waits sit
17200/// BETWEEN segment launches (not capturable) — same choreography in warm and replay
17201/// modes. The first TP2 decode step runs fully eager to park every slot (allocations
17202/// inside a capture become graph mem nodes); captures are lazy on the second step.
17203#[derive(Default)]
17204struct Tp2Graphs {
17205    warm: bool,
17206    a: [Vec<Option<GraphEntry>>; 2],
17207    b: [Vec<Option<GraphEntry>>; 2],
17208    /// Count-gated MoE tail (routed half + shared add + join push) — fixed launch
17209    /// shapes via the pack blob, so the variable expert split still captures.
17210    c: [Vec<Option<GraphEntry>>; 2],
17211    /// MoE join add + gate_write.
17212    d: [Vec<Option<GraphEntry>>; 2],
17213    exit: [Option<GraphEntry>; 2],
17214}
17215
17216/// Compact value-head order for card `d`: heads h with h % nk in [d*nk_h, (d+1)*nk_h),
17217/// ascending. With nv % nk == 0 this is exactly `(j / nk_h) * nk + (j % nk_h) + d*nk_h`,
17218/// and the compact system stays self-consistent with the kernels' kh = h % nk_h mapping.
17219fn tp2_gdn_head_map(d: usize, nk: usize, nv: usize) -> Vec<usize> {
17220    let nk_h = nk / 2;
17221    let nv_h = nv / 2;
17222    (0..nv_h)
17223        .map(|j| (j / nk_h) * nk + (j % nk_h) + d * nk_h)
17224        .collect()
17225}
17226
17227/// Gather whole rows (row-major [rows, in_f]) into a compact copy.
17228fn gather_rows_host(src: &[f32], in_f: usize, rows: &[usize]) -> Vec<f32> {
17229    let mut out = Vec::with_capacity(rows.len() * in_f);
17230    for &r in rows {
17231        out.extend_from_slice(&src[r * in_f..(r + 1) * in_f]);
17232    }
17233    out
17234}
17235
17236/// Gather column blocks per row (row-major [nrows, ncols]) into a compact copy.
17237fn gather_cols_host(
17238    src: &[f32],
17239    nrows: usize,
17240    ncols: usize,
17241    blocks: &[(usize, usize)],
17242) -> Vec<f32> {
17243    let width: usize = blocks.iter().map(|&(_, l)| l).sum();
17244    let mut out = Vec::with_capacity(nrows * width);
17245    for r in 0..nrows {
17246        for &(start, len) in blocks {
17247            out.extend_from_slice(&src[r * ncols + start..r * ncols + start + len]);
17248        }
17249    }
17250    out
17251}
17252
17253fn need_twin(e: &Engine, data: &[f32], in_f: usize, what: &str) -> Res<CudaSlice<u8>> {
17254    bf16_twin(e, data, in_f)?.ok_or_else(|| {
17255        format!("qwen4exp_gpu tp2: {what} has no exact bf16 twin (in_f {in_f})").into()
17256    })
17257}
17258
17259/// Launch `q4e_push_f32`: UVA store of `n` f32 into the PEER address `dst_raw` on `e`'s
17260/// stream (the direct-join push).
17261fn launch_push(e: &Engine, src: &CudaSlice<f32>, dst_raw: u64, n: usize) -> Res<()> {
17262    let f = e.func("q4e_push_f32");
17263    let cfg = LaunchConfig::for_num_elems(n as u32);
17264    let nl = n as i64;
17265    let stream = e.gpu.stream();
17266    let mut b = stream.launch_builder(&f);
17267    b.arg(src).arg(&dst_raw).arg(&nl);
17268    unsafe {
17269        b.launch(cfg)?;
17270    }
17271    Ok(())
17272}
17273
17274/// Enable bidirectional P2P + pool peer access between two engines (the
17275/// `configure_native_p2p` essentials for the qwen4_exp TP2 pair; pool access makes every
17276/// pooled allocation UVA-addressable from the peer, which is what `q4e_push_f32` needs).
17277pub fn tp2_enable_p2p(e0: &Engine, e1: &Engine) -> Res<()> {
17278    use cudarc::driver::sys;
17279    for (src, dst) in [(e0, e1), (e1, e0)] {
17280        let mut can = 0i32;
17281        unsafe {
17282            sys::cuDeviceCanAccessPeer(&mut can, src.ctx().cu_device(), dst.ctx().cu_device())
17283                .result()?;
17284        }
17285        if can == 0 {
17286            return Err(format!(
17287                "qwen4exp_gpu tp2: dev{} cannot access dev{} over P2P",
17288                src.ctx().ordinal(),
17289                dst.ctx().ordinal()
17290            )
17291            .into());
17292        }
17293        src.ctx().bind_to_thread()?;
17294        let rc = unsafe { sys::cuCtxEnablePeerAccess(dst.ctx().cu_ctx(), 0) };
17295        use cudarc::driver::sys::cudaError_enum as E;
17296        if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
17297            return Err(format!("qwen4exp_gpu tp2: cuCtxEnablePeerAccess failed: {rc:?}").into());
17298        }
17299    }
17300    for (owner, accessor) in [(e0, e1), (e1, e0)] {
17301        let device = cudarc::driver::result::device::get(owner.ctx().ordinal() as i32)?;
17302        let mut pool: sys::CUmemoryPool = std::ptr::null_mut();
17303        unsafe {
17304            sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
17305        }
17306        let desc = sys::CUmemAccessDesc {
17307            location: sys::CUmemLocation {
17308                type_: sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
17309                id: accessor.ctx().ordinal() as i32,
17310            },
17311            flags: sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
17312        };
17313        let rc = unsafe { sys::cuMemPoolSetAccess(pool, &desc, 1) };
17314        if rc != sys::cudaError_enum::CUDA_SUCCESS {
17315            return Err(format!("qwen4exp_gpu tp2: cuMemPoolSetAccess failed: {rc:?}").into());
17316        }
17317    }
17318    Ok(())
17319}
17320
17321/// Build the card-1 replica PLE weight set from the checkpoint's host weights (the
17322/// device parts of `PleW` with an EMPTY table — the 102 GB n-gram table stays host-
17323/// resident on the model and is passed to `ple_block` explicitly).
17324fn build_ple_replica(
17325    e: &Engine,
17326    weights: &ReferenceWeights,
17327    prefix: &str,
17328    ple_plan: &PleEmbeddingPlan,
17329    streams: usize,
17330    hidden: usize,
17331) -> Res<PleW> {
17332    let embed_dim = ple_plan.embed_dim as usize;
17333    let key_proj = expect(weights, &family_id(format!("{prefix}ple.key_proj.weight")))?;
17334    let conv_w = expect(weights, &family_id(format!("{prefix}ple.conv1d.weight")))?;
17335    let norm_slices = |name: &str| -> Res<Vec<CudaSlice<f32>>> {
17336        let t = expect(weights, &family_id(format!("{prefix}ple.{name}.weight")))?;
17337        split_rows(&t.data, streams, hidden, 1)
17338            .into_iter()
17339            .map(|v| e.htod(&v))
17340            .collect::<Result<_, _>>()
17341    };
17342    let ints = |name: &str| -> Res<Vec<i64>> {
17343        let t = expect(
17344            weights,
17345            &family_id(format!("{prefix}ple.ple_embedding.{name}")),
17346        )?;
17347        t.ints
17348            .clone()
17349            .ok_or_else(|| "qwen4exp_gpu: n-gram buffer must be I64".into())
17350    };
17351    Ok(PleW {
17352        plan: *ple_plan,
17353        key_proj: split_rows(&key_proj.data, streams, hidden, embed_dim)
17354            .into_iter()
17355            .map(|v| e.htod(&v))
17356            .collect::<Result<_, _>>()?,
17357        value_proj: upload(
17358            e,
17359            &expect(
17360                weights,
17361                &family_id(format!("{prefix}ple.value_proj.weight")),
17362            )?,
17363        )?,
17364        norm_key: norm_slices("norm_key")?,
17365        norm_query: norm_slices("norm_query")?,
17366        norm_conv: norm_slices("norm_conv")?,
17367        conv_w: split_rows(&conv_w.data, streams, hidden, ple_plan.conv_kernel as usize)
17368            .into_iter()
17369            .map(|v| e.htod(&v))
17370            .collect::<Result<_, _>>()?,
17371        multipliers: ints("layer_multipliers")?,
17372        sizes: ints("ngram_heads_vocab_sizes")?,
17373        offsets: ints("ngram_heads_offsets")?,
17374        table: NgramTable::F32(Vec::new()), // never gathered; the model's table is passed in
17375    })
17376}
17377
17378/// Build one card's compact GDN half from host weights.
17379#[allow(clippy::too_many_arguments)]
17380fn build_gdn_half(
17381    e: &Engine,
17382    weights: &ReferenceWeights,
17383    index: u32,
17384    gdn: &GatedDeltaNetPlan,
17385    hidden: usize,
17386    d: usize,
17387) -> Res<GdnHalfW> {
17388    let (nk, nv) = (gdn.key_heads as usize, gdn.value_heads as usize);
17389    let (hk, hv) = (gdn.key_head_dim as usize, gdn.value_head_dim as usize);
17390    if nk % 2 != 0 || nv % nk != 0 {
17391        return Err(format!(
17392            "qwen4exp_gpu tp2: GDN layer {index} nk {nk} / nv {nv} does not split by key-head halves"
17393        )
17394        .into());
17395    }
17396    let (nk_h, nv_h) = (nk / 2, nv / 2);
17397    let head_map = tp2_gdn_head_map(d, nk, nv);
17398    let qkv = expect(weights, &layer_id(index, LayerTensor::GdnQkv))?;
17399    let z = expect(weights, &layer_id(index, LayerTensor::GdnGate))?;
17400    let beta = expect(weights, &layer_id(index, LayerTensor::GdnBeta))?;
17401    let alpha = expect(weights, &layer_id(index, LayerTensor::GdnAlpha))?;
17402    let out = expect(weights, &layer_id(index, LayerTensor::GdnOutput))?;
17403    let conv_w = expect(weights, &layer_id(index, LayerTensor::GdnConv1d))?;
17404    let a = expect(weights, &layer_id(index, LayerTensor::GdnA))?;
17405    let dt = expect(weights, &layer_id(index, LayerTensor::GdnDtBias))?;
17406    let norm = expect(weights, &layer_id(index, LayerTensor::GdnNorm))?;
17407    let kernel = gdn.conv_kernel as usize;
17408    // Row lists for the fused qkv/conv (q block, k block, v per compact head).
17409    let mut qkv_rows: Vec<usize> = Vec::with_capacity(2 * nk_h * hk + nv_h * hv);
17410    qkv_rows.extend(d * nk_h * hk..(d + 1) * nk_h * hk);
17411    qkv_rows.extend(nk * hk + d * nk_h * hk..nk * hk + (d + 1) * nk_h * hk);
17412    for &hm in &head_map {
17413        qkv_rows.extend(2 * nk * hk + hm * hv..2 * nk * hk + (hm + 1) * hv);
17414    }
17415    let mut z_rows: Vec<usize> = Vec::with_capacity(nv_h * hv);
17416    for &hm in &head_map {
17417        z_rows.extend(hm * hv..(hm + 1) * hv);
17418    }
17419    let out_blocks: Vec<(usize, usize)> = head_map.iter().map(|&hm| (hm * hv, hv)).collect();
17420    let qkv_c = gather_rows_host(&qkv.data, hidden, &qkv_rows);
17421    let z_c = gather_rows_host(&z.data, hidden, &z_rows);
17422    let beta_c = gather_rows_host(&beta.data, hidden, &head_map);
17423    let alpha_c = gather_rows_host(&alpha.data, hidden, &head_map);
17424    let out_c = gather_cols_host(&out.data, hidden, nv * hv, &out_blocks);
17425    let conv_c = gather_rows_host(&conv_w.data, kernel, &qkv_rows);
17426    let a_c: Vec<f32> = head_map.iter().map(|&hm| a.data[hm]).collect();
17427    let dt_c: Vec<f32> = head_map.iter().map(|&hm| dt.data[hm]).collect();
17428    Ok(GdnHalfW {
17429        nk_h,
17430        nv_h,
17431        hk,
17432        hv,
17433        kernel,
17434        gate_activation: gdn.gate_activation,
17435        proj_b16: need_stack_twin(
17436            e,
17437            &[&qkv_c, &z_c, &beta_c, &alpha_c],
17438            hidden,
17439            "tp2 gdn proj half",
17440        )?,
17441        out_b16: need_twin(e, &out_c, nv_h * hv, "tp2 gdn out half")?,
17442        conv_w: e.htod(&conv_c)?,
17443        a: e.htod(&a_c)?,
17444        dt: e.htod(&dt_c)?,
17445        norm: e.htod(&norm.data)?,
17446    })
17447}
17448
17449/// Build one card's QSA half from host weights (query heads d*nh_h.., KV heads d*nkv_h..).
17450#[allow(clippy::too_many_arguments)]
17451fn build_qsa_half(
17452    e: &Engine,
17453    weights: &ReferenceWeights,
17454    index: u32,
17455    attn: &FullAttentionPlan,
17456    hidden: usize,
17457    d: usize,
17458) -> Res<QsaHalfW> {
17459    let nh = attn.query_heads as usize;
17460    let nkv = attn.kv_heads as usize;
17461    let hd = attn.key_head_dim as usize;
17462    if nh % 2 != 0 || nkv % 2 != 0 || nh % nkv != 0 {
17463        return Err(format!(
17464            "qwen4exp_gpu tp2: QSA layer {index} heads {nh}/{nkv} do not split in halves"
17465        )
17466        .into());
17467    }
17468    let (nh_h, nkv_h) = (nh / 2, nkv / 2);
17469    let wq = expect(weights, &layer_id(index, LayerTensor::Query))?;
17470    let wk = expect(weights, &layer_id(index, LayerTensor::Key))?;
17471    let wv = expect(weights, &layer_id(index, LayerTensor::Value))?;
17472    let wo = expect(weights, &layer_id(index, LayerTensor::AttentionOutput))?;
17473    // Fused [q|gate] per head: card d's heads are a contiguous row block.
17474    let q_rows: Vec<usize> = (d * nh_h * 2 * hd..(d + 1) * nh_h * 2 * hd).collect();
17475    let kv_rows: Vec<usize> = (d * nkv_h * hd..(d + 1) * nkv_h * hd).collect();
17476    let wq_c = gather_rows_host(&wq.data, hidden, &q_rows);
17477    let wk_c = gather_rows_host(&wk.data, hidden, &kv_rows);
17478    let wv_c = gather_rows_host(&wv.data, hidden, &kv_rows);
17479    let wo_c = gather_cols_host(&wo.data, hidden, nh * hd, &[(d * nh_h * hd, nh_h * hd)]);
17480    let opt_norm = |tensor: LayerTensor| -> Res<Option<CudaSlice<f32>>> {
17481        match weights.get(&layer_id(index, tensor)) {
17482            Some(t) => Ok(Some(e.htod(&t.data)?)),
17483            None => Ok(None),
17484        }
17485    };
17486    let scale = match attn.scale {
17487        memra_gguf::model_plan::AttentionScale::InverseSqrtKeyDim => 1.0 / (hd as f32).sqrt(),
17488        memra_gguf::model_plan::AttentionScale::Fixed(scale) => scale,
17489    };
17490    Ok(QsaHalfW {
17491        nh_h,
17492        nkv_h,
17493        hd,
17494        n_rot: attn.rope.dimensions as usize,
17495        rope_base: attn.rope.base,
17496        scale,
17497        proj_b16: need_stack_twin(e, &[&wq_c, &wk_c, &wv_c], hidden, "tp2 qsa proj half")?,
17498        wo_b16: need_twin(e, &wo_c, nh_h * hd, "tp2 qsa o half")?,
17499        q_norm: opt_norm(LayerTensor::QueryNorm)?,
17500        k_norm: opt_norm(LayerTensor::KeyNorm)?,
17501        // Device table on THIS half's card; the width check ran at single-card load.
17502        yarn: build_yarn(e, &attn.rope, None, index)?,
17503    })
17504}
17505
17506/// Build the TP2 shard from a loaded checkpoint (host data), before the single-card
17507/// model consumes it. Card 0 gets its compact split copies on `e0`; card 1 gets its
17508/// replicas + halves on `e1`.
17509pub fn build_tp2_shard(e0: &Engine, e1: &Engine, ckpt: &LoadedCheckpoint) -> Res<Tp2Shard> {
17510    let plan = &ckpt.plan;
17511    let weights = &ckpt.weights;
17512    let hidden = plan.hidden_size as usize;
17513    let vocab = plan.vocab_size as usize;
17514    if vocab % 2 != 0 {
17515        return Err("qwen4exp_gpu tp2: odd vocab".into());
17516    }
17517    let mixer_plan = plan
17518        .exit_mixer
17519        .ok_or("qwen4exp_gpu tp2: missing exit mixer")?;
17520    let streams = mixer_plan.streams as usize;
17521    let rank = mixer_plan.bottleneck_rank as usize;
17522    // Expert placement, read ONCE per shard build (MEMRA_Q4E_EP_MAP; unset = the even
17523    // split control arm). Refusals are load-time, before a single byte is uploaded.
17524    let plan_experts = plan
17525        .layers
17526        .iter()
17527        .find_map(|l| match &l.mlp {
17528            MlpPlan::Moe(m) => Some(m.expert_count as usize),
17529            _ => None,
17530        })
17531        .ok_or("qwen4exp_gpu tp2: no MoE layer in the plan")?;
17532    let placement = match Tp2Placement::from_env(plan_experts)? {
17533        Some(p) => p,
17534        None => Tp2Placement::even(plan_experts),
17535    };
17536    println!(
17537        "# tp2-placement\tstrategy={}\tentry_rank={}\texperts={plan_experts}\tsource={}",
17538        placement.strategy(),
17539        placement.entry_rank(),
17540        placement.source()
17541    );
17542    let mut layers = Vec::with_capacity(plan.layers.len());
17543    for layer in &plan.layers {
17544        let prefix = format!("trunk.layers.{}.", layer.index);
17545        let _g1 = e1.gpu.enter_main()?;
17546        let attn_gate1 = load_gate(
17547            e1,
17548            weights,
17549            &prefix,
17550            "attn_hyper_connection.",
17551            streams,
17552            hidden,
17553            rank,
17554            true,
17555        )?;
17556        let mlp_gate1 = load_gate(
17557            e1,
17558            weights,
17559            &prefix,
17560            "mlp_hyper_connection.",
17561            streams,
17562            hidden,
17563            rank,
17564            true,
17565        )?;
17566        let ple1 = match layer.ple.as_ref() {
17567            None => None,
17568            Some(ple_plan) => Some(build_ple_replica(
17569                e1, weights, &prefix, ple_plan, streams, hidden,
17570            )?),
17571        };
17572        drop(_g1);
17573        let (mixer0, mixer1) = match &layer.attention {
17574            AttentionPlan::GatedDeltaNet(gdn) => {
17575                let _g0 = e0.gpu.enter_main()?;
17576                let m0 = MixerHalfW::Gdn(build_gdn_half(e0, weights, layer.index, gdn, hidden, 0)?);
17577                drop(_g0);
17578                let _g1 = e1.gpu.enter_main()?;
17579                let m1 = MixerHalfW::Gdn(build_gdn_half(e1, weights, layer.index, gdn, hidden, 1)?);
17580                (m0, m1)
17581            }
17582            AttentionPlan::Full(attn) => {
17583                let _g0 = e0.gpu.enter_main()?;
17584                let m0 =
17585                    MixerHalfW::Qsa(build_qsa_half(e0, weights, layer.index, attn, hidden, 0)?);
17586                drop(_g0);
17587                let _g1 = e1.gpu.enter_main()?;
17588                let m1 =
17589                    MixerHalfW::Qsa(build_qsa_half(e1, weights, layer.index, attn, hidden, 1)?);
17590                (m0, m1)
17591            }
17592            other => {
17593                return Err(format!("qwen4exp_gpu tp2: unsupported mixer {other:?}").into());
17594            }
17595        };
17596        // MoE: card1 bank halves from the HOST bank sources; NVFP4 required.
17597        let MlpPlan::Moe(moe_plan) = &layer.mlp else {
17598            return Err("qwen4exp_gpu tp2: non-MoE layer".into());
17599        };
17600        let experts = moe_plan.expert_count as usize;
17601        let ff = moe_plan.expert_intermediate_size as usize;
17602        if experts % 2 != 0 {
17603            return Err("qwen4exp_gpu tp2: odd expert count".into());
17604        }
17605        // Streamed like every other bank consumer: this layer's source is read off the
17606        // mmap here and dropped at the end of the iteration. TP2 therefore reads the bank
17607        // bytes TWICE per load (once here for the card-1 gather, once in
17608        // `from_loaded_checkpoint` for card 0) — a load-time disk/page-cache cost, not a
17609        // numerics or steady-state one, and the price of not holding 72 GB of banks on a
17610        // host that has 180 GB total. Single-pass shard+model build is a named follow-up.
17611        let bank = ckpt.read_bank(layer.index)?;
17612        let bank = &bank;
17613        // The layer's expert placement, resolved ONCE here and carried on the shard so
17614        // the route split at decode/prefill cannot disagree with what was uploaded.
17615        let place = placement.layer(layer.index, experts)?;
17616        // Card 1's bank is a GATHER of the placed expert rows in local-slot order, not a
17617        // contiguous suffix slice. For the even control arm `card1` is exactly
17618        // `e_half..experts` ascending, so the gather concatenates the same bytes the old
17619        // slice handed over, in the same order — bit-identical by construction, which is
17620        // what makes "even split = control arm" a statement about bytes and not a hope.
17621        let upper =
17622            |src: &BankTensorSrc, out_f: usize, in_f: usize, what: &str| -> Res<Nvfp4Half> {
17623                let BankTensorSrc::Nvfp4 {
17624                    codes,
17625                    scales,
17626                    macros,
17627                    ..
17628                } = src
17629                else {
17630                    return Err(format!("qwen4exp_gpu tp2: {what} bank is not NVFP4").into());
17631                };
17632                let wbytes = out_f * in_f / 2;
17633                let sbytes = out_f * in_f / 16;
17634                let need_codes = place.card1.len() * wbytes;
17635                let need_scales = place.card1.len() * sbytes;
17636                if codes.len() < experts * wbytes || scales.len() < experts * sbytes {
17637                    return Err(format!(
17638                        "qwen4exp_gpu tp2: {what} bank is {} code / {} scale bytes, too \
17639                         small for {experts} experts x ({wbytes}, {sbytes})",
17640                        codes.len(),
17641                        scales.len()
17642                    )
17643                    .into());
17644                }
17645                let mut gcodes = Vec::with_capacity(need_codes);
17646                let mut gscales = Vec::with_capacity(need_scales);
17647                let mut gmacros = Vec::with_capacity(place.card1.len());
17648                for &eid in &place.card1 {
17649                    let e = eid as usize;
17650                    gcodes.extend_from_slice(&codes[e * wbytes..(e + 1) * wbytes]);
17651                    gscales.extend_from_slice(&scales[e * sbytes..(e + 1) * sbytes]);
17652                    gmacros.push(macros[e]);
17653                }
17654                Ok(Nvfp4Half {
17655                    codes: e1.htod_bytes(&gcodes)?,
17656                    scales: e1.htod_bytes(&gscales)?,
17657                    macros_dev: e1.htod(&gmacros)?,
17658                })
17659            };
17660        let shared = moe_plan
17661            .shared
17662            .as_ref()
17663            .ok_or("qwen4exp_gpu tp2: missing shared expert")?;
17664        let sff = shared.intermediate_size as usize;
17665        if sff % 2 != 0 {
17666            return Err("qwen4exp_gpu tp2: odd shared ff".into());
17667        }
17668        let sffh = sff / 2;
17669        let sh_gate = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpGate))?;
17670        let sh_up = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpUp))?;
17671        let sh_down = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpDown))?;
17672        let sh_ig = if shared.gated {
17673            Some(expect(
17674                weights,
17675                &layer_id(layer.index, LayerTensor::SharedMlpInputGate),
17676            )?)
17677        } else {
17678            None
17679        };
17680        let moe = {
17681            let _g1 = e1.gpu.enter_main()?;
17682            let gate1 = upper(&bank.gate, ff, hidden, "gate")?;
17683            let up1 = upper(&bank.up, ff, hidden, "up")?;
17684            let down1 = upper(&bank.down, hidden, ff, "down")?;
17685            let shared_gu1_b16 = need_stack_twin(
17686                e1,
17687                &[&sh_gate.data[sffh * hidden..], &sh_up.data[sffh * hidden..]],
17688                hidden,
17689                "tp2 shared gate/up (card1)",
17690            )?;
17691            let down1_c = gather_cols_host(&sh_down.data, hidden, sff, &[(sffh, sffh)]);
17692            let shared_down1 = need_twin(e1, &down1_c, sffh, "tp2 shared down (card1)")?;
17693            let shared_input_gate1 = match sh_ig.as_ref() {
17694                Some(t) => Some(e1.htod(&t.data)?),
17695                None => None,
17696            };
17697            drop(_g1);
17698            let _g0 = e0.gpu.enter_main()?;
17699            let down0_c = gather_cols_host(&sh_down.data, hidden, sff, &[(0, sffh)]);
17700            let shared_down0 = need_twin(e0, &down0_c, sffh, "tp2 shared down (card0)")?;
17701            let shared_gu0_b16 = need_stack_twin(
17702                e0,
17703                &[&sh_gate.data[..sffh * hidden], &sh_up.data[..sffh * hidden]],
17704                hidden,
17705                "tp2 shared gate/up (card0)",
17706            )?;
17707            MoeHalfW {
17708                gate1,
17709                up1,
17710                down1,
17711                shared_down0,
17712                shared_down1,
17713                shared_input_gate1,
17714                shared_gu0_b16,
17715                shared_gu1_b16,
17716            }
17717        };
17718        layers.push(Tp2LayerW {
17719            attn_gate1,
17720            mlp_gate1,
17721            mixer0,
17722            mixer1,
17723            moe,
17724            ple1,
17725            place,
17726        });
17727    }
17728    let _g1 = e1.gpu.enter_main()?;
17729    let exit_gate1 = load_gate(
17730        e1,
17731        weights,
17732        "trunk.hyper_connection_mixer.",
17733        "",
17734        streams,
17735        hidden,
17736        rank,
17737        false,
17738    )?;
17739    let vsplit = vocab / 2;
17740    let head = match weights.get(&TensorId::OutputProjection) {
17741        Some(t) => &t.data,
17742        None => &expect(weights, &TensorId::TokenEmbedding)?.data.clone(),
17743    };
17744    let lm_head1 = need_twin(
17745        e1,
17746        &head[vsplit * hidden..],
17747        hidden,
17748        "tp2 lm_head upper half",
17749    )?;
17750    let stage1 = [e1.zeros(hidden)?, e1.zeros(hidden)?];
17751    let ev1 = [e1.ctx().new_event(None)?, e1.ctx().new_event(None)?];
17752    let stage1_raw = {
17753        let s = e1.gpu.stream();
17754        [stage1[0].device_ptr(&s).0, stage1[1].device_ptr(&s).0]
17755    };
17756    drop(_g1);
17757    let _g0 = e0.gpu.enter_main()?;
17758    let stage0 = [e0.zeros(hidden)?, e0.zeros(hidden)?];
17759    let ev0 = [e0.ctx().new_event(None)?, e0.ctx().new_event(None)?];
17760    let stage0_raw = {
17761        let s = e0.gpu.stream();
17762        [stage0[0].device_ptr(&s).0, stage0[1].device_ptr(&s).0]
17763    };
17764    Ok(Tp2Shard {
17765        layers,
17766        exit_gate1,
17767        lm_head1,
17768        vsplit,
17769        stage0,
17770        stage1,
17771        stage0_raw,
17772        stage1_raw,
17773        ev0,
17774        ev1,
17775    })
17776}
17777
17778impl Qwen4ExpGpu {
17779    /// Load a checkpoint dir for TP2: P2P is enabled, the shard is built from the host
17780    /// checkpoint data (before the single-card model consumes it), then the single-card
17781    /// model loads onto `e0` exactly as `load_from_dir_with`.
17782    pub fn load_from_dir_tp2(
17783        e0: &Engine,
17784        e1: &Engine,
17785        dir: &std::path::Path,
17786        opts: LoadOptions,
17787    ) -> Res<(Self, Tp2Shard)> {
17788        tp2_enable_p2p(e0, e1)?;
17789        let checkpoint = read_checkpoint_with(dir, opts)?;
17790        let shard = build_tp2_shard(e0, e1, &checkpoint)?;
17791        let model = Self::from_loaded_checkpoint(e0, checkpoint)?;
17792        Ok((model, shard))
17793    }
17794
17795    /// One-time single-card -> TP2 half-state migration (host bounce; the state is
17796    /// TP2-latched afterwards). Card 0 keeps the host-side indexer raw-key cache and
17797    /// the single-card PLE history (replicated path); mixer device state splits.
17798    fn tp2_migrate(
17799        &self,
17800        e0: &Engine,
17801        e1: &Engine,
17802        _shard: &Tp2Shard,
17803        state: &mut Qwen4ExpState,
17804    ) -> Res<()> {
17805        let cap = state.capacity;
17806        let pos = state.pos;
17807        let mut tlayers = Vec::with_capacity(self.layers.len());
17808        for (layer, lstate) in self.layers.iter().zip(state.layers.iter_mut()) {
17809            let (m0, m1) = match (&layer.mixer, &mut lstate.mixer) {
17810                (
17811                    MixerW::Gdn(gdn),
17812                    MixerState::Gdn {
17813                        conv,
17814                        state: gstate,
17815                    },
17816                ) => {
17817                    let p = &gdn.plan;
17818                    let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
17819                    let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
17820                    let (nk_h, nv_h) = (nk / 2, nv / 2);
17821                    let pad = p.conv_kernel as usize - 1;
17822                    let conv_dim = 2 * nk * hk + nv * hv;
17823                    let conv_dim_h = 2 * nk_h * hk + nv_h * hv;
17824                    let state_host = {
17825                        let _g = e0.gpu.enter_main()?;
17826                        e0.dtoh(gstate)?
17827                    };
17828                    let conv_host = {
17829                        let _g = e0.gpu.enter_main()?;
17830                        e0.dtoh(conv)?
17831                    };
17832                    let mut halves = Vec::with_capacity(2);
17833                    for d in 0..2 {
17834                        let head_map = tp2_gdn_head_map(d, nk, nv);
17835                        let state_c = gather_rows_host(&state_host, hv * hk, &head_map);
17836                        let mut blocks: Vec<(usize, usize)> = vec![
17837                            (d * nk_h * hk, nk_h * hk),
17838                            (nk * hk + d * nk_h * hk, nk_h * hk),
17839                        ];
17840                        blocks.extend(head_map.iter().map(|&hm| (2 * nk * hk + hm * hv, hv)));
17841                        let conv_c = gather_cols_host(&conv_host, pad, conv_dim, &blocks);
17842                        let e = if d == 0 { e0 } else { e1 };
17843                        let _g = e.gpu.enter_main()?;
17844                        let state_dev = e.htod(&state_c)?;
17845                        let conv_dev = e.htod(&conv_c)?;
17846                        debug_assert_eq!(conv_c.len(), pad * conv_dim_h);
17847                        halves.push(MixerHalfState::Gdn {
17848                            conv: conv_dev,
17849                            state: state_dev,
17850                        });
17851                    }
17852                    let m1 = halves.pop().expect("two halves");
17853                    let m0 = halves.pop().expect("two halves");
17854                    (m0, m1)
17855                }
17856                (MixerW::Qsa(qsa), MixerState::Qsa { kv, .. }) => {
17857                    let nkv = qsa.attn.kv_heads as usize;
17858                    let hd = qsa.attn.key_head_dim as usize;
17859                    let nkv_h = nkv / 2;
17860                    let mut halves = Vec::with_capacity(2);
17861                    match &*kv {
17862                        QsaKvStore::F32 { k, v } => {
17863                            let (k_host, v_host) = {
17864                                let _g = e0.gpu.enter_main()?;
17865                                (
17866                                    e0.dtoh_view(&k.slice(0..pos * nkv * hd))?,
17867                                    e0.dtoh_view(&v.slice(0..pos * nkv * hd))?,
17868                                )
17869                            };
17870                            for d in 0..2 {
17871                                let block = [(d * nkv_h * hd, nkv_h * hd)];
17872                                let k_c = gather_cols_host(&k_host, pos, nkv * hd, &block);
17873                                let v_c = gather_cols_host(&v_host, pos, nkv * hd, &block);
17874                                let e = if d == 0 { e0 } else { e1 };
17875                                let _g = e.gpu.enter_main()?;
17876                                let mut k_dev = e.zeros(cap * nkv_h * hd)?;
17877                                let mut v_dev = e.zeros(cap * nkv_h * hd)?;
17878                                if pos > 0 {
17879                                    let mut kv_view = k_dev.slice_mut(0..pos * nkv_h * hd);
17880                                    e.gpu.stream().memcpy_htod(&k_c, &mut kv_view)?;
17881                                    let mut vv_view = v_dev.slice_mut(0..pos * nkv_h * hd);
17882                                    e.gpu.stream().memcpy_htod(&v_c, &mut vv_view)?;
17883                                }
17884                                halves.push(MixerHalfState::Qsa {
17885                                    kv: QsaKvStore::F32 { k: k_dev, v: v_dev },
17886                                });
17887                            }
17888                        }
17889                        QsaKvStore::Q8Q5 { k, v } => {
17890                            // Quantized halves: each head's hd elems are whole q8/q5
17891                            // 32-blocks (hd % 32 == 0 on real geometry), so the half
17892                            // rows gather BYTES verbatim — no dequant, no requant, the
17893                            // half caches are bit-slices of the single-card cache.
17894                            if hd % 32 != 0 {
17895                                return Err("qwen4exp_gpu tp2: quantized halves need \
17896                                            hd % 32 == 0 (byte-aligned head blocks)"
17897                                    .into());
17898                            }
17899                            let (krb, vrb) = (q8_row_bytes(nkv * hd), q5_row_bytes(nkv * hd));
17900                            let (krb_h, vrb_h) =
17901                                (q8_row_bytes(nkv_h * hd), q5_row_bytes(nkv_h * hd));
17902                            let (k_host, v_host) = {
17903                                let _g = e0.gpu.enter_main()?;
17904                                (
17905                                    e0.dtoh_u8_view(&k.slice(0..pos * krb))?,
17906                                    e0.dtoh_u8_view(&v.slice(0..pos * vrb))?,
17907                                )
17908                            };
17909                            for d in 0..2 {
17910                                let mut k_c = Vec::with_capacity(pos * krb_h);
17911                                let mut v_c = Vec::with_capacity(pos * vrb_h);
17912                                for r in 0..pos {
17913                                    let ko = r * krb + d * krb_h;
17914                                    k_c.extend_from_slice(&k_host[ko..ko + krb_h]);
17915                                    let vo = r * vrb + d * vrb_h;
17916                                    v_c.extend_from_slice(&v_host[vo..vo + vrb_h]);
17917                                }
17918                                let e = if d == 0 { e0 } else { e1 };
17919                                let _g = e.gpu.enter_main()?;
17920                                let mut k_dev = e.alloc_u8(cap * krb_h)?;
17921                                let mut v_dev = e.alloc_u8(cap * vrb_h)?;
17922                                if pos > 0 {
17923                                    let mut kv_view = k_dev.slice_mut(0..pos * krb_h);
17924                                    e.gpu.stream().memcpy_htod(&k_c, &mut kv_view)?;
17925                                    let mut vv_view = v_dev.slice_mut(0..pos * vrb_h);
17926                                    e.gpu.stream().memcpy_htod(&v_c, &mut vv_view)?;
17927                                }
17928                                halves.push(MixerHalfState::Qsa {
17929                                    kv: QsaKvStore::Q8Q5 { k: k_dev, v: v_dev },
17930                                });
17931                            }
17932                        }
17933                    }
17934                    // The single-card cache is DEAD after migration (a TP2-touched
17935                    // state refuses single-card forwards), and at long-context
17936                    // capacities it is the largest allocation on card 0 — stub it.
17937                    {
17938                        let _g = e0.gpu.enter_main()?;
17939                        *kv = match &*kv {
17940                            QsaKvStore::F32 { .. } => QsaKvStore::F32 {
17941                                k: e0.zeros(1)?,
17942                                v: e0.zeros(1)?,
17943                            },
17944                            QsaKvStore::Q8Q5 { .. } => QsaKvStore::Q8Q5 {
17945                                k: e0.alloc_u8(34)?,
17946                                v: e0.alloc_u8(24)?,
17947                            },
17948                        };
17949                    }
17950                    let m1 = halves.pop().expect("two halves");
17951                    let m0 = halves.pop().expect("two halves");
17952                    (m0, m1)
17953                }
17954                _ => return Err("qwen4exp_gpu tp2: layer/state mixer mismatch".into()),
17955            };
17956            // Card-1 PLE history replica (replicated path): copy card0's normed-conv rows.
17957            let ple1 = match lstate.ple.as_ref() {
17958                None => None,
17959                Some(ps) => {
17960                    let mut conv_hist = Vec::with_capacity(ps.conv_hist.len());
17961                    for h in &ps.conv_hist {
17962                        let host = {
17963                            let _g = e0.gpu.enter_main()?;
17964                            e0.dtoh(h)?
17965                        };
17966                        let _g = e1.gpu.enter_main()?;
17967                        conv_hist.push(e1.htod(&host)?);
17968                    }
17969                    Some(PleState {
17970                        conv_hist,
17971                        ngram_ids: Vec::new(),
17972                        ngram_history: Vec::new(),
17973                        ngram_last_eos: -1,
17974                    })
17975                }
17976            };
17977            tlayers.push(Tp2LayerState { m0, m1, ple1 });
17978        }
17979        state.tp2 = Some(Tp2State {
17980            ws1: StepPool::default(),
17981            layers: tlayers,
17982            graphs: Tp2Graphs::default(),
17983            pf_stage0: None,
17984            pf_stage1: None,
17985            pf_stage0_raw: [0; 2],
17986            pf_stage1_raw: [0; 2],
17987            pf_rows: 0,
17988        });
17989        Ok(())
17990    }
17991
17992    /// Per-card GDN split half (t-generic — TP2 prefill runs chunk-sized t):
17993    /// projections, conv, scan, norm+gate, and the compact out-projection PARTIAL
17994    /// (joined by the driver). Mirrors `gdn_forward`.
17995    #[allow(clippy::too_many_arguments)]
17996    fn gdn_forward_half(
17997        &self,
17998        e: &Engine,
17999        ws: &mut StepPool,
18000        eps: f32,
18001        h: &GdnHalfW,
18002        mixed: &CudaSlice<f32>,
18003        hstate: &mut MixerHalfState,
18004        t: usize,
18005    ) -> Res<CudaSlice<f32>> {
18006        let MixerHalfState::Gdn { conv, state } = hstate else {
18007            return Err("qwen4exp_gpu tp2: GDN half bound to non-GDN state".into());
18008        };
18009        let hidden = self.hidden;
18010        let (nk, nv, hk, hv) = (h.nk_h, h.nv_h, h.hk, h.hv);
18011        let kernel = h.kernel;
18012        let pad = kernel - 1;
18013        let conv_dim = 2 * nk * hk + nv * hv;
18014        let mut qkv = ws.take_f32(e, "gdn.qkv", t * conv_dim, 0)?;
18015        let mut z = ws.take_f32(e, "gdn.z", t * nv * hv, 0)?;
18016        let mut beta_raw = ws.take_f32(e, "gdn.beta", t * nv, 0)?;
18017        let mut alpha = ws.take_f32(e, "gdn.alpha", t * nv, 0)?;
18018        // Proj stack (round 4): the 4 half projections in ONE launch (bit-identical
18019        // rows; OFF arm = row-offset views of the same required stack). t == 1 only
18020        // (decode form); chunks run the per-mat row-offset launches.
18021        if t == 1 && proj_stack_on() {
18022            launch_qmatvec_bf16w_multi4(
18023                e,
18024                &h.proj_b16,
18025                mixed,
18026                &[
18027                    (&qkv, conv_dim),
18028                    (&z, nv * hv),
18029                    (&beta_raw, nv),
18030                    (&alpha, nv),
18031                ],
18032                hidden,
18033            )?;
18034        } else {
18035            launch_qmatvec_bf16w_off(e, &h.proj_b16, 0, mixed, &mut qkv, hidden, conv_dim, t)?;
18036            launch_qmatvec_bf16w_off(e, &h.proj_b16, conv_dim, mixed, &mut z, hidden, nv * hv, t)?;
18037            launch_qmatvec_bf16w_off(
18038                e,
18039                &h.proj_b16,
18040                conv_dim + nv * hv,
18041                mixed,
18042                &mut beta_raw,
18043                hidden,
18044                nv,
18045                t,
18046            )?;
18047            launch_qmatvec_bf16w_off(
18048                e,
18049                &h.proj_b16,
18050                conv_dim + nv * hv + nv,
18051                mixed,
18052                &mut alpha,
18053                hidden,
18054                nv,
18055                t,
18056            )?;
18057        }
18058        let mut g_log = ws.take_f32(e, "gdn.glog", t * nv, 0)?;
18059        e.gdn_glog_v(&alpha.slice(0..t * nv), &h.dt, &h.a, &mut g_log, nv, t)?;
18060        ws.put_f32("gdn.alpha", alpha);
18061        let mut conv_out = ws.take_f32(e, "gdn.conv_out", t * conv_dim, 0)?;
18062        launch_dwconv(
18063            e,
18064            &qkv,
18065            conv,
18066            &h.conv_w,
18067            &mut conv_out,
18068            t,
18069            pad,
18070            conv_dim,
18071            kernel,
18072            1,
18073            1,
18074        )?;
18075        let mut o = ws.take_f32(e, "gdn.o", t * nv * hv, 0)?;
18076        let scale = 1.0 / (hk as f32).sqrt();
18077        if t == 1 && gdn_step_on() && hk % 32 == 0 && hk <= 1024 {
18078            launch_gdn_scan_step(
18079                e, &conv_out, &g_log, &beta_raw, state, &mut o, nk, nv, hk, hv, scale, eps,
18080            )?;
18081        } else {
18082            launch_gdn_scan(
18083                e, &conv_out, &g_log, &beta_raw, state, &mut o, nk, nv, hk, hv, t, scale, eps,
18084            )?;
18085        }
18086        ws.put_f32("gdn.conv_out", conv_out);
18087        // conv history <- last `pad` raw qkv rows (zeros keep their place when t < pad).
18088        if t >= pad {
18089            e.copy_range_into(conv, 0, &qkv, (t - pad) * conv_dim, pad * conv_dim)?;
18090        } else {
18091            let keep = pad - t;
18092            let mut tmp = ws.take_f32(e, "gdn.tmp", keep * conv_dim, 0)?;
18093            e.copy_range_into(&mut tmp, 0, conv, t * conv_dim, keep * conv_dim)?;
18094            e.copy_range_into(conv, 0, &tmp, 0, keep * conv_dim)?;
18095            e.copy_range_into(conv, keep * conv_dim, &qkv, 0, t * conv_dim)?;
18096            ws.put_f32("gdn.tmp", tmp);
18097        }
18098        ws.put_f32("gdn.qkv", qkv);
18099        ws.put_f32("gdn.beta", beta_raw);
18100        ws.put_f32("gdn.glog", g_log);
18101        let mut gated = ws.take_f32(e, "gdn.gated", t * nv * hv, 0)?;
18102        match h.gate_activation {
18103            GdnGateActivation::Sigmoid if gdn_fuse_on() => {
18104                launch_rms_sigmul(e, &o, &h.norm, &z, &mut gated, hv, t * nv, eps)?;
18105            }
18106            GdnGateActivation::Sigmoid => {
18107                let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
18108                e.rms_norm(&o, &h.norm, &mut normed, hv, t * nv, eps)?;
18109                let mut sg = ws.take_f32(e, "gdn.sg", t * nv * hv, 0)?;
18110                e.sigmoid(&z, &mut sg, t * nv * hv)?;
18111                e.mul(&normed, &sg, &mut gated, t * nv * hv)?;
18112                ws.put_f32("gdn.sg", sg);
18113                ws.put_f32("gdn.normed", normed);
18114            }
18115            GdnGateActivation::Silu => {
18116                let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
18117                e.rms_norm(&o, &h.norm, &mut normed, hv, t * nv, eps)?;
18118                e.silu_mul(&z, &normed, &mut gated, t * nv * hv)?;
18119                ws.put_f32("gdn.normed", normed);
18120            }
18121        }
18122        let mut partial = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
18123        launch_qmatvec_bf16w(
18124            e,
18125            &h.out_b16,
18126            &gated,
18127            &mut partial,
18128            nv * hv,
18129            hidden,
18130            t,
18131            1,
18132            0,
18133            0,
18134            nv * hv,
18135            0,
18136        )?;
18137        ws.put_f32("gdn.gated", gated);
18138        ws.put_f32("gdn.z", z);
18139        ws.put_f32("gdn.o", o);
18140        Ok(partial)
18141    }
18142
18143    /// Per-card QSA split half UP TO the cache append (t-generic — TP2 prefill runs
18144    /// chunk-sized t); returns (q, gate) for the post-selection half
18145    /// (`qsa_half_attend`). The indexer selection is built once on card 0.
18146    #[allow(clippy::too_many_arguments)]
18147    fn qsa_half_proj(
18148        &self,
18149        e: &Engine,
18150        ws: &mut StepPool,
18151        eps: f32,
18152        h: &QsaHalfW,
18153        mixed: &CudaSlice<f32>,
18154        hstate: &mut MixerHalfState,
18155        base_pos: usize,
18156        t: usize,
18157    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
18158        let MixerHalfState::Qsa { kv } = hstate else {
18159            return Err("qwen4exp_gpu tp2: QSA half bound to non-QSA state".into());
18160        };
18161        let hidden = self.hidden;
18162        let (nh, nkv, hd) = (h.nh_h, h.nkv_h, h.hd);
18163        let mut q_fused = ws.take_f32(e, "qsa.qf", t * 2 * nh * hd, 0)?;
18164        let mut k_new = ws.take_f32(e, "qsa.k", t * nkv * hd, 0)?;
18165        let mut v_new = ws.take_f32(e, "qsa.v", t * nkv * hd, 0)?;
18166        // Proj stack (round 4): wq/wk/wv halves in ONE launch (bit-identical rows; OFF
18167        // arm = row-offset views of the same required stack). t == 1 only (the multi4
18168        // kernel is a decode form); chunks run the per-mat row-offset launches.
18169        if t == 1 && proj_stack_on() {
18170            launch_qmatvec_bf16w_multi4(
18171                e,
18172                &h.proj_b16,
18173                mixed,
18174                &[
18175                    (&q_fused, 2 * nh * hd),
18176                    (&k_new, nkv * hd),
18177                    (&v_new, nkv * hd),
18178                ],
18179                hidden,
18180            )?;
18181        } else {
18182            launch_qmatvec_bf16w_off(
18183                e,
18184                &h.proj_b16,
18185                0,
18186                mixed,
18187                &mut q_fused,
18188                hidden,
18189                2 * nh * hd,
18190                t,
18191            )?;
18192            launch_qmatvec_bf16w_off(
18193                e,
18194                &h.proj_b16,
18195                2 * nh * hd,
18196                mixed,
18197                &mut k_new,
18198                hidden,
18199                nkv * hd,
18200                t,
18201            )?;
18202            launch_qmatvec_bf16w_off(
18203                e,
18204                &h.proj_b16,
18205                2 * nh * hd + nkv * hd,
18206                mixed,
18207                &mut v_new,
18208                hidden,
18209                nkv * hd,
18210                t,
18211            )?;
18212        }
18213        let mut q = ws.take_f32(e, "qsa.q", t * nh * hd, 0)?;
18214        let mut gate = ws.take_f32(e, "qsa.gate", t * nh * hd, 0)?;
18215        e.q_gate_split(&q_fused, &mut q, &mut gate, hd, nh, t)?;
18216        ws.put_f32("qsa.qf", q_fused);
18217        let mut q = if let Some(norm) = h.q_norm.as_ref() {
18218            let mut dst = ws.take_f32(e, "qsa.qn", t * nh * hd, 0)?;
18219            e.rms_norm(&q, norm, &mut dst, hd, t * nh, eps)?;
18220            ws.put_f32("qsa.q", q);
18221            dst
18222        } else {
18223            q
18224        };
18225        let mut k_new = if let Some(norm) = h.k_norm.as_ref() {
18226            let mut dst = ws.take_f32(e, "qsa.kn", t * nkv * hd, 0)?;
18227            e.rms_norm(&k_new, norm, &mut dst, hd, t * nkv, eps)?;
18228            ws.put_f32("qsa.k", k_new);
18229            dst
18230        } else {
18231            k_new
18232        };
18233        let positions: Vec<i32> = (0..t).map(|i| (base_pos + i) as i32).collect();
18234        let pos_dev = ws.take_i32(e, "qsa.pos", &positions, 0)?;
18235        if let Some(yarn) = h.yarn.as_ref() {
18236            e.rope_neox_ffm(
18237                &mut q,
18238                &pos_dev,
18239                hd,
18240                h.n_rot,
18241                nh,
18242                t,
18243                h.rope_base,
18244                1.0,
18245                &yarn.ff,
18246                yarn.mscale,
18247            )?;
18248            e.rope_neox_ffm(
18249                &mut k_new,
18250                &pos_dev,
18251                hd,
18252                h.n_rot,
18253                nkv,
18254                t,
18255                h.rope_base,
18256                1.0,
18257                &yarn.ff,
18258                yarn.mscale,
18259            )?;
18260        } else {
18261            e.rope_neox(&mut q, &pos_dev, hd, h.n_rot, nh, t, h.rope_base, 1.0)?;
18262            e.rope_neox(&mut k_new, &pos_dev, hd, h.n_rot, nkv, t, h.rope_base, 1.0)?;
18263        }
18264        ws.put_i32("qsa.pos", pos_dev);
18265        match kv {
18266            QsaKvStore::F32 { k, v } => {
18267                e.copy_range_into(k, base_pos * nkv * hd, &k_new, 0, t * nkv * hd)?;
18268                e.copy_range_into(v, base_pos * nkv * hd, &v_new, 0, t * nkv * hd)?;
18269            }
18270            QsaKvStore::Q8Q5 { k, v } => {
18271                launch_q4e_kv_append(e, &k_new, &v_new, k, v, base_pos, t, nkv * hd)?;
18272            }
18273        }
18274        ws.put_f32(
18275            if h.k_norm.is_some() {
18276                "qsa.kn"
18277            } else {
18278                "qsa.k"
18279            },
18280            k_new,
18281        );
18282        ws.put_f32("qsa.v", v_new);
18283        Ok((q, gate))
18284    }
18285
18286    /// Post-selection QSA half: BLOCK-LIST SDPA over this card's KV half (bit-identical
18287    /// to the historical masked form on the same selection — the fixture-longatt /
18288    /// arm-0f pedigree — and the only form the quantized halves have), sigmoid gate,
18289    /// and the compact out-projection PARTIAL. t-generic.
18290    #[allow(clippy::too_many_arguments)]
18291    fn qsa_half_attend(
18292        &self,
18293        e: &Engine,
18294        ws: &mut StepPool,
18295        h: &QsaHalfW,
18296        hstate: &MixerHalfState,
18297        q: CudaSlice<f32>,
18298        gate: CudaSlice<f32>,
18299        pos_dev: &CudaSlice<i32>,
18300        meta_dev: &CudaSlice<i32>,
18301        max_count: usize,
18302        t: usize,
18303        t_kv: usize,
18304    ) -> Res<CudaSlice<f32>> {
18305        let MixerHalfState::Qsa { kv } = hstate else {
18306            return Err("qwen4exp_gpu tp2: QSA half bound to non-QSA state".into());
18307        };
18308        let hidden = self.hidden;
18309        let (nh, nkv, hd) = (h.nh_h, h.nkv_h, h.hd);
18310        let mut attended = ws.take_f32(e, "qsa.att", t * nh * hd, 0)?;
18311        match kv {
18312            QsaKvStore::F32 { k, v } => {
18313                let k_view = k.slice(0..t_kv * nkv * hd);
18314                let v_view = v.slice(0..t_kv * nkv * hd);
18315                launch_sdpa_blocklist(
18316                    e,
18317                    &q,
18318                    &k_view,
18319                    &v_view,
18320                    &mut attended,
18321                    pos_dev,
18322                    meta_dev,
18323                    hd,
18324                    nh,
18325                    nkv,
18326                    t,
18327                    max_count,
18328                    h.scale,
18329                )?;
18330            }
18331            QsaKvStore::Q8Q5 { k, v } => {
18332                launch_q4e_sdpa_blocklist_q8q5(
18333                    e,
18334                    &q,
18335                    k,
18336                    v,
18337                    &mut attended,
18338                    pos_dev,
18339                    meta_dev,
18340                    hd,
18341                    nh,
18342                    nkv,
18343                    t,
18344                    max_count,
18345                    h.scale,
18346                )?;
18347            }
18348        }
18349        ws.put_f32(
18350            if h.q_norm.is_some() {
18351                "qsa.qn"
18352            } else {
18353                "qsa.q"
18354            },
18355            q,
18356        );
18357        let mut sg = ws.take_f32(e, "qsa.sg", t * nh * hd, 0)?;
18358        e.sigmoid(&gate, &mut sg, t * nh * hd)?;
18359        let mut gated = ws.take_f32(e, "qsa.gated", t * nh * hd, 0)?;
18360        e.mul(&attended, &sg, &mut gated, t * nh * hd)?;
18361        let mut partial = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
18362        launch_qmatvec_bf16w(
18363            e,
18364            &h.wo_b16,
18365            &gated,
18366            &mut partial,
18367            nh * hd,
18368            hidden,
18369            t,
18370            1,
18371            0,
18372            0,
18373            nh * hd,
18374            0,
18375        )?;
18376        ws.put_f32("qsa.sg", sg);
18377        ws.put_f32("qsa.gated", gated);
18378        ws.put_f32("qsa.att", attended);
18379        ws.put_f32("qsa.gate", gate);
18380        Ok(partial)
18381    }
18382
18383    /// The QSA indexer host twin factored for TP2 (runs on card 0's projection; the mask
18384    /// bytes feed BOTH cards' masked SDPA halves).
18385    // dead_code: bring-up scaffolding the in-flight qwen4exp lanes still call; not deleted in
18386    // the clippy-zero lane (bit-neutral by construction).
18387    #[allow(dead_code)]
18388    #[allow(clippy::too_many_arguments)]
18389    fn qsa_indexer_mask(
18390        &self,
18391        e: &Engine,
18392        ws: &mut StepPool,
18393        qsa: &QsaW,
18394        eps: f32,
18395        mixed: &CudaSlice<f32>,
18396        raw_keys: &mut IdxRawCache,
18397        pooled_keys: &mut Vec<f32>,
18398        base_pos: usize,
18399    ) -> Res<Vec<u8>> {
18400        let overlay = &qsa.overlay;
18401        let idx_dim = overlay.head_dim as usize;
18402        let qk_width = (overlay.query_heads as usize + overlay.kv_heads as usize) * idx_dim;
18403        let hidden = self.hidden;
18404        let mut idx_proj = ws.take_f32(e, "qsa.idxp", qk_width, 0)?;
18405        e.linear_device_into(mixed, &qsa.idx_proj, &mut idx_proj, 1, hidden, qk_width)?;
18406        let rows = e.dtoh_view(&idx_proj.slice(0..qk_width))?;
18407        ws.put_f32("qsa.idxp", idx_proj);
18408        raw_keys.append_rows_f32(
18409            &rows[overlay.query_heads as usize * idx_dim..qk_width],
18410            1,
18411            idx_dim,
18412        );
18413        indexer_mask_rows(
18414            overlay,
18415            qsa.attn.rope.base,
18416            qsa.yarn.as_ref().map(|y| (y.ff_host.as_slice(), y.mscale)),
18417            eps,
18418            &qsa.idx_q_norm,
18419            &qsa.idx_k_norm,
18420            &rows,
18421            raw_keys,
18422            pooled_keys,
18423            base_pos,
18424            1,
18425            base_pos + 1,
18426            0,
18427        )
18428    }
18429
18430    /// Shared-expert half on one card: gate/up rows (card 0 = the resident full twins'
18431    /// row prefix; card 1 = its suffix copies), silu, compact down columns. Returns the
18432    /// down PARTIAL and the (replicated-deterministic) input-gate scalar buffer.
18433    #[allow(clippy::too_many_arguments)]
18434    fn tp2_shared_half(
18435        &self,
18436        e: &Engine,
18437        ws: &mut StepPool,
18438        gu_b16: &CudaSlice<u8>,
18439        down_b16: &CudaSlice<u8>,
18440        input_gate: Option<&CudaSlice<f32>>,
18441        mixed: &CudaSlice<f32>,
18442        sffh: usize,
18443        t: usize,
18444    ) -> Res<(CudaSlice<f32>, Option<CudaSlice<f32>>)> {
18445        let hidden = self.hidden;
18446        let mut sh_gate = ws.take_f32(e, "moe.sh_gate", t * sffh, 0)?;
18447        let mut sh_up = ws.take_f32(e, "moe.sh_up", t * sffh, 0)?;
18448        // Proj stack (round 4): shared gate/up halves in ONE launch (bit-identical rows;
18449        // OFF arm = row-offset views of the same required stack). t == 1 only.
18450        if t == 1 && proj_stack_on() {
18451            launch_qmatvec_bf16w_multi4(
18452                e,
18453                gu_b16,
18454                mixed,
18455                &[(&sh_gate, sffh), (&sh_up, sffh)],
18456                hidden,
18457            )?;
18458        } else {
18459            launch_qmatvec_bf16w_off(e, gu_b16, 0, mixed, &mut sh_gate, hidden, sffh, t)?;
18460            launch_qmatvec_bf16w_off(e, gu_b16, sffh, mixed, &mut sh_up, hidden, sffh, t)?;
18461        }
18462        let mut act = ws.take_f32(e, "moe.sh_act", t * sffh, 0)?;
18463        e.silu_mul(&sh_gate, &sh_up, &mut act, t * sffh)?;
18464        let mut shared = ws.take_f32(e, "moe.sh_down", t * hidden, 0)?;
18465        launch_qmatvec_bf16w(
18466            e,
18467            down_b16,
18468            &act,
18469            &mut shared,
18470            sffh,
18471            hidden,
18472            t,
18473            1,
18474            0,
18475            0,
18476            sffh,
18477            0,
18478        )?;
18479        let g = match input_gate {
18480            Some(w) => {
18481                let mut g = ws.take_f32(e, "moe.g", t, 0)?;
18482                e.sigmoid_dot_rows_into(mixed, w, &mut g, hidden, t)?;
18483                Some(g)
18484            }
18485            None => None,
18486        };
18487        ws.put_f32("moe.sh_gate", sh_gate);
18488        ws.put_f32("moe.sh_up", sh_up);
18489        ws.put_f32("moe.sh_act", act);
18490        Ok((shared, g))
18491    }
18492}
18493
18494impl Qwen4ExpGpu {
18495    /// One TP2 decode step (t == 1, eager issue — decode graphs stay off in TP2; the
18496    /// joins are the schedule). Prefill stays single-card; the first call migrates the
18497    /// state (one-way latch). Requires the bf16-trunk + fused-gate seams ON (replicated
18498    /// compute must be deterministic-kernel-only).
18499    pub fn decode_step_tp2(
18500        &self,
18501        e0: &Engine,
18502        e1: &Engine,
18503        shard: &Tp2Shard,
18504        token: u32,
18505        state: &mut Qwen4ExpState,
18506    ) -> Res<Vec<f32>> {
18507        if !trunk_bf16_on() || !hc_fused_gate_on() {
18508            return Err(
18509                "qwen4exp_gpu tp2: requires set_trunk_bf16(true) and set_hc_fused_gate(true) \
18510                 (replicated compute must run deterministic kernels)"
18511                    .into(),
18512            );
18513        }
18514        if state.pos + 1 > state.capacity {
18515            return Err("qwen4exp_gpu: state capacity exceeded".into());
18516        }
18517        if state.tp2.is_none() {
18518            self.tp2_migrate(e0, e1, shard, state)?;
18519            state.graphs = StepGraphs::default();
18520        }
18521        let hidden = self.hidden;
18522        let vocab = self.vocab;
18523        let vsplit = shard.vsplit;
18524        let base_pos = state.pos;
18525        let reserve = state.reserve;
18526        state.tokens.push(token);
18527        let Qwen4ExpState {
18528            ref tokens,
18529            ws: ref mut ws0,
18530            ref mut tp2,
18531            layers: ref mut lstates,
18532            ..
18533        } = *state;
18534        let Tp2State {
18535            ws1,
18536            layers: tlayers,
18537            graphs: tgraphs,
18538            ..
18539        } = tp2.as_mut().expect("migrated above");
18540        // Slot RESERVE unit: reserve-derived, NOT capacity — a long-context TP2 state
18541        // (1M rows) must not reserve capacity-sized plane slots (~10 GB each).
18542        let cap = reserve.max(1);
18543
18544        // Entry: one embed row, H2D to both cards' plane slots (replicated planes).
18545        let token_us = token as usize;
18546        if token_us >= vocab {
18547            return Err(format!("qwen4exp_gpu: token {token_us} out of range").into());
18548        }
18549        let embedded = &self.embed_host[token_us * hidden..(token_us + 1) * hidden];
18550        let mut planes1: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
18551        let ptrs1 = {
18552            let _g = e1.gpu.enter_main()?;
18553            let embedded_dev = ws1.take_f32_h2d(e1, "entry.embed", embedded, cap * hidden)?;
18554            for s in 0..self.streams {
18555                let mut plane = ws1.take_f32(e1, PLANE_SLOTS[s], hidden, cap * hidden)?;
18556                e1.copy_into(&mut plane, 0, &embedded_dev, hidden)?;
18557                planes1.push(plane);
18558            }
18559            ws1.put_f32("entry.embed", embedded_dev);
18560            let ptr_vals: Vec<u64> = {
18561                let stream = e1.gpu.stream();
18562                planes1.iter().map(|p| p.device_ptr(&stream).0).collect()
18563            };
18564            ws1.take_u64_h2d(e1, "hc.ptrs", &ptr_vals, 0)?
18565        };
18566        let mut planes0: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
18567        let ptrs0 = {
18568            let _g = e0.gpu.enter_main()?;
18569            let embedded_dev = ws0.take_f32_h2d(e0, "entry.embed", embedded, cap * hidden)?;
18570            for s in 0..self.streams {
18571                let mut plane = ws0.take_f32(e0, PLANE_SLOTS[s], hidden, cap * hidden)?;
18572                e0.copy_into(&mut plane, 0, &embedded_dev, hidden)?;
18573                planes0.push(plane);
18574            }
18575            ws0.put_f32("entry.embed", embedded_dev);
18576            let ptr_vals: Vec<u64> = {
18577                let stream = e0.gpu.stream();
18578                planes0.iter().map(|p| p.device_ptr(&stream).0).collect()
18579            };
18580            ws0.take_u64_h2d(e0, "hc.ptrs", &ptr_vals, 0)?
18581        };
18582
18583        // Segment-graph mode (the single-card StepGraphs pattern per rank): first TP2
18584        // step runs fully eager to park every slot; captures are lazy on the next step.
18585        let use_graphs = decode_graphs_on() && step_ws_on();
18586        let graphs_live = use_graphs && tgraphs.warm;
18587        if use_graphs && !tgraphs.warm {
18588            tgraphs.warm = true;
18589        }
18590        if graphs_live && tgraphs.a[0].len() != self.layers.len() {
18591            for d in 0..2 {
18592                tgraphs.a[d] = (0..self.layers.len()).map(|_| None).collect();
18593                tgraphs.b[d] = (0..self.layers.len()).map(|_| None).collect();
18594                tgraphs.c[d] = (0..self.layers.len()).map(|_| None).collect();
18595                tgraphs.d[d] = (0..self.layers.len()).map(|_| None).collect();
18596            }
18597        }
18598        for (li, layer) in self.layers.iter().enumerate() {
18599            let lstate = &mut lstates[li];
18600            let tw = &shard.layers[li];
18601            let ts = &mut tlayers[li];
18602            let eps_a = layer.eps_attn;
18603            let eps_m = layer.eps_mlp;
18604            let moe = &layer.moe;
18605            let ff = moe.plan.expert_intermediate_size as usize;
18606            let experts = moe.plan.expert_count as usize;
18607            let selected = moe.plan.experts_per_token as usize;
18608            let sff = moe
18609                .plan
18610                .shared
18611                .as_ref()
18612                .map(|s| s.intermediate_size as usize)
18613                .unwrap_or(0);
18614            let sffh = sff / 2;
18615
18616            // ---- phase 1: attn gate + mixer half + join push (parity 0), per card ----
18617            match (&layer.mixer, &tw.mixer0, &tw.mixer1) {
18618                (MixerW::Gdn(_), MixerHalfW::Gdn(h0), MixerHalfW::Gdn(h1)) => {
18619                    {
18620                        let _g = e1.gpu.enter_main()?;
18621                        if let (Some(ple1), Some(ps1)) = (tw.ple1.as_ref(), ts.ple1.as_mut()) {
18622                            let table = &layer.ple.as_ref().expect("ple plan").table;
18623                            self.ple_block(
18624                                e1,
18625                                layer,
18626                                ple1,
18627                                table,
18628                                ps1,
18629                                &mut planes1,
18630                                tokens,
18631                                1,
18632                                false,
18633                                None,
18634                            )?;
18635                        }
18636                        if graphs_live && layer.ple.is_none() {
18637                            if tgraphs.a[1][li].is_none() {
18638                                tgraphs.a[1][li] =
18639                                    Some(e1.capture_graph_retained_nowarm(|eng| {
18640                                        self.tp2_gdn_seg_a(
18641                                            eng,
18642                                            ws1,
18643                                            &ptrs1,
18644                                            &tw.attn_gate1,
18645                                            h1,
18646                                            &mut ts.m1,
18647                                            &planes1,
18648                                            eps_a,
18649                                            shard.stage0_raw[0],
18650                                        )
18651                                    })?);
18652                            }
18653                            tgraphs.a[1][li].as_ref().unwrap().0.launch()?;
18654                        } else {
18655                            self.tp2_gdn_seg_a(
18656                                e1,
18657                                ws1,
18658                                &ptrs1,
18659                                &tw.attn_gate1,
18660                                h1,
18661                                &mut ts.m1,
18662                                &planes1,
18663                                eps_a,
18664                                shard.stage0_raw[0],
18665                            )?;
18666                        }
18667                        shard.ev1[0].record(&e1.gpu.stream())?;
18668                    }
18669                    {
18670                        let _g = e0.gpu.enter_main()?;
18671                        if let (Some(ple), Some(ps)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
18672                            self.ple_block(
18673                                e0,
18674                                layer,
18675                                ple,
18676                                &ple.table,
18677                                ps,
18678                                &mut planes0,
18679                                tokens,
18680                                1,
18681                                false,
18682                                None,
18683                            )?;
18684                        }
18685                        if graphs_live && layer.ple.is_none() {
18686                            if tgraphs.a[0][li].is_none() {
18687                                tgraphs.a[0][li] =
18688                                    Some(e0.capture_graph_retained_nowarm(|eng| {
18689                                        self.tp2_gdn_seg_a(
18690                                            eng,
18691                                            ws0,
18692                                            &ptrs0,
18693                                            &layer.attn_gate,
18694                                            h0,
18695                                            &mut ts.m0,
18696                                            &planes0,
18697                                            eps_a,
18698                                            shard.stage1_raw[0],
18699                                        )
18700                                    })?);
18701                            }
18702                            tgraphs.a[0][li].as_ref().unwrap().0.launch()?;
18703                        } else {
18704                            self.tp2_gdn_seg_a(
18705                                e0,
18706                                ws0,
18707                                &ptrs0,
18708                                &layer.attn_gate,
18709                                h0,
18710                                &mut ts.m0,
18711                                &planes0,
18712                                eps_a,
18713                                shard.stage1_raw[0],
18714                            )?;
18715                        }
18716                        shard.ev0[0].record(&e0.gpu.stream())?;
18717                    }
18718                }
18719                (MixerW::Qsa(qsa), MixerHalfW::Qsa(h0), MixerHalfW::Qsa(h1)) => {
18720                    // QSA stays eager: the indexer selection and the per-step t_kv
18721                    // launch shape are not capturable (single-card precedent).
18722                    let (q1, g1, inj1) = {
18723                        let _g = e1.gpu.enter_main()?;
18724                        let (mixed1, inj1) = self.gate_read(
18725                            e1,
18726                            ws1,
18727                            &ptrs1,
18728                            &tw.attn_gate1,
18729                            &planes1,
18730                            1,
18731                            eps_a,
18732                            false,
18733                        )?;
18734                        let (q1, g1) = self
18735                            .qsa_half_proj(e1, ws1, eps_a, h1, &mixed1, &mut ts.m1, base_pos, 1)?;
18736                        ws1.put_f32("hc.mixed", mixed1);
18737                        (q1, g1, inj1)
18738                    };
18739                    // The selection runs ONCE on card 0 (the single-card machinery:
18740                    // idxcache device raw cache, device scorer, audit twin) and its
18741                    // position lists feed BOTH cards' block-list halves — bit-identical
18742                    // to the historical masked form on the same selection.
18743                    let (sels, q0, g0, inj0) = {
18744                        let _g = e0.gpu.enter_main()?;
18745                        let (mixed0, inj0) = self.gate_read(
18746                            e0,
18747                            ws0,
18748                            &ptrs0,
18749                            &layer.attn_gate,
18750                            &planes0,
18751                            1,
18752                            eps_a,
18753                            false,
18754                        )?;
18755                        let (q0, g0) = self
18756                            .qsa_half_proj(e0, ws0, eps_a, h0, &mixed0, &mut ts.m0, base_pos, 1)?;
18757                        let MixerState::Qsa {
18758                            raw_keys,
18759                            pooled_keys,
18760                            pooled_dev,
18761                            pooled_dev_rows,
18762                            raw_dev,
18763                            raw_dev_rows,
18764                            idx_audit,
18765                            ..
18766                        } = &mut lstate.mixer
18767                        else {
18768                            return Err("qwen4exp_gpu tp2: QSA layer without raw-key cache".into());
18769                        };
18770                        let sels = self.qsa_update_select(
18771                            e0,
18772                            ws0,
18773                            qsa,
18774                            eps_a,
18775                            &mixed0,
18776                            raw_keys,
18777                            pooled_keys,
18778                            pooled_dev,
18779                            pooled_dev_rows,
18780                            raw_dev,
18781                            raw_dev_rows,
18782                            idx_audit.as_mut(),
18783                            base_pos,
18784                            1,
18785                            0,
18786                            false,
18787                        )?;
18788                        ws0.put_f32("hc.mixed", mixed0);
18789                        (sels, q0, g0, inj0)
18790                    };
18791                    let t_kv = base_pos + 1;
18792                    let block_size = qsa.overlay.block_size as usize;
18793                    let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
18794                    {
18795                        let _g = e1.gpu.enter_main()?;
18796                        let pos_dev = ws1.take_i32(e1, "qsa.selpos", &pos_flat, 0)?;
18797                        let meta_dev = ws1.take_i32(e1, "qsa.selmeta", &meta, 0)?;
18798                        let p1 = self.qsa_half_attend(
18799                            e1, ws1, h1, &ts.m1, q1, g1, &pos_dev, &meta_dev, max_count, 1, t_kv,
18800                        )?;
18801                        ws1.put_i32("qsa.selpos", pos_dev);
18802                        ws1.put_i32("qsa.selmeta", meta_dev);
18803                        launch_push(e1, &p1, shard.stage0_raw[0], hidden)?;
18804                        ws1.put_f32("mixer.out", p1);
18805                        put_inject(ws1, inj1);
18806                        shard.ev1[0].record(&e1.gpu.stream())?;
18807                    }
18808                    {
18809                        let _g = e0.gpu.enter_main()?;
18810                        let pos_dev = ws0.take_i32(e0, "qsa.selpos", &pos_flat, 0)?;
18811                        let meta_dev = ws0.take_i32(e0, "qsa.selmeta", &meta, 0)?;
18812                        let p0 = self.qsa_half_attend(
18813                            e0, ws0, h0, &ts.m0, q0, g0, &pos_dev, &meta_dev, max_count, 1, t_kv,
18814                        )?;
18815                        ws0.put_i32("qsa.selpos", pos_dev);
18816                        ws0.put_i32("qsa.selmeta", meta_dev);
18817                        launch_push(e0, &p0, shard.stage1_raw[0], hidden)?;
18818                        ws0.put_f32("mixer.out", p0);
18819                        put_inject(ws0, inj0);
18820                        shard.ev0[0].record(&e0.gpu.stream())?;
18821                    }
18822                }
18823                _ => return Err("qwen4exp_gpu tp2: mixer/shard shape mismatch".into()),
18824            }
18825            {
18826                let _g = e0.gpu.enter_main()?;
18827                e0.gpu.stream().wait(&shard.ev1[0])?;
18828            }
18829            {
18830                let _g = e1.gpu.enter_main()?;
18831                e1.gpu.stream().wait(&shard.ev0[0])?;
18832            }
18833
18834            // ---- phase 2: join add + write + mlp gate (+ card1 shared prestage) ----
18835            {
18836                let _g = e1.gpu.enter_main()?;
18837                if graphs_live {
18838                    if tgraphs.b[1][li].is_none() {
18839                        tgraphs.b[1][li] = Some(e1.capture_graph_retained_nowarm(|eng| {
18840                            self.tp2_seg_b(
18841                                eng,
18842                                ws1,
18843                                &ptrs1,
18844                                &tw.mlp_gate1,
18845                                &mut planes1,
18846                                &shard.stage1[0],
18847                                false,
18848                                eps_m,
18849                                Some((
18850                                    &tw.moe.shared_gu1_b16,
18851                                    &tw.moe.shared_down1,
18852                                    tw.moe.shared_input_gate1.as_ref(),
18853                                    sffh,
18854                                )),
18855                            )
18856                        })?);
18857                    }
18858                    tgraphs.b[1][li].as_ref().unwrap().0.launch()?;
18859                } else {
18860                    self.tp2_seg_b(
18861                        e1,
18862                        ws1,
18863                        &ptrs1,
18864                        &tw.mlp_gate1,
18865                        &mut planes1,
18866                        &shard.stage1[0],
18867                        false,
18868                        eps_m,
18869                        Some((
18870                            &tw.moe.shared_gu1_b16,
18871                            &tw.moe.shared_down1,
18872                            tw.moe.shared_input_gate1.as_ref(),
18873                            sffh,
18874                        )),
18875                    )?;
18876                }
18877            }
18878            {
18879                let _g = e0.gpu.enter_main()?;
18880                if graphs_live {
18881                    if tgraphs.b[0][li].is_none() {
18882                        tgraphs.b[0][li] = Some(e0.capture_graph_retained_nowarm(|eng| {
18883                            self.tp2_seg_b(
18884                                eng,
18885                                ws0,
18886                                &ptrs0,
18887                                &layer.mlp_gate,
18888                                &mut planes0,
18889                                &shard.stage0[0],
18890                                true,
18891                                eps_m,
18892                                None,
18893                            )
18894                        })?);
18895                    }
18896                    tgraphs.b[0][li].as_ref().unwrap().0.launch()?;
18897                } else {
18898                    self.tp2_seg_b(
18899                        e0,
18900                        ws0,
18901                        &ptrs0,
18902                        &layer.mlp_gate,
18903                        &mut planes0,
18904                        &shard.stage0[0],
18905                        true,
18906                        eps_m,
18907                        None,
18908                    )?;
18909                }
18910            }
18911
18912            // ---- phase 3: router host boundary + count-gated MoE tail (graphable via the
18913            // pack blob: fixed launch shapes, live slot count on device) + join (parity 1) ----
18914            let route = {
18915                let _g = e0.gpu.enter_main()?;
18916                let mixed0 = ws0.take_f32(e0, "hc.mixed", hidden, 0)?;
18917                let mut router_out = ws0.take_f32(e0, "moe.router", experts, 0)?;
18918                let none: Option<CudaSlice<u8>> = None;
18919                let rb = if router_bf16_on() {
18920                    &moe.router_b16
18921                } else {
18922                    &none
18923                };
18924                linear_trunk_into(
18925                    e0,
18926                    &moe.router,
18927                    rb,
18928                    &mixed0,
18929                    &mut router_out,
18930                    1,
18931                    hidden,
18932                    experts,
18933                )?;
18934                let logits = e0.dtoh_view(&router_out.slice(0..experts))?;
18935                ws0.put_f32("moe.router", router_out);
18936                ws0.put_f32("hc.mixed", mixed0);
18937                host_route_softmax_topk(&logits, selected)
18938            };
18939            // Split by PLACEMENT (even split when no map is loaded — then rank() is
18940            // `expert >= experts/2` and local() is `expert - experts/2`, i.e. exactly the
18941            // arithmetic this site used before the seam existed).
18942            let place = &tw.place;
18943            let mut sel0: Vec<i32> = Vec::with_capacity(selected);
18944            let mut w0: Vec<f32> = Vec::with_capacity(selected);
18945            let mut sel1: Vec<i32> = Vec::with_capacity(selected);
18946            let mut w1: Vec<f32> = Vec::with_capacity(selected);
18947            for &(expert, weight) in &route {
18948                if place.rank(expert) == 0 {
18949                    sel0.push(place.local(expert) as i32);
18950                    w0.push(weight);
18951                } else {
18952                    sel1.push(place.local(expert) as i32);
18953                    w1.push(weight);
18954                }
18955            }
18956            {
18957                // Route trace + per-rank engagement, in the decode shape (t == 1). The
18958                // trace rides the readback the host router twin already did.
18959                let r0: Vec<Vec<(usize, f32)>> = vec![
18960                    sel0.iter()
18961                        .zip(&w0)
18962                        .map(|(&s, &w)| (s as usize, w))
18963                        .collect(),
18964                ];
18965                let r1: Vec<Vec<(usize, f32)>> = vec![
18966                    sel1.iter()
18967                        .zip(&w1)
18968                        .map(|(&s, &w)| (s as usize, w))
18969                        .collect(),
18970                ];
18971                tp2_count_split(&r0, &r1);
18972                trace_moe_routes(layer.index, 1, std::slice::from_ref(&route));
18973            }
18974            match tp2_gate_red()? {
18975                Tp2GateRed::None => {}
18976                // Drop the peer's routed contribution entirely.
18977                Tp2GateRed::SkipPeerMoe => {
18978                    sel1.clear();
18979                    w1.clear();
18980                }
18981                // Send peer-owned experts to card 0's bank at their peer LOCAL slot: the
18982                // plausible off-by-remap bug — right magnitudes, wrong experts.
18983                Tp2GateRed::PeerLocalIds => {
18984                    sel0.extend(sel1.drain(..));
18985                    w0.extend(w1.drain(..));
18986                }
18987                Tp2GateRed::ReverseePeerWeights => w1.reverse(),
18988            }
18989            let max_sel = selected;
18990            {
18991                let _g = e1.gpu.enter_main()?;
18992                ws1.upsert_u8(e1, "moe.pack", &tp2_pack_bytes(&sel1, &w1, max_sel), 0)?;
18993                if graphs_live {
18994                    if tgraphs.c[1][li].is_none() {
18995                        tgraphs.c[1][li] = Some(e1.capture_graph_retained_nowarm(|eng| {
18996                            self.tp2_seg_c(
18997                                eng,
18998                                ws1,
18999                                (
19000                                    &tw.moe.gate1.codes,
19001                                    &tw.moe.gate1.scales,
19002                                    &tw.moe.gate1.macros_dev,
19003                                ),
19004                                (
19005                                    &tw.moe.up1.codes,
19006                                    &tw.moe.up1.scales,
19007                                    &tw.moe.up1.macros_dev,
19008                                ),
19009                                (
19010                                    &tw.moe.down1.codes,
19011                                    &tw.moe.down1.scales,
19012                                    &tw.moe.down1.macros_dev,
19013                                ),
19014                                ff,
19015                                max_sel,
19016                                None,
19017                                tw.moe.shared_input_gate1.is_some(),
19018                                shard.stage0_raw[1],
19019                            )
19020                        })?);
19021                    }
19022                    tgraphs.c[1][li].as_ref().unwrap().0.launch()?;
19023                } else {
19024                    self.tp2_seg_c(
19025                        e1,
19026                        ws1,
19027                        (
19028                            &tw.moe.gate1.codes,
19029                            &tw.moe.gate1.scales,
19030                            &tw.moe.gate1.macros_dev,
19031                        ),
19032                        (
19033                            &tw.moe.up1.codes,
19034                            &tw.moe.up1.scales,
19035                            &tw.moe.up1.macros_dev,
19036                        ),
19037                        (
19038                            &tw.moe.down1.codes,
19039                            &tw.moe.down1.scales,
19040                            &tw.moe.down1.macros_dev,
19041                        ),
19042                        ff,
19043                        max_sel,
19044                        None,
19045                        tw.moe.shared_input_gate1.is_some(),
19046                        shard.stage0_raw[1],
19047                    )?;
19048                }
19049                shard.ev1[1].record(&e1.gpu.stream())?;
19050            }
19051            {
19052                let _g = e0.gpu.enter_main()?;
19053                let (
19054                    BankHalf::Nvfp4 {
19055                        codes: gc,
19056                        scales: gs,
19057                        macros_dev: gm,
19058                        ..
19059                    },
19060                    BankHalf::Nvfp4 {
19061                        codes: uc,
19062                        scales: us,
19063                        macros_dev: um,
19064                        ..
19065                    },
19066                    BankHalf::Nvfp4 {
19067                        codes: dc,
19068                        scales: ds,
19069                        macros_dev: dm,
19070                        ..
19071                    },
19072                ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
19073                else {
19074                    return Err("qwen4exp_gpu tp2: card0 bank is not NVFP4".into());
19075                };
19076                ws0.upsert_u8(e0, "moe.pack", &tp2_pack_bytes(&sel0, &w0, max_sel), 0)?;
19077                if graphs_live {
19078                    if tgraphs.c[0][li].is_none() {
19079                        tgraphs.c[0][li] = Some(e0.capture_graph_retained_nowarm(|eng| {
19080                            self.tp2_seg_c(
19081                                eng,
19082                                ws0,
19083                                (gc, gs, gm),
19084                                (uc, us, um),
19085                                (dc, ds, dm),
19086                                ff,
19087                                max_sel,
19088                                Some((
19089                                    &tw.moe.shared_gu0_b16,
19090                                    &tw.moe.shared_down0,
19091                                    moe.shared_input_gate.as_ref(),
19092                                    sffh,
19093                                )),
19094                                false,
19095                                shard.stage1_raw[1],
19096                            )
19097                        })?);
19098                    }
19099                    tgraphs.c[0][li].as_ref().unwrap().0.launch()?;
19100                } else {
19101                    self.tp2_seg_c(
19102                        e0,
19103                        ws0,
19104                        (gc, gs, gm),
19105                        (uc, us, um),
19106                        (dc, ds, dm),
19107                        ff,
19108                        max_sel,
19109                        Some((
19110                            &tw.moe.shared_gu0_b16,
19111                            &tw.moe.shared_down0,
19112                            moe.shared_input_gate.as_ref(),
19113                            sffh,
19114                        )),
19115                        false,
19116                        shard.stage1_raw[1],
19117                    )?;
19118                }
19119                shard.ev0[1].record(&e0.gpu.stream())?;
19120            }
19121            {
19122                let _g = e1.gpu.enter_main()?;
19123                e1.gpu.stream().wait(&shard.ev0[1])?;
19124                if graphs_live {
19125                    if tgraphs.d[1][li].is_none() {
19126                        tgraphs.d[1][li] = Some(e1.capture_graph_retained_nowarm(|eng| {
19127                            self.tp2_seg_d(eng, ws1, &ptrs1, &mut planes1, &shard.stage1[1], false)
19128                        })?);
19129                    }
19130                    tgraphs.d[1][li].as_ref().unwrap().0.launch()?;
19131                } else {
19132                    self.tp2_seg_d(e1, ws1, &ptrs1, &mut planes1, &shard.stage1[1], false)?;
19133                }
19134            }
19135            {
19136                let _g = e0.gpu.enter_main()?;
19137                e0.gpu.stream().wait(&shard.ev1[1])?;
19138                if graphs_live {
19139                    if tgraphs.d[0][li].is_none() {
19140                        tgraphs.d[0][li] = Some(e0.capture_graph_retained_nowarm(|eng| {
19141                            self.tp2_seg_d(eng, ws0, &ptrs0, &mut planes0, &shard.stage0[1], true)
19142                        })?);
19143                    }
19144                    tgraphs.d[0][li].as_ref().unwrap().0.launch()?;
19145                } else {
19146                    self.tp2_seg_d(e0, ws0, &ptrs0, &mut planes0, &shard.stage0[1], true)?;
19147                }
19148            }
19149        }
19150
19151        // Exit mixer (replicated) + vocab-split lm_head, per card (graphable).
19152        {
19153            let _g = e1.gpu.enter_main()?;
19154            if graphs_live {
19155                if tgraphs.exit[1].is_none() {
19156                    tgraphs.exit[1] = Some(e1.capture_graph_retained_nowarm(|eng| {
19157                        self.tp2_seg_exit(
19158                            eng,
19159                            ws1,
19160                            &ptrs1,
19161                            &shard.exit_gate1,
19162                            &planes1,
19163                            &shard.lm_head1,
19164                            vocab - vsplit,
19165                            1, // decode_step_tp2 is t == 1 by construction
19166                        )
19167                    })?);
19168                }
19169                tgraphs.exit[1].as_ref().unwrap().0.launch()?;
19170            } else {
19171                self.tp2_seg_exit(
19172                    e1,
19173                    ws1,
19174                    &ptrs1,
19175                    &shard.exit_gate1,
19176                    &planes1,
19177                    &shard.lm_head1,
19178                    vocab - vsplit,
19179                    1, // decode_step_tp2 is t == 1 by construction
19180                )?;
19181            }
19182        }
19183        {
19184            let _g = e0.gpu.enter_main()?;
19185            let head0 = self
19186                .output_b16
19187                .as_ref()
19188                .ok_or("qwen4exp_gpu tp2: lm_head has no bf16 twin")?;
19189            if graphs_live {
19190                if tgraphs.exit[0].is_none() {
19191                    tgraphs.exit[0] = Some(e0.capture_graph_retained_nowarm(|eng| {
19192                        self.tp2_seg_exit(
19193                            eng,
19194                            ws0,
19195                            &ptrs0,
19196                            &self.exit_mixer,
19197                            &planes0,
19198                            head0,
19199                            vsplit,
19200                            1, // decode_step_tp2 is t == 1 by construction
19201                        )
19202                    })?);
19203                }
19204                tgraphs.exit[0].as_ref().unwrap().0.launch()?;
19205            } else {
19206                self.tp2_seg_exit(
19207                    e0,
19208                    ws0,
19209                    &ptrs0,
19210                    &self.exit_mixer,
19211                    &planes0,
19212                    head0,
19213                    vsplit,
19214                    1, // decode_step_tp2 is t == 1 by construction
19215                )?;
19216            }
19217        }
19218        let mut out = vec![0.0f32; vocab];
19219        {
19220            let _g = e0.gpu.enter_main()?;
19221            let logits0 = ws0.peek_f32("logits")?;
19222            let host0 = e0.dtoh_view(&logits0.slice(0..vsplit))?;
19223            out[..vsplit].copy_from_slice(&host0);
19224        }
19225        {
19226            let _g = e1.gpu.enter_main()?;
19227            let logits1 = ws1.peek_f32("logits")?;
19228            let host1 = e1.dtoh_view(&logits1.slice(0..vocab - vsplit))?;
19229            out[vsplit..].copy_from_slice(&host1);
19230        }
19231        for (s, plane) in planes0.into_iter().enumerate() {
19232            ws0.put_f32(PLANE_SLOTS[s], plane);
19233        }
19234        for (s, plane) in planes1.into_iter().enumerate() {
19235            ws1.put_f32(PLANE_SLOTS[s], plane);
19236        }
19237        ws0.put_u64("hc.ptrs", ptrs0);
19238        ws1.put_u64("hc.ptrs", ptrs1);
19239        state.pos += 1;
19240        Ok(out)
19241    }
19242}
19243
19244impl Qwen4ExpGpu {
19245    /// TP2-NATIVE long-context state (tp2-prefill lane): the per-card halves allocate
19246    /// DIRECTLY at `capacity` and the single-card KV allocates as a stub — a 1M-token
19247    /// state never materializes the single-card cache at all (the yarn cell's card-0
19248    /// blocker). The state is TP2-latched from birth: single-card forwards refuse it
19249    /// (`state.tp2.is_some()`), and `decode_step_tp2` skips the migration.
19250    pub fn alloc_state_tp2(
19251        &self,
19252        e0: &Engine,
19253        e1: &Engine,
19254        shard: &Tp2Shard,
19255        capacity: usize,
19256        reserve: usize,
19257    ) -> Res<Qwen4ExpState> {
19258        // The single-card side: stub KV, live idx caches (the TP2 indexer runs on
19259        // card 0 through the same machinery), PLE/GDN states on card 0 unused by the
19260        // TP2 route but kept tiny.
19261        let mut state = {
19262            // Stub the single-card KV by allocating under a 1-token capacity, then
19263            // restore the real capacity for the mask/meta bookkeeping.
19264            // The stub's reserve is 1, not `reserve`: `reserve.min(1).max(1)` was written
19265            // here and is the constant 1 for every usize (clippy::min_max, deny-by-default,
19266            // which is how it surfaced). Behaviour-identical simplification — the real
19267            // `reserve` is restored two lines down.
19268            let mut st = self.alloc_state_reserve(e0, 1, 1, None)?;
19269            st.capacity = capacity;
19270            st.reserve = reserve;
19271            st
19272        };
19273        let mut tlayers = Vec::with_capacity(self.layers.len());
19274        for (layer, tw) in self.layers.iter().zip(shard.layers.iter()) {
19275            let mk_half = |e: &Engine, hw: &MixerHalfW| -> Res<MixerHalfState> {
19276                let _g = e.gpu.enter_main()?;
19277                match hw {
19278                    MixerHalfW::Gdn(h) => {
19279                        let conv_dim = 2 * h.nk_h * h.hk + h.nv_h * h.hv;
19280                        let pad = h.kernel - 1;
19281                        Ok(MixerHalfState::Gdn {
19282                            conv: e.zeros(pad * conv_dim)?,
19283                            state: e.zeros(h.nv_h * h.hv * h.hk)?,
19284                        })
19285                    }
19286                    MixerHalfW::Qsa(h) => {
19287                        let kv_dim = h.nkv_h * h.hd;
19288                        let kv = if kv_quant_on() {
19289                            QsaKvStore::Q8Q5 {
19290                                k: e.alloc_u8(capacity * q8_row_bytes(kv_dim))?,
19291                                v: e.alloc_u8(capacity * q5_row_bytes(kv_dim))?,
19292                            }
19293                        } else {
19294                            QsaKvStore::F32 {
19295                                k: e.zeros(capacity * kv_dim)?,
19296                                v: e.zeros(capacity * kv_dim)?,
19297                            }
19298                        };
19299                        Ok(MixerHalfState::Qsa { kv })
19300                    }
19301                }
19302            };
19303            let m0 = mk_half(e0, &tw.mixer0)?;
19304            let m1 = mk_half(e1, &tw.mixer1)?;
19305            let ple1 = match layer.ple.as_ref() {
19306                None => None,
19307                Some(ple) => {
19308                    let pad = (ple.plan.conv_kernel as usize - 1) * ple.plan.max_ngram as usize;
19309                    let _g = e1.gpu.enter_main()?;
19310                    let mut conv_hist = Vec::with_capacity(self.streams);
19311                    for _ in 0..self.streams {
19312                        conv_hist.push(e1.zeros(pad * self.hidden)?);
19313                    }
19314                    Some(PleState {
19315                        conv_hist,
19316                        ngram_ids: Vec::new(),
19317                        ngram_history: Vec::new(),
19318                        ngram_last_eos: -1,
19319                    })
19320                }
19321            };
19322            tlayers.push(Tp2LayerState { m0, m1, ple1 });
19323        }
19324        state.tp2 = Some(Tp2State {
19325            ws1: StepPool::default(),
19326            layers: tlayers,
19327            graphs: Tp2Graphs::default(),
19328            pf_stage0: None,
19329            pf_stage1: None,
19330            pf_stage0_raw: [0; 2],
19331            pf_stage1_raw: [0; 2],
19332            pf_rows: 0,
19333        });
19334        Ok(state)
19335    }
19336
19337    /// TP2 LONG-context chunked prefill: `prefill_extend`'s program on the TP2 route —
19338    /// KV/state fill happens SHARDED-LOCAL on each card (the yarn cell measured remote
19339    /// KV at 18x decode collapse; local halves are the 1M route). Returns the LAST
19340    /// row's logits [vocab].
19341    pub fn prefill_extend_tp2(
19342        &self,
19343        e0: &Engine,
19344        e1: &Engine,
19345        shard: &Tp2Shard,
19346        ids: &[u32],
19347        state: &mut Qwen4ExpState,
19348        chunk: usize,
19349    ) -> Res<Vec<f32>> {
19350        if ids.is_empty() || chunk == 0 {
19351            return Err("qwen4exp_gpu: prefill_extend_tp2 needs ids and a chunk size".into());
19352        }
19353        let mut last = Vec::new();
19354        for piece in ids.chunks(chunk) {
19355            let is_last =
19356                piece.as_ptr() as usize + piece.len() * 4 == ids.as_ptr() as usize + ids.len() * 4;
19357            let head = if is_last {
19358                HeadMode::LastRow
19359            } else {
19360                HeadMode::Skip
19361            };
19362            last = self.forward_tp2(e0, e1, shard, piece, state, head)?;
19363        }
19364        Ok(last)
19365    }
19366
19367    /// One TP2 forward over `t` rows (eager; the TP2-prefill program). Replicated
19368    /// planes + gate reads on both cards, mixer/MoE halves with LOCAL KV/state, join
19369    /// adds in fixed rank order (the decode joins' determinism argument), the indexer
19370    /// selection ONCE on card 0 feeding both cards' block-list halves, and the MoE
19371    /// route split by expert half from the card-0 host route.
19372    #[allow(clippy::too_many_arguments)]
19373    pub fn forward_tp2(
19374        &self,
19375        e0: &Engine,
19376        e1: &Engine,
19377        shard: &Tp2Shard,
19378        ids: &[u32],
19379        state: &mut Qwen4ExpState,
19380        head: HeadMode,
19381    ) -> Res<Vec<f32>> {
19382        if !trunk_bf16_on() || !hc_fused_gate_on() {
19383            return Err(
19384                "qwen4exp_gpu tp2: requires set_trunk_bf16(true) and set_hc_fused_gate(true)"
19385                    .into(),
19386            );
19387        }
19388        let t = ids.len();
19389        if t == 0 {
19390            return Err("qwen4exp_gpu tp2: empty chunk".into());
19391        }
19392        if state.pos + t > state.capacity {
19393            return Err("qwen4exp_gpu: state capacity exceeded".into());
19394        }
19395        if state.tp2.is_none() {
19396            self.tp2_migrate(e0, e1, shard, state)?;
19397            state.graphs = StepGraphs::default();
19398        }
19399        let hidden = self.hidden;
19400        let vocab = self.vocab;
19401        let vsplit = shard.vsplit;
19402        let base_pos = state.pos;
19403        let reserve = state.reserve;
19404        state.tokens.extend_from_slice(ids);
19405        let Qwen4ExpState {
19406            ref tokens,
19407            ws: ref mut ws0,
19408            ref mut tp2,
19409            layers: ref mut lstates,
19410            ..
19411        } = *state;
19412        let tp2s = tp2.as_mut().expect("alloc'd or migrated above");
19413        // Prefill join staging: [t*hidden] x 2 per direction, grown to the largest
19414        // chunk seen (the two-buffer parity proof is the decode staging's, verbatim).
19415        if tp2s.pf_rows < t {
19416            {
19417                let _g = e1.gpu.enter_main()?;
19418                let s1 = [e1.zeros(t * hidden)?, e1.zeros(t * hidden)?];
19419                let s = e1.gpu.stream();
19420                tp2s.pf_stage1_raw = [s1[0].device_ptr(&s).0, s1[1].device_ptr(&s).0];
19421                tp2s.pf_stage1 = Some(s1);
19422            }
19423            {
19424                let _g = e0.gpu.enter_main()?;
19425                let s0 = [e0.zeros(t * hidden)?, e0.zeros(t * hidden)?];
19426                let s = e0.gpu.stream();
19427                tp2s.pf_stage0_raw = [s0[0].device_ptr(&s).0, s0[1].device_ptr(&s).0];
19428                tp2s.pf_stage0 = Some(s0);
19429            }
19430            tp2s.pf_rows = t;
19431        }
19432        let Tp2State {
19433            ws1,
19434            layers: tlayers,
19435            pf_stage0,
19436            pf_stage1,
19437            pf_stage0_raw,
19438            pf_stage1_raw,
19439            ..
19440        } = tp2s;
19441        let pf_stage0 = pf_stage0.as_ref().expect("sized above");
19442        let pf_stage1 = pf_stage1.as_ref().expect("sized above");
19443        let resv = reserve.max(t);
19444
19445        // Entry: embed rows, H2D to BOTH cards' plane slots (replicated planes).
19446        let mut embedded = vec![0.0f32; t * hidden];
19447        for (row, &token) in ids.iter().enumerate() {
19448            let token = token as usize;
19449            if token >= vocab {
19450                return Err(format!("qwen4exp_gpu: token {token} out of range").into());
19451            }
19452            embedded[row * hidden..(row + 1) * hidden]
19453                .copy_from_slice(&self.embed_host[token * hidden..(token + 1) * hidden]);
19454        }
19455        let mut planes1: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
19456        let ptrs1 = {
19457            let _g = e1.gpu.enter_main()?;
19458            let embedded_dev = ws1.take_f32_h2d(e1, "entry.embed", &embedded, resv * hidden)?;
19459            for s in 0..self.streams {
19460                let mut plane = ws1.take_f32(e1, PLANE_SLOTS[s], t * hidden, resv * hidden)?;
19461                e1.copy_into(&mut plane, 0, &embedded_dev, t * hidden)?;
19462                planes1.push(plane);
19463            }
19464            ws1.put_f32("entry.embed", embedded_dev);
19465            let ptr_vals: Vec<u64> = {
19466                let stream = e1.gpu.stream();
19467                planes1.iter().map(|p| p.device_ptr(&stream).0).collect()
19468            };
19469            ws1.take_u64_h2d(e1, "hc.ptrs", &ptr_vals, 0)?
19470        };
19471        let mut planes0: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
19472        let ptrs0 = {
19473            let _g = e0.gpu.enter_main()?;
19474            let embedded_dev = ws0.take_f32_h2d(e0, "entry.embed", &embedded, resv * hidden)?;
19475            for s in 0..self.streams {
19476                let mut plane = ws0.take_f32(e0, PLANE_SLOTS[s], t * hidden, resv * hidden)?;
19477                e0.copy_into(&mut plane, 0, &embedded_dev, t * hidden)?;
19478                planes0.push(plane);
19479            }
19480            ws0.put_f32("entry.embed", embedded_dev);
19481            let ptr_vals: Vec<u64> = {
19482                let stream = e0.gpu.stream();
19483                planes0.iter().map(|p| p.device_ptr(&stream).0).collect()
19484            };
19485            ws0.take_u64_h2d(e0, "hc.ptrs", &ptr_vals, 0)?
19486        };
19487
19488        for (li, layer) in self.layers.iter().enumerate() {
19489            let lstate = &mut lstates[li];
19490            let tw = &shard.layers[li];
19491            let ts = &mut tlayers[li];
19492            let eps_a = layer.eps_attn;
19493            let eps_m = layer.eps_mlp;
19494            let moe = &layer.moe;
19495            let ff = moe.plan.expert_intermediate_size as usize;
19496            let experts = moe.plan.expert_count as usize;
19497            let selected = moe.plan.experts_per_token as usize;
19498            let sff = moe
19499                .plan
19500                .shared
19501                .as_ref()
19502                .map(|s| s.intermediate_size as usize)
19503                .unwrap_or(0);
19504            let sffh = sff / 2;
19505
19506            // ---- PLE (wide-stream add), replicated on both cards ----
19507            if let (Some(ple), Some(ps)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
19508                let _g = e0.gpu.enter_main()?;
19509                self.ple_block(
19510                    e0,
19511                    layer,
19512                    ple,
19513                    &ple.table,
19514                    ps,
19515                    &mut planes0,
19516                    tokens,
19517                    t,
19518                    false,
19519                    None,
19520                )?;
19521            }
19522            if let (Some(ple1), Some(ps1)) = (tw.ple1.as_ref(), ts.ple1.as_mut()) {
19523                let table = &layer.ple.as_ref().expect("ple plan").table;
19524                let _g = e1.gpu.enter_main()?;
19525                self.ple_block(
19526                    e1,
19527                    layer,
19528                    ple1,
19529                    table,
19530                    ps1,
19531                    &mut planes1,
19532                    tokens,
19533                    t,
19534                    false,
19535                    None,
19536                )?;
19537            }
19538
19539            // ---- phase 1: attn gate + mixer halves + join push (parity 0) ----
19540            match (&layer.mixer, &tw.mixer0, &tw.mixer1) {
19541                (MixerW::Gdn(_), MixerHalfW::Gdn(h0), MixerHalfW::Gdn(h1)) => {
19542                    {
19543                        let _g = e1.gpu.enter_main()?;
19544                        let (mixed1, inj1) = self.gate_read(
19545                            e1,
19546                            ws1,
19547                            &ptrs1,
19548                            &tw.attn_gate1,
19549                            &planes1,
19550                            t,
19551                            eps_a,
19552                            false,
19553                        )?;
19554                        let p1 =
19555                            self.gdn_forward_half(e1, ws1, eps_a, h1, &mixed1, &mut ts.m1, t)?;
19556                        ws1.put_f32("hc.mixed", mixed1);
19557                        launch_push(e1, &p1, pf_stage0_raw[0], t * hidden)?;
19558                        ws1.put_f32("mixer.out", p1);
19559                        put_inject(ws1, inj1);
19560                        shard.ev1[0].record(&e1.gpu.stream())?;
19561                    }
19562                    {
19563                        let _g = e0.gpu.enter_main()?;
19564                        let (mixed0, inj0) = self.gate_read(
19565                            e0,
19566                            ws0,
19567                            &ptrs0,
19568                            &layer.attn_gate,
19569                            &planes0,
19570                            t,
19571                            eps_a,
19572                            false,
19573                        )?;
19574                        let p0 =
19575                            self.gdn_forward_half(e0, ws0, eps_a, h0, &mixed0, &mut ts.m0, t)?;
19576                        ws0.put_f32("hc.mixed", mixed0);
19577                        launch_push(e0, &p0, pf_stage1_raw[0], t * hidden)?;
19578                        ws0.put_f32("mixer.out", p0);
19579                        put_inject(ws0, inj0);
19580                        shard.ev0[0].record(&e0.gpu.stream())?;
19581                    }
19582                }
19583                (MixerW::Qsa(qsa), MixerHalfW::Qsa(h0), MixerHalfW::Qsa(h1)) => {
19584                    let (q1, g1, inj1) = {
19585                        let _g = e1.gpu.enter_main()?;
19586                        let (mixed1, inj1) = self.gate_read(
19587                            e1,
19588                            ws1,
19589                            &ptrs1,
19590                            &tw.attn_gate1,
19591                            &planes1,
19592                            t,
19593                            eps_a,
19594                            false,
19595                        )?;
19596                        let (q1, g1) = self
19597                            .qsa_half_proj(e1, ws1, eps_a, h1, &mixed1, &mut ts.m1, base_pos, t)?;
19598                        ws1.put_f32("hc.mixed", mixed1);
19599                        (q1, g1, inj1)
19600                    };
19601                    let (sels, q0, g0, inj0) = {
19602                        let _g = e0.gpu.enter_main()?;
19603                        let (mixed0, inj0) = self.gate_read(
19604                            e0,
19605                            ws0,
19606                            &ptrs0,
19607                            &layer.attn_gate,
19608                            &planes0,
19609                            t,
19610                            eps_a,
19611                            false,
19612                        )?;
19613                        let (q0, g0) = self
19614                            .qsa_half_proj(e0, ws0, eps_a, h0, &mixed0, &mut ts.m0, base_pos, t)?;
19615                        let MixerState::Qsa {
19616                            raw_keys,
19617                            pooled_keys,
19618                            pooled_dev,
19619                            pooled_dev_rows,
19620                            raw_dev,
19621                            raw_dev_rows,
19622                            idx_audit,
19623                            ..
19624                        } = &mut lstate.mixer
19625                        else {
19626                            return Err("qwen4exp_gpu tp2: QSA layer without raw-key cache".into());
19627                        };
19628                        let sels = self.qsa_update_select(
19629                            e0,
19630                            ws0,
19631                            qsa,
19632                            eps_a,
19633                            &mixed0,
19634                            raw_keys,
19635                            pooled_keys,
19636                            pooled_dev,
19637                            pooled_dev_rows,
19638                            raw_dev,
19639                            raw_dev_rows,
19640                            idx_audit.as_mut(),
19641                            base_pos,
19642                            t,
19643                            0,
19644                            false,
19645                        )?;
19646                        ws0.put_f32("hc.mixed", mixed0);
19647                        (sels, q0, g0, inj0)
19648                    };
19649                    let t_kv = base_pos + t;
19650                    let block_size = qsa.overlay.block_size as usize;
19651                    let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
19652                    {
19653                        let _g = e1.gpu.enter_main()?;
19654                        let pos_dev = ws1.take_i32(e1, "qsa.selpos", &pos_flat, 0)?;
19655                        let meta_dev = ws1.take_i32(e1, "qsa.selmeta", &meta, 0)?;
19656                        let p1 = self.qsa_half_attend(
19657                            e1, ws1, h1, &ts.m1, q1, g1, &pos_dev, &meta_dev, max_count, t, t_kv,
19658                        )?;
19659                        ws1.put_i32("qsa.selpos", pos_dev);
19660                        ws1.put_i32("qsa.selmeta", meta_dev);
19661                        launch_push(e1, &p1, pf_stage0_raw[0], t * hidden)?;
19662                        ws1.put_f32("mixer.out", p1);
19663                        put_inject(ws1, inj1);
19664                        shard.ev1[0].record(&e1.gpu.stream())?;
19665                    }
19666                    {
19667                        let _g = e0.gpu.enter_main()?;
19668                        let pos_dev = ws0.take_i32(e0, "qsa.selpos", &pos_flat, 0)?;
19669                        let meta_dev = ws0.take_i32(e0, "qsa.selmeta", &meta, 0)?;
19670                        let p0 = self.qsa_half_attend(
19671                            e0, ws0, h0, &ts.m0, q0, g0, &pos_dev, &meta_dev, max_count, t, t_kv,
19672                        )?;
19673                        ws0.put_i32("qsa.selpos", pos_dev);
19674                        ws0.put_i32("qsa.selmeta", meta_dev);
19675                        launch_push(e0, &p0, pf_stage1_raw[0], t * hidden)?;
19676                        ws0.put_f32("mixer.out", p0);
19677                        put_inject(ws0, inj0);
19678                        shard.ev0[0].record(&e0.gpu.stream())?;
19679                    }
19680                }
19681                _ => return Err("qwen4exp_gpu tp2: mixer/shard shape mismatch".into()),
19682            }
19683            {
19684                let _g = e0.gpu.enter_main()?;
19685                e0.gpu.stream().wait(&shard.ev1[0])?;
19686            }
19687            {
19688                let _g = e1.gpu.enter_main()?;
19689                e1.gpu.stream().wait(&shard.ev0[0])?;
19690            }
19691
19692            // ---- phase 2: join add (fixed rank order) + gate_write + mlp gate_read ----
19693            let join_write = |e: &Engine,
19694                              ws: &mut StepPool,
19695                              ptrs: &CudaSlice<u64>,
19696                              planes: &mut [CudaSlice<f32>],
19697                              stage: &CudaSlice<f32>,
19698                              rank0: bool|
19699             -> Res<()> {
19700                let p = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
19701                let mut out = ws.take_f32(e, "join.out", t * hidden, 0)?;
19702                if rank0 {
19703                    e.add(&p, stage, &mut out, t * hidden)?;
19704                } else {
19705                    e.add(stage, &p, &mut out, t * hidden)?;
19706                }
19707                let inj = take_inject(e, ws, self.streams, t)?;
19708                self.gate_write(e, planes, ptrs, &out, &inj, t)?;
19709                ws.put_f32("mixer.out", p);
19710                ws.put_f32("join.out", out);
19711                put_inject(ws, inj);
19712                Ok(())
19713            };
19714            {
19715                let _g = e1.gpu.enter_main()?;
19716                join_write(e1, ws1, &ptrs1, &mut planes1, &pf_stage1[0], false)?;
19717            }
19718            {
19719                let _g = e0.gpu.enter_main()?;
19720                join_write(e0, ws0, &ptrs0, &mut planes0, &pf_stage0[0], true)?;
19721            }
19722
19723            // ---- phase 3: mlp gate + MoE halves + shared halves + join (parity 1) ----
19724            let mixed1 = {
19725                let _g = e1.gpu.enter_main()?;
19726                let (mixed1, injm1) =
19727                    self.gate_read(e1, ws1, &ptrs1, &tw.mlp_gate1, &planes1, t, eps_m, false)?;
19728                put_inject(ws1, injm1);
19729                mixed1
19730            };
19731            let mixed0 = {
19732                let _g = e0.gpu.enter_main()?;
19733                let (mixed0, injm0) =
19734                    self.gate_read(e0, ws0, &ptrs0, &layer.mlp_gate, &planes0, t, eps_m, false)?;
19735                put_inject(ws0, injm0);
19736                mixed0
19737            };
19738            // Route on card 0 (host twin — TP2 keeps host expert ids by construction),
19739            // split by expert half.
19740            let routes: Vec<Vec<(usize, f32)>> = {
19741                let _g = e0.gpu.enter_main()?;
19742                let mut router_out = ws0.take_f32(e0, "moe.router", t * experts, 0)?;
19743                let none: Option<CudaSlice<u8>> = None;
19744                let rb = if router_bf16_on() {
19745                    &moe.router_b16
19746                } else {
19747                    &none
19748                };
19749                linear_trunk_into(
19750                    e0,
19751                    &moe.router,
19752                    rb,
19753                    &mixed0,
19754                    &mut router_out,
19755                    t,
19756                    hidden,
19757                    experts,
19758                )?;
19759                let logits = e0.dtoh_view(&router_out.slice(0..t * experts))?;
19760                ws0.put_f32("moe.router", router_out);
19761                let mut routes = Vec::with_capacity(t);
19762                for token in 0..t {
19763                    routes.push(host_route_softmax_topk(
19764                        &logits[token * experts..(token + 1) * experts],
19765                        selected,
19766                    ));
19767                }
19768                routes
19769            };
19770            // Split by PLACEMENT (see the decode site); with no map loaded this is the
19771            // even split and reproduces the previous `eid < e_half` / `eid - e_half`
19772            // arithmetic exactly.
19773            let place = &tw.place;
19774            let split_half = |home: bool| -> Vec<Vec<(usize, f32)>> {
19775                routes
19776                    .iter()
19777                    .map(|r| {
19778                        r.iter()
19779                            .filter(|&&(eid, _)| (place.rank(eid) == 0) == home)
19780                            .map(|&(eid, w)| (place.local(eid), w))
19781                            .collect()
19782                    })
19783                    .collect()
19784            };
19785            let mut routes0 = split_half(true);
19786            let mut routes1 = split_half(false);
19787            // Per-rank engagement + the shared-format route trace, in the PREFILL shape
19788            // (one line per (layer, forward) carrying this chunk's t rows of picks).
19789            tp2_count_split(&routes0, &routes1);
19790            trace_moe_routes(layer.index, t, &routes);
19791            match tp2_gate_red()? {
19792                Tp2GateRed::None => {}
19793                Tp2GateRed::SkipPeerMoe => routes1.iter_mut().for_each(|r| r.clear()),
19794                Tp2GateRed::PeerLocalIds => {
19795                    for (r0, r1) in routes0.iter_mut().zip(routes1.iter_mut()) {
19796                        r0.append(r1);
19797                    }
19798                }
19799                Tp2GateRed::ReverseePeerWeights => {
19800                    for r in routes1.iter_mut() {
19801                        let n = r.len();
19802                        for i in 0..n / 2 {
19803                            let (a, b) = (r[i].1, r[n - 1 - i].1);
19804                            r[i].1 = b;
19805                            r[n - 1 - i].1 = a;
19806                        }
19807                    }
19808                }
19809            }
19810            let (routes0, routes1) = (routes0, routes1);
19811            // Card 1: routed half over the bank half (local ids) + shared suffix half.
19812            {
19813                let _g = e1.gpu.enter_main()?;
19814                let mut out1 = self.tp2_moe_rows(
19815                    e1,
19816                    ws1,
19817                    (
19818                        &tw.moe.gate1.codes,
19819                        &tw.moe.gate1.scales,
19820                        &tw.moe.gate1.macros_dev,
19821                    ),
19822                    (
19823                        &tw.moe.up1.codes,
19824                        &tw.moe.up1.scales,
19825                        &tw.moe.up1.macros_dev,
19826                    ),
19827                    (
19828                        &tw.moe.down1.codes,
19829                        &tw.moe.down1.scales,
19830                        &tw.moe.down1.macros_dev,
19831                    ),
19832                    &routes1,
19833                    &mixed1,
19834                    t,
19835                    ff,
19836                )?;
19837                let (sh, g) = self.tp2_shared_half(
19838                    e1,
19839                    ws1,
19840                    &tw.moe.shared_gu1_b16,
19841                    &tw.moe.shared_down1,
19842                    tw.moe.shared_input_gate1.as_ref(),
19843                    &mixed1,
19844                    sffh,
19845                    t,
19846                )?;
19847                match g.as_ref() {
19848                    Some(g) => e1.add_scaled_rows(&sh, g, &mut out1, hidden, t)?,
19849                    None => {
19850                        let mut summed = ws1.take_f32(e1, "moe.sum", t * hidden, 0)?;
19851                        e1.add(&out1, &sh, &mut summed, t * hidden)?;
19852                        ws1.put_f32("moe.out", out1);
19853                        out1 = summed;
19854                    }
19855                }
19856                ws1.put_f32("moe.sh_down", sh);
19857                if let Some(g) = g {
19858                    ws1.put_f32("moe.g", g);
19859                }
19860                launch_push(e1, &out1, pf_stage0_raw[1], t * hidden)?;
19861                ws1.put_f32("moe.out", out1);
19862                ws1.put_f32("hc.mixed", mixed1);
19863                shard.ev1[1].record(&e1.gpu.stream())?;
19864            }
19865            // Card 0: routed half over the FULL resident bank (absolute ids < E/2) +
19866            // shared prefix half.
19867            {
19868                let _g = e0.gpu.enter_main()?;
19869                let (
19870                    BankHalf::Nvfp4 {
19871                        codes: gc,
19872                        scales: gs,
19873                        macros_dev: gm,
19874                        ..
19875                    },
19876                    BankHalf::Nvfp4 {
19877                        codes: uc,
19878                        scales: us,
19879                        macros_dev: um,
19880                        ..
19881                    },
19882                    BankHalf::Nvfp4 {
19883                        codes: dc,
19884                        scales: ds,
19885                        macros_dev: dm,
19886                        ..
19887                    },
19888                ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
19889                else {
19890                    return Err("qwen4exp_gpu tp2: card0 bank is not NVFP4".into());
19891                };
19892                let mut out0 = self.tp2_moe_rows(
19893                    e0,
19894                    ws0,
19895                    (gc, gs, gm),
19896                    (uc, us, um),
19897                    (dc, ds, dm),
19898                    &routes0,
19899                    &mixed0,
19900                    t,
19901                    ff,
19902                )?;
19903                let (sh, g) = self.tp2_shared_half(
19904                    e0,
19905                    ws0,
19906                    &tw.moe.shared_gu0_b16,
19907                    &tw.moe.shared_down0,
19908                    moe.shared_input_gate.as_ref(),
19909                    &mixed0,
19910                    sffh,
19911                    t,
19912                )?;
19913                match g.as_ref() {
19914                    Some(g) => e0.add_scaled_rows(&sh, g, &mut out0, hidden, t)?,
19915                    None => {
19916                        let mut summed = ws0.take_f32(e0, "moe.sum", t * hidden, 0)?;
19917                        e0.add(&out0, &sh, &mut summed, t * hidden)?;
19918                        ws0.put_f32("moe.out", out0);
19919                        out0 = summed;
19920                    }
19921                }
19922                ws0.put_f32("moe.sh_down", sh);
19923                if let Some(g) = g {
19924                    ws0.put_f32("moe.g", g);
19925                }
19926                launch_push(e0, &out0, pf_stage1_raw[1], t * hidden)?;
19927                ws0.put_f32("moe.out", out0);
19928                ws0.put_f32("hc.mixed", mixed0);
19929                shard.ev0[1].record(&e0.gpu.stream())?;
19930            }
19931            {
19932                let _g = e1.gpu.enter_main()?;
19933                e1.gpu.stream().wait(&shard.ev0[1])?;
19934                let p = ws1.take_f32(e1, "moe.out", t * hidden, 0)?;
19935                let mut out = ws1.take_f32(e1, "join.out", t * hidden, 0)?;
19936                e1.add(&pf_stage1[1], &p, &mut out, t * hidden)?;
19937                let inj = take_inject(e1, ws1, self.streams, t)?;
19938                self.gate_write(e1, &mut planes1, &ptrs1, &out, &inj, t)?;
19939                ws1.put_f32("moe.out", p);
19940                ws1.put_f32("join.out", out);
19941                put_inject(ws1, inj);
19942            }
19943            {
19944                let _g = e0.gpu.enter_main()?;
19945                e0.gpu.stream().wait(&shard.ev1[1])?;
19946                let p = ws0.take_f32(e0, "moe.out", t * hidden, 0)?;
19947                let mut out = ws0.take_f32(e0, "join.out", t * hidden, 0)?;
19948                e0.add(&p, &pf_stage0[1], &mut out, t * hidden)?;
19949                let inj = take_inject(e0, ws0, self.streams, t)?;
19950                self.gate_write(e0, &mut planes0, &ptrs0, &out, &inj, t)?;
19951                ws0.put_f32("moe.out", p);
19952                ws0.put_f32("join.out", out);
19953                put_inject(ws0, inj);
19954            }
19955        }
19956
19957        // Exit: Skip on interior chunks; LastRow copies each plane's final row into
19958        // t == 1 exit slots and runs the decode exit segment on them; All runs the exit
19959        // segment over ALL t rows straight off the planes.
19960        //
19961        // `All` used to fall through to the LastRow body, so a caller asking for every row
19962        // got exactly one and no error. That is the failure mode the loud-failure law is
19963        // about: the TP2 class gate's whole PRIME regime is "compare EVERY row of a full-head
19964        // forward", and it could not have done that — it only surfaced because the gate
19965        // length-checks single-card logits against TP2 logits before comparing
19966        // ("single-card produced 2483200 logits, TP2 248320"). Without that check the gate
19967        // would have compared one row and reported a t>=2 verdict.
19968        //
19969        // Cost note (why this stays an instrument, not a serving path): a [t, vocab] block is
19970        // t * 248320 * 4 bytes, so it is ~9.9 MB at the gate's 10-token probe and gigabytes at
19971        // a long-context chunk. Chunked prefill therefore still uses LastRow, exactly as the
19972        // single-card path does for the same reason.
19973        let head_rows = match head {
19974            HeadMode::All => t,
19975            _ => 1,
19976        };
19977        let mut out = vec![
19978            0.0f32;
19979            if head == HeadMode::Skip {
19980                0
19981            } else {
19982                head_rows * vocab
19983            }
19984        ];
19985        if head != HeadMode::Skip {
19986            {
19987                let _g = e1.gpu.enter_main()?;
19988                // All: the planes already hold every row, so the exit reads them directly
19989                // with the pointer array the trunk built. LastRow: copy each plane's final
19990                // row into the t == 1 exit slots (the decode-shaped exit).
19991                let mut exit_planes: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
19992                if head != HeadMode::All {
19993                    for (s, plane) in planes1.iter().enumerate() {
19994                        let mut row = ws1.take_f32(e1, EXIT_PLANE_SLOTS[s], hidden, hidden)?;
19995                        e1.copy_range_into(&mut row, 0, plane, (t - 1) * hidden, hidden)?;
19996                        exit_planes.push(row);
19997                    }
19998                }
19999                let use_planes: &[CudaSlice<f32>] = if head == HeadMode::All {
20000                    &planes1
20001                } else {
20002                    &exit_planes
20003                };
20004                let ptr_vals: Vec<u64> = {
20005                    let stream = e1.gpu.stream();
20006                    use_planes.iter().map(|p| p.device_ptr(&stream).0).collect()
20007                };
20008                let eptrs = ws1.take_u64_h2d(e1, "exit.ptrs", &ptr_vals, 0)?;
20009                self.tp2_seg_exit(
20010                    e1,
20011                    ws1,
20012                    &eptrs,
20013                    &shard.exit_gate1,
20014                    use_planes,
20015                    &shard.lm_head1,
20016                    vocab - vsplit,
20017                    head_rows,
20018                )?;
20019                ws1.put_u64("exit.ptrs", eptrs);
20020                for (s, p) in exit_planes.into_iter().enumerate() {
20021                    ws1.put_f32(EXIT_PLANE_SLOTS[s], p);
20022                }
20023                let logits1 = ws1.peek_f32("logits")?;
20024                let half1 = vocab - vsplit;
20025                let host1 = e1.dtoh_view(&logits1.slice(0..head_rows * half1))?;
20026                // This card owns the HIGH column half of every row, so a [rows, half1]
20027                // block scatters into [rows, vocab] one row at a time.
20028                for r in 0..head_rows {
20029                    out[r * vocab + vsplit..(r + 1) * vocab]
20030                        .copy_from_slice(&host1[r * half1..(r + 1) * half1]);
20031                }
20032            }
20033            {
20034                let _g = e0.gpu.enter_main()?;
20035                let head0 = self
20036                    .output_b16
20037                    .as_ref()
20038                    .ok_or("qwen4exp_gpu tp2: lm_head has no bf16 twin")?;
20039                let mut exit_planes: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
20040                if head != HeadMode::All {
20041                    for (s, plane) in planes0.iter().enumerate() {
20042                        let mut row = ws0.take_f32(e0, EXIT_PLANE_SLOTS[s], hidden, hidden)?;
20043                        e0.copy_range_into(&mut row, 0, plane, (t - 1) * hidden, hidden)?;
20044                        exit_planes.push(row);
20045                    }
20046                }
20047                let use_planes: &[CudaSlice<f32>] = if head == HeadMode::All {
20048                    &planes0
20049                } else {
20050                    &exit_planes
20051                };
20052                let ptr_vals: Vec<u64> = {
20053                    let stream = e0.gpu.stream();
20054                    use_planes.iter().map(|p| p.device_ptr(&stream).0).collect()
20055                };
20056                let eptrs = ws0.take_u64_h2d(e0, "exit.ptrs", &ptr_vals, 0)?;
20057                self.tp2_seg_exit(
20058                    e0,
20059                    ws0,
20060                    &eptrs,
20061                    &self.exit_mixer,
20062                    use_planes,
20063                    head0,
20064                    vsplit,
20065                    head_rows,
20066                )?;
20067                ws0.put_u64("exit.ptrs", eptrs);
20068                for (s, p) in exit_planes.into_iter().enumerate() {
20069                    ws0.put_f32(EXIT_PLANE_SLOTS[s], p);
20070                }
20071                let logits0 = ws0.peek_f32("logits")?;
20072                let host0 = e0.dtoh_view(&logits0.slice(0..head_rows * vsplit))?;
20073                // This card owns the LOW column half of every row.
20074                for r in 0..head_rows {
20075                    out[r * vocab..r * vocab + vsplit]
20076                        .copy_from_slice(&host0[r * vsplit..(r + 1) * vsplit]);
20077                }
20078            }
20079        } else {
20080            // Establish a host boundary per chunk so the chunk loop cannot run the
20081            // host arbitrarily far ahead of both devices.
20082            {
20083                let _g = e0.gpu.enter_main()?;
20084                e0.gpu.stream().synchronize()?;
20085            }
20086            {
20087                let _g = e1.gpu.enter_main()?;
20088                e1.gpu.stream().synchronize()?;
20089            }
20090        }
20091        for (s, plane) in planes0.into_iter().enumerate() {
20092            ws0.put_f32(PLANE_SLOTS[s], plane);
20093        }
20094        for (s, plane) in planes1.into_iter().enumerate() {
20095            ws1.put_f32(PLANE_SLOTS[s], plane);
20096        }
20097        ws0.put_u64("hc.ptrs", ptrs0);
20098        ws1.put_u64("hc.ptrs", ptrs1);
20099        state.pos += t;
20100        Ok(out)
20101    }
20102
20103    /// Grouped routed-experts half at t rows (TP2 prefill): the single-card grouped
20104    /// prefill program (SLOT_CAP sub-batching, absolute-token maps, per-token
20105    /// slot-ordered combines) over THIS CARD's bank (card 0 = the full resident bank
20106    /// with absolute ids < E/2; card 1 = the half bank with local ids). Tokens with no
20107    /// experts on this card keep their zero rows (the join sums the halves).
20108    #[allow(clippy::too_many_arguments)]
20109    fn tp2_moe_rows(
20110        &self,
20111        e: &Engine,
20112        ws: &mut StepPool,
20113        gate: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20114        up: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20115        down: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20116        routes: &[Vec<(usize, f32)>],
20117        mixed: &CudaSlice<f32>,
20118        t: usize,
20119        ff: usize,
20120    ) -> Res<CudaSlice<f32>> {
20121        let hidden = self.hidden;
20122        if !(sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0) {
20123            return Err(
20124                "qwen4exp_gpu tp2: prefill MoE needs the gufuse geometry (hidden%32, ff%4)".into(),
20125            );
20126        }
20127        let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
20128        {
20129            let mut view = out.slice_mut(0..t * hidden);
20130            e.memset_zeros_view(&mut view)?;
20131        }
20132        const SLOT_CAP: usize = 8192;
20133        let mut tok0 = 0usize;
20134        while tok0 < t {
20135            // Advance until the slot budget fills (routes are variable-length halves).
20136            let mut tok_n = 0usize;
20137            let mut slots = 0usize;
20138            while tok0 + tok_n < t {
20139                let n = routes[tok0 + tok_n].len();
20140                if tok_n > 0 && slots + n > SLOT_CAP {
20141                    break;
20142                }
20143                slots += n;
20144                tok_n += 1;
20145            }
20146            let batch = &routes[tok0..tok0 + tok_n];
20147            let mut sel_all: Vec<i32> = Vec::with_capacity(slots);
20148            let mut w_all: Vec<f32> = Vec::with_capacity(slots);
20149            let mut tok_all: Vec<i32> = Vec::with_capacity(slots);
20150            let mut ranges: Vec<(usize, usize)> = Vec::with_capacity(tok_n);
20151            for (i, route) in batch.iter().enumerate() {
20152                ranges.push((sel_all.len(), route.len()));
20153                for &(eid, wgt) in route {
20154                    sel_all.push(eid as i32);
20155                    w_all.push(wgt);
20156                    tok_all.push((tok0 + i) as i32);
20157                }
20158            }
20159            let s_total = sel_all.len();
20160            if s_total > 0 {
20161                let sel = ws.take_i32(e, "moe.sel", &sel_all, 0)?;
20162                let w_dev = ws.take_f32_h2d(e, "moe.w", &w_all, 0)?;
20163                let tokm = ws.take_i32(e, "moe.tok", &tok_all, 0)?;
20164                let mut act = ws.take_f32(e, "moe.act", s_total * ff, 0)?;
20165                launch_nvfp4_sel_gu_silu(
20166                    e,
20167                    gate,
20168                    up,
20169                    Some(&sel),
20170                    0,
20171                    s_total,
20172                    mixed,
20173                    &mut act,
20174                    hidden,
20175                    ff,
20176                    Some((&tokm, hidden)),
20177                )?;
20178                let mut partial = ws.take_f32(e, "moe.partial", s_total * hidden, 0)?;
20179                launch_nvfp4_sel_matvec(
20180                    e,
20181                    down.0,
20182                    down.1,
20183                    down.2,
20184                    &sel,
20185                    &act,
20186                    &mut partial,
20187                    s_total,
20188                    ff,
20189                    hidden,
20190                    ff,
20191                )?;
20192                for (i, &(start, len)) in ranges.iter().enumerate() {
20193                    if len > 0 {
20194                        launch_axpy_rows_seq_at(
20195                            e,
20196                            &partial,
20197                            start,
20198                            &w_dev,
20199                            start,
20200                            &mut out,
20201                            tok0 + i,
20202                            hidden,
20203                            len,
20204                        )?;
20205                    }
20206                }
20207                ws.put_i32("moe.sel", sel);
20208                ws.put_i32("moe.tok", tokm);
20209                ws.put_f32("moe.w", w_dev);
20210                ws.put_f32("moe.act", act);
20211                ws.put_f32("moe.partial", partial);
20212            }
20213            tok0 += tok_n;
20214        }
20215        Ok(out)
20216    }
20217
20218    /// TP2 segment A (GDN layers, graphable): attn gate_read + GDN half + join push;
20219    /// parks the partial in "mixer.out" and the inject scalars in their slots.
20220    #[allow(clippy::too_many_arguments)]
20221    fn tp2_gdn_seg_a(
20222        &self,
20223        e: &Engine,
20224        ws: &mut StepPool,
20225        ptrs: &CudaSlice<u64>,
20226        attn_gate: &GateW,
20227        h: &GdnHalfW,
20228        hstate: &mut MixerHalfState,
20229        planes: &[CudaSlice<f32>],
20230        eps: f32,
20231        push_raw: u64,
20232    ) -> Res<()> {
20233        let (mixed, inj) = self.gate_read(e, ws, ptrs, attn_gate, planes, 1, eps, false)?;
20234        let p = self.gdn_forward_half(e, ws, eps, h, &mixed, hstate, 1)?;
20235        ws.put_f32("hc.mixed", mixed);
20236        launch_push(e, &p, push_raw, self.hidden)?;
20237        ws.put_f32("mixer.out", p);
20238        put_inject(ws, inj);
20239        Ok(())
20240    }
20241
20242    /// TP2 segment B (all layers, graphable): mixer join add (SAME rank order on both
20243    /// cards) + gate_write + mlp gate_read (+ optional card-1 shared-half prestage,
20244    /// parked in "tp2.sh"/"tp2.shg"); parks the mlp mixed in "hc.mixed" and the mlp
20245    /// inject in its slots.
20246    #[allow(clippy::too_many_arguments)]
20247    fn tp2_seg_b(
20248        &self,
20249        e: &Engine,
20250        ws: &mut StepPool,
20251        ptrs: &CudaSlice<u64>,
20252        mlp_gate: &GateW,
20253        planes: &mut [CudaSlice<f32>],
20254        stage_recv: &CudaSlice<f32>,
20255        rank0: bool,
20256        eps_m: f32,
20257        shared: Option<(
20258            &CudaSlice<u8>,
20259            &CudaSlice<u8>,
20260            Option<&CudaSlice<f32>>,
20261            usize,
20262        )>,
20263    ) -> Res<()> {
20264        let hidden = self.hidden;
20265        let p = ws.take_f32(e, "mixer.out", hidden, 0)?;
20266        let mut out = ws.take_f32(e, "join.out", hidden, 0)?;
20267        if rank0 {
20268            e.add(&p, stage_recv, &mut out, hidden)?;
20269        } else {
20270            e.add(stage_recv, &p, &mut out, hidden)?;
20271        }
20272        let inj = take_inject(e, ws, self.streams, 1)?;
20273        self.gate_write(e, planes, ptrs, &out, &inj, 1)?;
20274        ws.put_f32("mixer.out", p);
20275        ws.put_f32("join.out", out);
20276        put_inject(ws, inj);
20277        let (mixed, injm) = self.gate_read(e, ws, ptrs, mlp_gate, planes, 1, eps_m, false)?;
20278        if let Some((gu_b16, d_b16, ig, sffh)) = shared {
20279            let (sh, gg) = self.tp2_shared_half(e, ws, gu_b16, d_b16, ig, &mixed, sffh, 1)?;
20280            // Slot-cycle invariant: park under the SAME names tp2_shared_half takes
20281            // from ("moe.sh_down"/"moe.g"), or the next capture of this segment would
20282            // allocate inside the capture region (graph mem node).
20283            ws.put_f32("moe.sh_down", sh);
20284            if let Some(gg) = gg {
20285                ws.put_f32("moe.g", gg);
20286            }
20287        }
20288        ws.put_f32("hc.mixed", mixed);
20289        put_inject(ws, injm);
20290        Ok(())
20291    }
20292
20293    /// TP2 exit segment (graphable): exit mixer read + this card's lm_head half into the
20294    /// parked "logits" slot.
20295    #[allow(clippy::too_many_arguments)]
20296    /// TP2 exit segment (mixer + this card's lm_head column half) over `rows` rows.
20297    ///
20298    /// `rows` used to be hardcoded to 1, which made `HeadMode::All` silently identical to
20299    /// `HeadMode::LastRow` in the TP2 forward — see the caller for why that was a defect
20300    /// and not merely a limitation. Both `gate_read_inner` and `launch_qmatvec_bf16w`
20301    /// already take a row count (the kernel's grid y-dim IS `t`, striding `x` by
20302    /// `x_tstride`), so this is a parameter that was never threaded, not new math: at
20303    /// `rows == 1` the launch arguments are byte-for-byte the ones this function used
20304    /// before, which is what makes the decode path a control rather than a hope.
20305    fn tp2_seg_exit(
20306        &self,
20307        e: &Engine,
20308        ws: &mut StepPool,
20309        ptrs: &CudaSlice<u64>,
20310        gate: &GateW,
20311        planes: &[CudaSlice<f32>],
20312        head_b16: &CudaSlice<u8>,
20313        out_f: usize,
20314        rows: usize,
20315    ) -> Res<()> {
20316        let x = self
20317            .gate_read_inner(e, ws, ptrs, gate, planes, rows, self.exit_eps, false, false)?
20318            .0;
20319        let mut logits = ws.take_f32(e, "logits", rows * out_f, rows * out_f)?;
20320        launch_qmatvec_bf16w(
20321            e,
20322            head_b16,
20323            &x,
20324            &mut logits,
20325            self.hidden,
20326            out_f,
20327            rows,
20328            1,
20329            0,
20330            0,
20331            self.hidden,
20332            0,
20333        )?;
20334        ws.put_f32("hc.mixed", x);
20335        ws.put_f32("logits", logits);
20336        Ok(())
20337    }
20338}
20339
20340/// Launch the count-gated grouped sel matvec (`_v3c`, fixed grid over `max_sel` slots,
20341/// live count from the pack blob). TP2 graph segments only; geometry must admit the
20342/// 4-row kernel (the artifact does).
20343#[allow(clippy::too_many_arguments)]
20344fn launch_nvfp4_sel_matvec_pack(
20345    e: &Engine,
20346    codes: &CudaSlice<u8>,
20347    scales: &CudaSlice<u8>,
20348    macros_dev: &CudaSlice<f32>,
20349    pack_raw: u64,
20350    max_sel: usize,
20351    x: &CudaSlice<f32>,
20352    y: &mut CudaSlice<f32>,
20353    in_f: usize,
20354    out_f: usize,
20355    x_stride: usize,
20356) -> Res<()> {
20357    if in_f % 32 != 0 || out_f % 4 != 0 {
20358        return Err(
20359            "qmatvec_nvfp4_modelopt_sel_f32_v3c: geometry needs in_f%32==0 && out_f%4==0".into(),
20360        );
20361    }
20362    let f = e.func("qmatvec_nvfp4_modelopt_sel_f32_v3c");
20363    let cfg = LaunchConfig {
20364        grid_dim: ((out_f / 4) as u32, max_sel as u32, 1),
20365        block_dim: (32, 1, 1),
20366        shared_mem_bytes: 0,
20367    };
20368    let (inf, outf, ms) = (in_f as i32, out_f as i32, max_sel as i32);
20369    let xs = x_stride as i64;
20370    let stream = e.gpu.stream();
20371    let mut b = stream.launch_builder(&f);
20372    b.arg(codes)
20373        .arg(scales)
20374        .arg(macros_dev)
20375        .arg(&pack_raw)
20376        .arg(&ms)
20377        .arg(x)
20378        .arg(y)
20379        .arg(&inf)
20380        .arg(&outf)
20381        .arg(&xs);
20382    unsafe {
20383        b.launch(cfg)?;
20384    }
20385    Ok(())
20386}
20387
20388fn launch_axpy_rows_seq_pack(
20389    e: &Engine,
20390    x: &CudaSlice<f32>,
20391    pack_raw: u64,
20392    max_sel: usize,
20393    y: &mut CudaSlice<f32>,
20394    width: usize,
20395) -> Res<()> {
20396    let f = e.func("axpy_rows_seq_pack_f32");
20397    let cfg = LaunchConfig::for_num_elems(width as u32);
20398    let (ms, wi) = (max_sel as i32, width as i32);
20399    let stream = e.gpu.stream();
20400    let mut b = stream.launch_builder(&f);
20401    b.arg(x).arg(&pack_raw).arg(&ms).arg(y).arg(&wi);
20402    unsafe {
20403        b.launch(cfg)?;
20404    }
20405    Ok(())
20406}
20407
20408/// Build the pack blob: [max_sel i32 sel padded][max_sel f32 w padded][i32 count].
20409fn tp2_pack_bytes(sel: &[i32], w: &[f32], max_sel: usize) -> Vec<u8> {
20410    let mut out = Vec::with_capacity((2 * max_sel + 1) * 4);
20411    for i in 0..max_sel {
20412        out.extend_from_slice(&sel.get(i).copied().unwrap_or(0).to_le_bytes());
20413    }
20414    for i in 0..max_sel {
20415        out.extend_from_slice(&w.get(i).copied().unwrap_or(0.0).to_le_bytes());
20416    }
20417    out.extend_from_slice(&(sel.len() as i32).to_le_bytes());
20418    out
20419}
20420
20421impl Qwen4ExpGpu {
20422    /// TP2 segment C (graphable): count-gated routed half over the pack blob + shared
20423    /// add + join push. Card 1 takes its prestaged shared parts ("moe.sh_down"/"moe.g",
20424    /// parked by seg B); card 0 computes its shared half here. Parks the MoE partial in
20425    /// "moe.out".
20426    #[allow(clippy::too_many_arguments)]
20427    fn tp2_seg_c(
20428        &self,
20429        e: &Engine,
20430        ws: &mut StepPool,
20431        gate: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20432        up: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20433        down: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20434        ff: usize,
20435        max_sel: usize,
20436        shared_compute: Option<(
20437            &CudaSlice<u8>,
20438            &CudaSlice<u8>,
20439            Option<&CudaSlice<f32>>,
20440            usize,
20441        )>,
20442        shared_gated: bool,
20443        push_raw: u64,
20444    ) -> Res<()> {
20445        let hidden = self.hidden;
20446        let pack_raw = {
20447            let pack = ws.peek_u8("moe.pack")?;
20448            let stream = e.gpu.stream();
20449            pack.device_ptr(&stream).0
20450        };
20451        let mixed = ws.take_f32(e, "hc.mixed", hidden, 0)?;
20452        let mut act = ws.take_f32(e, "moe.act", max_sel * ff, 0)?;
20453        // Fused gate+up+silu (round 4, count-gated pack mode): the capture bakes the
20454        // live arm; dead slots (>= live count) retire at the first instruction and the
20455        // count-gated down/axpy never read them. Bit-identical to the chain per slot.
20456        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
20457            launch_nvfp4_sel_gu_silu(
20458                e, gate, up, None, pack_raw, max_sel, &mixed, &mut act, hidden, ff, None,
20459            )?;
20460        } else {
20461            let mut yg = ws.take_f32(e, "moe.yg", max_sel * ff, 0)?;
20462            let mut yu = ws.take_f32(e, "moe.yu", max_sel * ff, 0)?;
20463            launch_nvfp4_sel_matvec_pack(
20464                e, gate.0, gate.1, gate.2, pack_raw, max_sel, &mixed, &mut yg, hidden, ff, 0,
20465            )?;
20466            launch_nvfp4_sel_matvec_pack(
20467                e, up.0, up.1, up.2, pack_raw, max_sel, &mixed, &mut yu, hidden, ff, 0,
20468            )?;
20469            e.silu_mul(&yg, &yu, &mut act, max_sel * ff)?;
20470            ws.put_f32("moe.yg", yg);
20471            ws.put_f32("moe.yu", yu);
20472        }
20473        let mut partial = ws.take_f32(e, "moe.partial", max_sel * hidden, 0)?;
20474        launch_nvfp4_sel_matvec_pack(
20475            e,
20476            down.0,
20477            down.1,
20478            down.2,
20479            pack_raw,
20480            max_sel,
20481            &act,
20482            &mut partial,
20483            ff,
20484            hidden,
20485            ff,
20486        )?;
20487        let mut r = ws.take_f32(e, "moe.out", hidden, 0)?;
20488        launch_axpy_rows_seq_pack(e, &partial, pack_raw, max_sel, &mut r, hidden)?;
20489        ws.put_f32("moe.act", act);
20490        ws.put_f32("moe.partial", partial);
20491        let (sh, g) = match shared_compute {
20492            Some((gu_b16, d_b16, ig, sffh)) => {
20493                self.tp2_shared_half(e, ws, gu_b16, d_b16, ig, &mixed, sffh, 1)?
20494            }
20495            None => {
20496                let sh = ws.take_f32(e, "moe.sh_down", hidden, 0)?;
20497                let g = if shared_gated {
20498                    Some(ws.take_f32(e, "moe.g", 1, 0)?)
20499                } else {
20500                    None
20501                };
20502                (sh, g)
20503            }
20504        };
20505        match g.as_ref() {
20506            Some(g) => e.add_scaled_rows(&sh, g, &mut r, hidden, 1)?,
20507            None => {
20508                let mut view = r.slice_mut(0..hidden);
20509                e.axpy_into(&sh, 1.0, &mut view, hidden)?;
20510            }
20511        }
20512        ws.put_f32("moe.sh_down", sh);
20513        if let Some(g) = g {
20514            ws.put_f32("moe.g", g);
20515        }
20516        launch_push(e, &r, push_raw, hidden)?;
20517        ws.put_f32("moe.out", r);
20518        ws.put_f32("hc.mixed", mixed);
20519        Ok(())
20520    }
20521
20522    /// TP2 segment D (graphable): MoE join add (SAME rank order both cards) + gate_write.
20523    #[allow(clippy::too_many_arguments)]
20524    fn tp2_seg_d(
20525        &self,
20526        e: &Engine,
20527        ws: &mut StepPool,
20528        ptrs: &CudaSlice<u64>,
20529        planes: &mut [CudaSlice<f32>],
20530        stage_recv: &CudaSlice<f32>,
20531        rank0: bool,
20532    ) -> Res<()> {
20533        let hidden = self.hidden;
20534        let mp = ws.take_f32(e, "moe.out", hidden, 0)?;
20535        let mut mo = ws.take_f32(e, "join.out", hidden, 0)?;
20536        if rank0 {
20537            e.add(&mp, stage_recv, &mut mo, hidden)?;
20538        } else {
20539            e.add(stage_recv, &mp, &mut mo, hidden)?;
20540        }
20541        let injm = take_inject(e, ws, self.streams, 1)?;
20542        self.gate_write(e, planes, ptrs, &mo, &injm, 1)?;
20543        ws.put_f32("moe.out", mp);
20544        ws.put_f32("join.out", mo);
20545        put_inject(ws, injm);
20546        Ok(())
20547    }
20548}
20549
20550#[cfg(test)]
20551mod sel_group_tests {
20552    use super::*;
20553
20554    /// The seam lives in process-global atomics and `cargo test` runs these in parallel
20555    /// THREADS of one process, so every test that mutates it takes this lock. Without it the
20556    /// mutating tests race and the suite fails intermittently on whichever one loses.
20557    static SEAM: std::sync::Mutex<()> = std::sync::Mutex::new(());
20558
20559    /// The AUTO rule at the SERVING geometry, pinned as a test because it is the shape the
20560    /// seam ships and it was WRONG once: an earlier rule derived `rows` from `g` to hold
20561    /// rows-per-warp at 4, and the measured ladder showed rows-per-LANE is what pays
20562    /// (DOWNSEL.md section 4). A regression here is a silent shape change.
20563    #[test]
20564    fn auto_resolves_the_measured_serving_shapes() {
20565        // down: out_f = hidden 2560, in_f = expert ff 640 -> pairs 20 -> g 4 (largest power
20566        // of two dividing 20), rows 4 -> rows_per_warp 32, grid.x 80.
20567        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 640, 2560), Some((4, 4)));
20568        // gate+up: out_f = ff 640, in_f = hidden 2560 -> pairs 80 -> g 16, rows 4 ->
20569        // rows_per_warp 8, grid.x 80.
20570        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 2560, 640), Some((16, 4)));
20571    }
20572
20573    #[test]
20574    fn off_and_odd_in_f_take_the_shipped_kernel() {
20575        assert_eq!(sel_group_resolve(SEL_GROUP_OFF, 640, 2560), None);
20576        // in_f % 32 != 0 is the v3 guard too; the group form must not claim it.
20577        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 48, 2560), None);
20578    }
20579
20580    /// AUTO must never hand back a shape the launcher cannot tile exactly: a ragged tile puts
20581    /// live and dead lanes in the same `__shfl_down_sync`. It steps `rows` down before giving
20582    /// up, and gives up rather than clamping.
20583    #[test]
20584    fn auto_backs_off_rows_then_refuses_rather_than_tiling_raggedly() {
20585        // pairs 2 -> g 2 -> 16 groups. out_f 32 admits rows 2 (rpw 32); rows 4 (rpw 64) does
20586        // not divide 32, so AUTO must step down instead of returning an untileable shape.
20587        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 64, 32), Some((2, 2)));
20588        // out_f 24 divides by neither 64, 32 nor 16 (rows 4/2/1 at g=2) -> refuse.
20589        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 64, 24), None);
20590        for &(in_f, out_f) in &[(640usize, 2560usize), (2560, 640), (32, 32), (64, 16)] {
20591            let (g, rows) = sel_group_resolve(SEL_GROUP_AUTO, in_f, out_f)
20592                .unwrap_or_else(|| panic!("auto refused {in_f}x{out_f}"));
20593            assert_eq!(
20594                out_f % ((32 / g) * rows),
20595                0,
20596                "{in_f}x{out_f} -> g{g} rows{rows}"
20597            );
20598        }
20599    }
20600
20601    /// An explicit pin is honoured verbatim (the A/B ladder depends on it) but still refuses a
20602    /// geometry it cannot tile, so a mis-set cell falls back to the shipped kernel loudly
20603    /// rather than launching a ragged grid.
20604    #[test]
20605    fn explicit_pins_are_verbatim_and_still_tile_checked() {
20606        let _g = SEAM.lock().unwrap();
20607        assert!(set_sel_group("dn:8:1+gu:16:4"));
20608        assert_eq!(sel_group_resolve(sel_group_dn(), 640, 2560), Some((8, 1)));
20609        assert_eq!(sel_group_resolve(sel_group_gu(), 2560, 640), Some((16, 4)));
20610        // g=1 rows=4 -> rows_per_warp 128. Both serving widths are multiples of 128 and
20611        // tile fine (2560 = 20x128, 640 = 5x128); an out_f that is NOT must refuse.
20612        assert!(set_sel_group("dn:1:4"));
20613        assert_eq!(sel_group_resolve(sel_group_dn(), 2560, 640), Some((1, 4)));
20614        assert_eq!(sel_group_resolve(sel_group_dn(), 2560, 96), None);
20615        set_sel_group("off");
20616    }
20617
20618    /// A malformed spec must APPLY NOTHING and report false. If it half-applied or reported
20619    /// true, a typo in a cell script would silently measure the wrong arm — the failure the
20620    /// seam grammar exists to make impossible.
20621    #[test]
20622    fn malformed_specs_apply_nothing_and_refuse() {
20623        let _g = SEAM.lock().unwrap();
20624        assert!(set_sel_group("dn:4:4+gu:16:4"));
20625        let before = sel_group_spec();
20626        for bad in [
20627            "dn:3:4",      // g not a power of two
20628            "dn:4:3",      // rows not in {1,2,4}
20629            "dn:64:4",     // g > 32
20630            "dn:4",        // no rows
20631            "xx:4:4",      // unknown family
20632            "dn:4:4+xx:1", // one good half, one bad -> still nothing applied
20633            "+",
20634        ] {
20635            assert!(!set_sel_group(bad), "{bad:?} was accepted");
20636            assert_eq!(
20637                sel_group_spec(),
20638                before,
20639                "{bad:?} mutated state while refusing"
20640            );
20641        }
20642        set_sel_group("off");
20643    }
20644
20645    /// `seam_state` has to answer for this seam even though it is shape-valued: the shared
20646    /// `--ladder-ab-seam` harness restores the entry arm ONLY when it answers, and a `None`
20647    /// there leaves the ON arm armed for every number after the A/B block.
20648    #[test]
20649    fn seam_round_trips_through_the_boolean_harness() {
20650        let _g = SEAM.lock().unwrap();
20651        set_sel_group("off");
20652        assert_eq!(seam_state("selgroup"), Some(false));
20653        assert!(set_seam("selgroup", true, None));
20654        assert_eq!(seam_state("selgroup"), Some(true));
20655        assert_eq!(sel_group_spec(), "dn:auto+gu:auto");
20656        assert!(set_seam("selgroup", false, None));
20657        assert_eq!(seam_state("selgroup"), Some(false));
20658        assert_eq!(sel_group_spec(), "dn:off+gu:off");
20659        // One family armed is still "armed", or an A/B that moved only the down half would
20660        // restore to OFF and lose the entry state.
20661        assert!(set_sel_group("dn:4:4+gu:off"));
20662        assert_eq!(seam_state("selgroup"), Some(true));
20663        set_sel_group("off");
20664        // Listed name and dispatch arm agree (the drift `seam_names` cannot detect alone).
20665        assert!(seam_names().contains(&"selgroup"));
20666        assert!(seam_exists("selgroup"));
20667    }
20668}
20669
20670// ============================================================ TP2/EP2 placement unit tests
20671//
20672// SCOPE, stated because this file is a GPU forward and these tests touch no GPU: every
20673// assertion below is over `Tp2Placement`/`LayerPlacement`, which are pure host logic: map
20674// parsing, the fail-closed refusal set, the bank-split arithmetic (`card1`/`local_of`/
20675// `rank_of`) and the even-split control-arm property. They run in plain `cargo test` on any
20676// machine, which is the point: the two-card BEHAVIOUR needs a box, but the two-card
20677// BOOKKEEPING is the part that silently moves expert weights under the router, and it had no
20678// coverage at all before this lane (`qwen4exp_gpu.rs` carried no test module).
20679//
20680// Lane: research/qwen4exp-bringup-20260829/ep2/EP2-DESIGN.md.
20681#[cfg(test)]
20682mod tp2_placement_tests {
20683    use super::{LayerPlacement, Tp2Placement};
20684
20685    /// One `memra-ep-map-v1` document over `experts` experts, `layers` = the (layer,
20686    /// assignment) rows given. Written through a temp file because `load` takes a path
20687    /// (the production door is `MEMRA_Q4E_EP_MAP=<path>`).
20688    fn write_map(name: &str, body: &str) -> std::path::PathBuf {
20689        let path = std::env::temp_dir().join(format!(
20690            "memra-q4e-ep-map-{name}-{}.json",
20691            std::process::id()
20692        ));
20693        std::fs::write(&path, body).expect("write map fixture");
20694        path
20695    }
20696
20697    fn load(name: &str, body: &str, expert_count: usize) -> Result<Tp2Placement, String> {
20698        let path = write_map(name, body);
20699        let out = Tp2Placement::load(&path, expert_count).map_err(|e| e.to_string());
20700        let _ = std::fs::remove_file(&path);
20701        out
20702    }
20703
20704    /// `{"format": ..., "ranks": 2, "entry_rank": 0, "expert_count": 4, <body>}`
20705    fn doc(body: &str) -> String {
20706        format!(
20707            "{{\"format\": \"memra-ep-map-v1\", \"strategy\": \"coactivation\", \
20708             \"ranks\": 2, \"entry_rank\": 0, \"expert_count\": 4, {body}}}"
20709        )
20710    }
20711
20712    fn assert_refuses(name: &str, body: &str, expert_count: usize, clause: &str) {
20713        match load(name, body, expert_count) {
20714            Ok(_) => panic!("{name}: expected a refusal naming {clause:?}, but the map loaded"),
20715            Err(msg) => {
20716                assert!(
20717                    msg.contains(clause),
20718                    "{name}: refusal must name the broken clause {clause:?}, got: {msg}"
20719                );
20720                // Every refusal names the FILE too, or the placement lane cannot tell
20721                // which of several candidate maps it has to fix.
20722                assert!(
20723                    msg.contains("MEMRA_Q4E_EP_MAP"),
20724                    "{name}: refusal must name the flag/file, got: {msg}"
20725                );
20726            }
20727        }
20728    }
20729
20730    // ---------------------------------------------------------------- the control arm
20731
20732    /// The unset door is the even split, and the even split is the CONTROL ARM of the
20733    /// placement A/B. Its bit-identity claim rests on exactly three properties, all
20734    /// asserted here rather than argued: card 0 addresses its full resident bank by
20735    /// GLOBAL id (no remap), card 1's gather order is the ascending suffix (a contiguous
20736    /// copy of what the pre-seam code sliced), and `is_even` recognises it.
20737    #[test]
20738    fn even_split_is_the_contiguous_suffix_control_arm() {
20739        let p = Tp2Placement::even(512);
20740        assert_eq!(p.strategy(), "even");
20741        assert_eq!(p.entry_rank(), 0);
20742        assert!(p.source().contains("MEMRA_Q4E_EP_MAP unset"));
20743
20744        let l = p.layer(0, 512).expect("even split resolves every layer");
20745        assert!(l.is_even(), "the built-in even split must report as even");
20746        assert_eq!(l.card1.len(), 256);
20747        // Ascending contiguous suffix.
20748        assert_eq!(l.card1, (256u32..512).collect::<Vec<_>>());
20749        for e in 0..256 {
20750            assert_eq!(l.rank(e), 0, "expert {e} belongs to card 0");
20751            assert_eq!(l.local(e), e, "card-0 local slot IS the global id");
20752        }
20753        for (slot, e) in (256..512).enumerate() {
20754            assert_eq!(l.rank(e), 1, "expert {e} belongs to card 1");
20755            assert_eq!(l.local(e), slot, "card-1 local slot is the gather position");
20756        }
20757        // Every MoE layer index resolves identically; the even split is layer-independent.
20758        let l47 = p.layer(47, 512).expect("layer 47");
20759        assert_eq!(l47.card1, l.card1);
20760    }
20761
20762    /// A MEASURED map moves bytes, and the local-slot bookkeeping is what keeps the
20763    /// router and the bank agreeing. Non-contiguous ownership is the whole point of
20764    /// co-activation placement, so it is the case the arithmetic must get right.
20765    #[test]
20766    fn measured_map_resolves_ascending_gather_and_local_slots() {
20767        // 4 experts, card 1 owns {0, 3}, deliberately NOT a suffix.
20768        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [1, 0, 0, 1]}]";
20769        let p = load("measured", &doc(body), 4).expect("balanced map loads");
20770        assert_eq!(p.strategy(), "coactivation");
20771        let l = p.layer(0, 4).expect("layer 0");
20772
20773        assert!(
20774            !l.is_even(),
20775            "a non-suffix placement is not the control arm"
20776        );
20777        // ASCENDING is load-bearing: it makes the gather order a function of the map
20778        // alone, so no host set-iteration order can leak into device bytes.
20779        assert_eq!(l.card1, vec![0u32, 3]);
20780        assert_eq!((l.rank(0), l.rank(1), l.rank(2), l.rank(3)), (1, 0, 0, 1));
20781        // card 1: local slot = position in `card1`.
20782        assert_eq!(l.local(0), 0);
20783        assert_eq!(l.local(3), 1);
20784        // card 0: local slot = the global id, untouched.
20785        assert_eq!(l.local(1), 1);
20786        assert_eq!(l.local(2), 2);
20787    }
20788
20789    /// `is_even` must not be fooled by a BALANCED-but-permuted map: it is the predicate a
20790    /// receipt uses to claim "this run was the control arm", so a false positive would let
20791    /// a measured-placement run be banked as its own control.
20792    #[test]
20793    fn is_even_rejects_a_balanced_permutation() {
20794        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 1, 1, 0]}]";
20795        let p = load("perm", &doc(body), 4).expect("balanced map loads");
20796        let l = p.layer(0, 4).expect("layer 0");
20797        assert_eq!(l.card1, vec![1u32, 2]);
20798        assert!(!l.is_even());
20799    }
20800
20801    /// A map whose assignment IS the even suffix must be recognised as the control arm,
20802    /// so the A/B harness can prove its two arms are the same program.
20803    #[test]
20804    fn an_explicit_even_map_matches_the_builtin_even_split() {
20805        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]";
20806        let p = load("explicit-even", &doc(body), 4).expect("even map loads");
20807        let l = p.layer(0, 4).expect("layer 0");
20808        let builtin = Tp2Placement::even(4).layer(0, 4).expect("builtin");
20809        assert!(l.is_even());
20810        assert_eq!(l.card1, builtin.card1);
20811        for e in 0..4 {
20812            assert_eq!(l.rank(e), builtin.rank(e), "rank of expert {e}");
20813            assert_eq!(l.local(e), builtin.local(e), "local slot of expert {e}");
20814        }
20815    }
20816
20817    // ---------------------------------------------------------------- the refusal set
20818    //
20819    // One test per contract clause. A half-applied placement moves expert weights under
20820    // the router and reads as a MODEL bug rather than a config bug, so each of these is a
20821    // load-time refusal by name, and each refusal has to name the clause it broke.
20822
20823    #[test]
20824    fn refuses_a_foreign_format() {
20825        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]";
20826        let text = format!(
20827            "{{\"format\": \"memra-ep-map-v2\", \"ranks\": 2, \"expert_count\": 4, {body}}}"
20828        );
20829        assert_refuses("format", &text, 4, "memra-ep-map-v1");
20830    }
20831
20832    #[test]
20833    fn refuses_a_rank_count_that_is_not_two() {
20834        let text = "{\"format\": \"memra-ep-map-v1\", \"ranks\": 4, \"expert_count\": 4, \
20835                    \"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]}";
20836        assert_refuses("ranks", text, 4, "exactly two cards");
20837    }
20838
20839    #[test]
20840    fn refuses_an_expert_count_that_is_not_the_plans() {
20841        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]";
20842        assert_refuses("experts", &doc(body), 8, "expert_count=4");
20843    }
20844
20845    #[test]
20846    fn refuses_an_entry_rank_outside_the_two_cards() {
20847        let text = "{\"format\": \"memra-ep-map-v1\", \"ranks\": 2, \"entry_rank\": 2, \
20848                    \"expert_count\": 4, \
20849                    \"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]}";
20850        assert_refuses("entry", text, 4, "entry_rank=2");
20851    }
20852
20853    #[test]
20854    fn refuses_a_document_with_no_layers_array() {
20855        assert_refuses("nolayers", &doc("\"strategy2\": 0"), 4, "no `layers` array");
20856    }
20857
20858    #[test]
20859    fn refuses_an_empty_layers_array() {
20860        assert_refuses(
20861            "emptylayers",
20862            &doc("\"layers\": []"),
20863            4,
20864            "`layers` is empty",
20865        );
20866    }
20867
20868    #[test]
20869    fn refuses_an_assignment_of_the_wrong_length() {
20870        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 1]}]";
20871        assert_refuses("shortassign", &doc(body), 4, "expected 4");
20872    }
20873
20874    #[test]
20875    fn refuses_a_rank_id_outside_the_two_cards() {
20876        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 7]}]";
20877        assert_refuses("badrank", &doc(body), 4, "expert 3");
20878    }
20879
20880    /// The clause with the sharpest consequence: the card-1 bank halves are EQUAL-SIZE
20881    /// device allocations, so an unbalanced map is out-of-bounds rather than merely
20882    /// slower. The refusal must also point at the tool's rebalance knob.
20883    #[test]
20884    fn refuses_an_unbalanced_layer_and_names_the_rebalance_knob() {
20885        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 1, 1, 1]}]";
20886        assert_refuses("unbalanced", &doc(body), 4, "card 1 owns 3 experts");
20887        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 1, 1, 1]}]";
20888        assert_refuses("unbalanced2", &doc(body), 4, "--balance-tolerance");
20889    }
20890
20891    /// A map that covers SOME MoE layers is not a placement. Falling the uncovered layers
20892    /// back to the even split would make the receipt a lie about which placement ran.
20893    #[test]
20894    fn refuses_a_layer_the_map_does_not_cover() {
20895        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]";
20896        let p = load("partial", &doc(body), 4).expect("map loads");
20897        assert!(p.layer(0, 4).is_ok(), "the covered layer resolves");
20898        let msg = p
20899            .layer(1, 4)
20900            .expect_err("an uncovered MoE layer must refuse")
20901            .to_string();
20902        assert!(msg.contains("does not cover MoE layer 1"), "got: {msg}");
20903        assert!(
20904            msg.contains("partly-applied map is not a placement"),
20905            "the refusal must say WHY it is fail-closed, got: {msg}"
20906        );
20907    }
20908
20909    #[test]
20910    fn refuses_a_layer_whose_expert_count_disagrees_with_the_map() {
20911        let p = Tp2Placement::even(512);
20912        let msg = p
20913            .layer(0, 256)
20914            .expect_err("a layer geometry the map is not for must refuse")
20915            .to_string();
20916        assert!(msg.contains("map is for 512"), "got: {msg}");
20917    }
20918
20919    #[test]
20920    fn refuses_an_unreadable_map_path() {
20921        let missing = std::env::temp_dir().join(format!(
20922            "memra-q4e-ep-map-absent-{}.json",
20923            std::process::id()
20924        ));
20925        let _ = std::fs::remove_file(&missing);
20926        let msg = Tp2Placement::load(&missing, 4)
20927            .expect_err("an unreadable map must refuse at the load preflight")
20928            .to_string();
20929        assert!(msg.contains("MEMRA_Q4E_EP_MAP"), "got: {msg}");
20930    }
20931
20932    /// An ODD routed bank has no equal halves, on either path.
20933    ///
20934    /// Scoped honestly, because the guard's first justification overclaimed and review caught
20935    /// it: production cannot reach this, since `build_tp2_shard` refuses `experts % 2 != 0`
20936    /// before it asks for a `LayerPlacement`. These are `pub` entry points and the refusal
20937    /// belongs on the contract it breaks.
20938    ///
20939    /// The loaded arm below is the one that closes a REAL hole, and it is deliberately the
20940    /// BALANCED odd map: `half = expert_count / 2` floors, so 2-of-5 on card 1 satisfies
20941    /// `on1 == half` and loaded clean before this check. An unbalanced odd map (3-of-5) would
20942    /// have been refused by the balance clause already, so testing only that would have made
20943    /// this arm nearly vacuous.
20944    #[test]
20945    fn refuses_an_odd_routed_bank_on_both_paths() {
20946        // built-in even split
20947        let msg = Tp2Placement::even(5)
20948            .layer(0, 5)
20949            .expect_err("an odd bank has no two-card placement")
20950            .to_string();
20951        assert!(msg.contains("ODD"), "got: {msg}");
20952        assert!(msg.contains("EQUAL-size"), "got: {msg}");
20953        // loaded map, BALANCED under the floored half (on1 == 5/2 == 2): this one passed the
20954        // balance clause before the geometry check existed.
20955        let balanced_odd = "{\"format\": \"memra-ep-map-v1\", \"ranks\": 2, \
20956                            \"expert_count\": 5, \
20957                            \"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 0, 1, 1]}]}";
20958        assert_refuses("odd-balanced", balanced_odd, 5, "ODD");
20959        // and the unbalanced odd map, which the balance clause would also have caught, so this
20960        // asserts the geometry clause wins the race and names the real problem.
20961        let unbalanced_odd = "{\"format\": \"memra-ep-map-v1\", \"ranks\": 2, \
20962                              \"expert_count\": 5, \
20963                              \"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1, 1]}]}";
20964        assert_refuses("odd-unbalanced", unbalanced_odd, 5, "ODD");
20965    }
20966
20967    // ---------------------------------------------------------------- bank-split arithmetic
20968
20969    /// The invariant the card-1 bank upload depends on, asserted over EVERY expert of a
20970    /// serving-geometry bank: exactly half the ids land on card 1, `card1` is strictly
20971    /// ascending, and `local_of` is a bijection onto `0..half` for card 1 and the identity
20972    /// on card 0. A violation here is an out-of-bounds device read, not a slow placement.
20973    #[test]
20974    fn local_slots_are_a_bijection_at_the_serving_geometry() {
20975        let experts = 512usize;
20976        let half = experts / 2;
20977        // A deterministic non-contiguous, exactly-balanced placement: alternate ownership.
20978        let assignment: Vec<String> = (0..experts).map(|e| (e % 2).to_string()).collect();
20979        let body = format!(
20980            "\"layers\": [{{\"layer\": 0, \"assignment\": [{}]}}]",
20981            assignment.join(", ")
20982        );
20983        let text = format!(
20984            "{{\"format\": \"memra-ep-map-v1\", \"ranks\": 2, \"expert_count\": {experts}, \
20985             {body}}}"
20986        );
20987        let p = load("bijection", &text, experts).expect("balanced alternating map loads");
20988        let l: LayerPlacement = p.layer(0, experts).expect("layer 0");
20989
20990        assert_eq!(l.card1.len(), half, "card 1 must own exactly half the bank");
20991        assert!(
20992            l.card1.windows(2).all(|w| w[0] < w[1]),
20993            "the gather order must be strictly ascending"
20994        );
20995        let mut seen = vec![false; half];
20996        for e in 0..experts {
20997            match l.rank(e) {
20998                0 => assert_eq!(l.local(e), e, "card-0 slot is the global id"),
20999                1 => {
21000                    let slot = l.local(e);
21001                    assert!(slot < half, "card-1 slot {slot} outside its half-bank");
21002                    assert!(!seen[slot], "card-1 slot {slot} claimed twice");
21003                    seen[slot] = true;
21004                }
21005                r => panic!("expert {e} has rank {r}"),
21006            }
21007        }
21008        assert!(seen.into_iter().all(|s| s), "card-1 slots must be dense");
21009        assert!(!l.is_even());
21010    }
21011}