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
3049fn micro_norm_on() -> bool {
3050    hc_micro_on()
3051}
3052
3053fn micro_inj_on() -> bool {
3054    hc_micro_on()
3055}
3056
3057fn micro_shexp_on() -> bool {
3058    hc_micro_on()
3059}
3060
3061/// Run `f` as a named profile section (sync–time–sync when profiling is on).
3062fn prof_section<T>(e: &Engine, name: &'static str, f: impl FnOnce() -> Res<T>) -> Res<T> {
3063    if !prof::on() {
3064        return f();
3065    }
3066    e.gpu.stream().synchronize()?;
3067    let t0 = std::time::Instant::now();
3068    let out = f()?;
3069    e.gpu.stream().synchronize()?;
3070    prof::add(name, t0.elapsed().as_secs_f64());
3071    Ok(out)
3072}
3073
3074// ---------------------------------------------------------------- host twins (oracle math)
3075
3076fn host_sigmoid(x: f32) -> f32 {
3077    1.0 / (1.0 + (-x).exp())
3078}
3079
3080/// memra_reference `softmax_in_place` twin.
3081fn host_softmax(values: &mut [f32]) {
3082    let max = values.iter().copied().fold(f32::NEG_INFINITY, f32::max);
3083    let mut sum = 0.0;
3084    for value in values.iter_mut() {
3085        *value = (*value - max).exp();
3086        sum += *value;
3087    }
3088    for value in values {
3089        *value /= sum;
3090    }
3091}
3092
3093/// The router renorm denominator floor (memra_reference `route_experts`, mirrored by
3094/// the device twin). Note it is UNBINDABLE on real softmax geometry: the top-k weights
3095/// are the k largest of a distribution summing to 1, so their sum is >= k/experts
3096/// (10/512 ~ 0.0195 >> 6.1e-5) — kept because the reference ships it.
3097const ROUTE_DENOM_FLOOR: f32 = 6.103_515_6e-5;
3098
3099/// memra_reference `route_experts` twin, Softmax arm only (qwen4_exp router — softmax,
3100/// top-k renormalized with the 6.1035156e-5 floor, tie rule score-desc/index-asc).
3101fn host_route_softmax_topk(logits: &[f32], selected: usize) -> Vec<(usize, f32)> {
3102    let mut weights = logits.to_vec();
3103    host_softmax(&mut weights);
3104    let mut indices: Vec<usize> = (0..logits.len()).collect();
3105    indices.sort_by(|&left, &right| {
3106        weights[right]
3107            .total_cmp(&weights[left])
3108            .then(left.cmp(&right))
3109    });
3110    indices.truncate(selected);
3111    let denominator = indices
3112        .iter()
3113        .map(|&index| weights[index])
3114        .sum::<f32>()
3115        .max(ROUTE_DENOM_FLOOR);
3116    indices
3117        .into_iter()
3118        .map(|index| (index, weights[index] / denominator))
3119        .collect()
3120}
3121
3122/// memra_reference `rms_norm` twin (host, effective weights).
3123fn host_rms_norm(x: &mut [f32], width: usize, weight: &[f32], epsilon: f32) {
3124    for row in x.chunks_exact_mut(width) {
3125        let mean_square = row.iter().map(|v| v * v).sum::<f32>() / width as f32;
3126        let inverse = 1.0 / (mean_square + epsilon).sqrt();
3127        for (value, w) in row.iter_mut().zip(weight) {
3128            *value = *value * inverse * w;
3129        }
3130    }
3131}
3132
3133/// memra_reference `apply_rope_at_position` twin (NeoX split-half). `yarn` = the shared
3134/// (divisor table, mscale) pair when the plan carries YaRN factors — identical divisor
3135/// semantics to the reference (`frequency / divisor`, cos/sin scaled by mscale); `None`
3136/// keeps the historical byte-exact plain path.
3137fn host_rope_at(
3138    values: &mut [f32],
3139    head_dim: usize,
3140    dimensions: usize,
3141    base: f32,
3142    yarn: Option<(&[f32], f32)>,
3143    position: usize,
3144) {
3145    let dimensions = dimensions.min(head_dim) / 2 * 2;
3146    let half = dimensions / 2;
3147    for head in values.chunks_exact_mut(head_dim) {
3148        for index in 0..half {
3149            let frequency = base.powf(-2.0 * index as f32 / dimensions as f32);
3150            let frequency = match yarn {
3151                Some((ff, _)) => frequency / ff[index],
3152                None => frequency,
3153            };
3154            let angle = position as f32 * frequency;
3155            let (sin, cos) = angle.sin_cos();
3156            let (sin, cos) = match yarn {
3157                Some((_, mscale)) => (sin * mscale, cos * mscale),
3158                None => (sin, cos),
3159            };
3160            let first = head[index];
3161            let second = head[index + half];
3162            head[index] = first * cos - second * sin;
3163            head[index + half] = first * sin + second * cos;
3164        }
3165    }
3166}
3167
3168/// What the forward's exit computes (chunked long-context prefill skips the head: the
3169/// [t, vocab] logits block of a big chunk is gigabytes and reads/writes no state).
3170#[derive(Clone, Copy, PartialEq, Eq)]
3171pub enum HeadMode {
3172    /// Exit mixer + lm_head on every row ([t, vocab] logits) — the historical shape.
3173    All,
3174    /// Exit mixer on the chunk, lm_head on the LAST row only ([vocab] logits).
3175    LastRow,
3176    /// No exit mixer, no lm_head, empty return (mid-prefill chunks).
3177    Skip,
3178}
3179
3180/// One query row's QSA visibility in BLOCK form — the selection's native shape (the
3181/// dense [t, t_kv] mask is a rendering of this for the smem-bounded masked kernel; the
3182/// long-context block-list kernel consumes it directly).
3183struct RowSel {
3184    /// Structural fast path (complete <= budget): the FULL causal prefix is visible.
3185    full: bool,
3186    /// Selected complete blocks, ascending. Empty when `full`.
3187    blocks: Vec<u32>,
3188    /// Visible prefix length (absolute row + 1). Positions
3189    /// [complete*block_size .. visible) are the always-visible incomplete tail.
3190    visible: usize,
3191}
3192
3193/// Extend the POOLED indexer-key cache to cover every complete block of `raw_keys`:
3194/// fp32 mean over the block's raw rows (offset-outer/dim-inner, the historical loop
3195/// order), k_layernorm, rope at the block-start position + pos_off. A block's pooled key
3196/// never depends on the query row, so each block is computed ONCE — bit-identical to the
3197/// historical per-(row, block) recompute.
3198#[allow(clippy::too_many_arguments)]
3199fn extend_pooled_keys(
3200    pooled_keys: &mut Vec<f32>,
3201    raw_keys: &IdxRawCache,
3202    head_dim: usize,
3203    block_size: usize,
3204    idx_k_norm: &[f32],
3205    epsilon: f32,
3206    rope_dims: usize,
3207    rope_base: f32,
3208    yarn: Option<(&[f32], f32)>,
3209    pos_off: usize,
3210) {
3211    let complete_total = raw_keys.rows(head_dim) / block_size;
3212    let cached = pooled_keys.len() / head_dim;
3213    let mut block_rows: Vec<f32> = Vec::new();
3214    for block in cached..complete_total {
3215        let start = block * block_size;
3216        // idxq lane: dequant the block's raw rows at read; the fp32 mean-pool below is
3217        // the historical op order verbatim (f32 arm: an exact copy of the same rows).
3218        raw_keys.rows_f32(start, block_size, head_dim, &mut block_rows);
3219        let mut pooled = vec![0.0f32; head_dim];
3220        for offset in 0..block_size {
3221            for dim in 0..head_dim {
3222                pooled[dim] += block_rows[offset * head_dim + dim];
3223            }
3224        }
3225        for value in &mut pooled {
3226            *value /= block_size as f32;
3227        }
3228        host_rms_norm(&mut pooled, head_dim, idx_k_norm, epsilon);
3229        host_rope_at(
3230            &mut pooled,
3231            head_dim,
3232            rope_dims,
3233            rope_base,
3234            yarn,
3235            start + pos_off,
3236        );
3237        pooled_keys.extend_from_slice(&pooled);
3238    }
3239}
3240
3241/// Comparator of the pinned tie rule: score desc, block index asc (a STRICT total order
3242/// — `total_cmp` plus the index tiebreak leaves no equal pair).
3243#[inline]
3244fn sel_cmp(scores: &[f32], a: u32, b: u32) -> std::cmp::Ordering {
3245    scores[b as usize]
3246        .total_cmp(&scores[a as usize])
3247        .then(a.cmp(&b))
3248}
3249
3250/// Top-`budget` blocks under the pinned tie rule, returned ASCENDING. Replaces the
3251/// historical full `sort_by` + `take(budget)` with `select_nth_unstable_by` under the
3252/// SAME strict total order — the kept SET is identical by definition of a total order
3253/// (both keep exactly the `budget` smallest elements under the comparator), and the
3254/// emitted ascending order erases any within-set permutation. When the block count is
3255/// large, disjoint ranges are reduced to per-range top-`budget` candidates first: any
3256/// global top-`budget` element is beaten by fewer than `budget` blocks overall, hence by
3257/// fewer than `budget` in its own range, hence survives its range cut — the union of
3258/// range winners contains the global set, and the final cut recovers it EXACTLY.
3259fn top_blocks_ascending(scores: &[f32], budget: usize, threads: usize) -> Vec<u32> {
3260    fn cut(scores: &[f32], idx: &mut Vec<u32>, budget: usize) {
3261        let k = budget.min(idx.len());
3262        if k < idx.len() {
3263            idx.select_nth_unstable_by(k - 1, |&a, &b| sel_cmp(scores, a, b));
3264            idx.truncate(k);
3265        }
3266    }
3267    let complete = scores.len();
3268    debug_assert!(budget < complete);
3269    const PAR_MIN: usize = 1 << 15;
3270    let mut candidates: Vec<u32> = if threads > 1 && complete >= PAR_MIN {
3271        let ranges: Vec<(u32, u32)> = {
3272            let per = complete.div_ceil(threads);
3273            (0..threads)
3274                .map(|i| ((i * per) as u32, ((i + 1) * per).min(complete) as u32))
3275                .filter(|(a, b)| a < b)
3276                .collect()
3277        };
3278        std::thread::scope(|scope| {
3279            let handles: Vec<_> = ranges
3280                .iter()
3281                .map(|&(a, b)| {
3282                    scope.spawn(move || {
3283                        let mut idx: Vec<u32> = (a..b).collect();
3284                        cut(scores, &mut idx, budget);
3285                        idx
3286                    })
3287                })
3288                .collect();
3289            handles
3290                .into_iter()
3291                .flat_map(|h| h.join().unwrap())
3292                .collect()
3293        })
3294    } else {
3295        (0..complete as u32).collect()
3296    };
3297    cut(scores, &mut candidates, budget);
3298    candidates.sort_unstable();
3299    candidates
3300}
3301
3302/// Score every complete block for one prepared query row (relu-sum over heads / sqrt(d),
3303/// fp32 — the reference arithmetic verbatim, reading the pooled cache). Parallel over
3304/// DISJOINT block ranges when large: per-block values are independent, so the split
3305/// changes nothing but wall time.
3306fn score_blocks(
3307    query: &[f32],
3308    pooled_keys: &[f32],
3309    heads: usize,
3310    head_dim: usize,
3311    complete: usize,
3312    scale: f32,
3313    threads: usize,
3314) -> Vec<f32> {
3315    let mut scores = vec![0.0f32; complete];
3316    let run = |scores: &mut [f32], block0: usize| {
3317        for (i, slot) in scores.iter_mut().enumerate() {
3318            let block = block0 + i;
3319            let pooled = &pooled_keys[block * head_dim..(block + 1) * head_dim];
3320            let mut score = 0.0f32;
3321            for head in 0..heads {
3322                let mut dot = 0.0f32;
3323                for dim in 0..head_dim {
3324                    dot += query[head * head_dim + dim] * pooled[dim];
3325                }
3326                score += dot.max(0.0);
3327            }
3328            *slot = score / scale;
3329        }
3330    };
3331    const PAR_MIN: usize = 1 << 14;
3332    if threads > 1 && complete >= PAR_MIN {
3333        let per = complete.div_ceil(threads);
3334        let run = &run;
3335        std::thread::scope(|scope| {
3336            for (i, chunk) in scores.chunks_mut(per).enumerate() {
3337                scope.spawn(move || run(chunk, i * per));
3338            }
3339        });
3340    } else {
3341        run(&mut scores, 0);
3342    }
3343    scores
3344}
3345
3346/// memra_reference `micro_block_selection_mask` twin over the raw-key CACHE — the decode
3347/// form of the same program in BLOCK form: per query token at absolute position
3348/// `base_pos + qt`, score the pooled complete blocks (cache: `extend_pooled_keys`), then
3349/// the pinned tie rule (score desc, block index asc) and the always-visible incomplete
3350/// tail. Values and selected sets are bit-identical to the historical per-row recompute
3351/// (see the helper docs above); rows are computed in PARALLEL when the work is large
3352/// (rows are independent; single-row chunks parallelize across block ranges instead).
3353#[allow(clippy::too_many_arguments)]
3354fn indexer_select_rows(
3355    overlay: &MicroBlockIndexPlan,
3356    rope_base: f32,
3357    // YaRN (divisors, mscale) — the indexer consumes the MAIN rotary (SEMANTICS.md §Rope),
3358    // so the caller passes the layer's shared table; `None` on the shipped config.
3359    yarn: Option<(&[f32], f32)>,
3360    epsilon: f32,
3361    idx_q_norm: &[f32],
3362    idx_k_norm: &[f32],
3363    proj_rows: &[f32],      // [t, (ih+ikv)*id] this chunk's index_qk_proj output
3364    raw_keys: &IdxRawCache, // [t_kv, id] cache INCLUDING the current chunk
3365    pooled_keys: &mut Vec<f32>,
3366    // Device scorer (long-context lane): `Some((engine, device pooled mirror, mirrored
3367    // rows))` runs block scoring on the GPU with the host twin's exact arithmetic
3368    // (thread-per-block sequential dim loop, same relu-sum, same division — bit-identical
3369    // scores, identical selected sets); the mirror grows by H2D of the new rows. `None`
3370    // keeps the pure-host path (the tiny/reference shape).
3371    mut dev: Option<(&Engine, &mut Option<CudaSlice<f32>>, &mut usize)>,
3372    base_pos: usize,
3373    t: usize,
3374    t_kv: usize,
3375    // Rope-position offset: cache row i carries absolute position i + pos_off. 0 for
3376    // the trunk; 1 for the MTP draft, whose row i holds TARGET position i + 1
3377    // (position 0 never enters the draft — SGLang alignment, SEMANTICS.md §MTP).
3378    pos_off: usize,
3379) -> Res<Vec<RowSel>> {
3380    let heads = overlay.query_heads as usize;
3381    let head_dim = overlay.head_dim as usize;
3382    let block_size = overlay.block_size as usize;
3383    let budget_blocks = overlay.budget_blocks as usize;
3384    let rope_dims = overlay.rope_dimensions as usize;
3385    let qk_width = (heads + overlay.kv_heads as usize) * head_dim;
3386    let scale = (head_dim as f32).sqrt();
3387    debug_assert_eq!(raw_keys.rows(head_dim), t_kv);
3388    extend_pooled_keys(
3389        pooled_keys,
3390        raw_keys,
3391        head_dim,
3392        block_size,
3393        idx_k_norm,
3394        epsilon,
3395        rope_dims,
3396        rope_base,
3397        yarn,
3398        pos_off,
3399    );
3400    let threads = std::thread::available_parallelism()
3401        .map(|n| n.get())
3402        .unwrap_or(1);
3403    // ---- device scoring path: mirror the new pooled rows, then score in row
3404    // sub-batches (the score slab is rows x n_blocks floats — at 250k blocks a whole
3405    // prefill chunk of rows would be terabytes, so rows batch).
3406    if let Some((e, mirror, mirrored)) = dev.as_mut() {
3407        let rows_needed: Vec<usize> = (0..t)
3408            .map(|qt| (base_pos + qt + 1) / block_size)
3409            .filter(|&c| c > budget_blocks)
3410            .collect();
3411        if let Some(&max_blocks) = rows_needed.iter().max() {
3412            let pooled_rows = pooled_keys.len() / head_dim;
3413            // Grow + fill the device mirror with any rows it does not have yet.
3414            let want = pooled_rows.max(max_blocks);
3415            // POOL_PLANES regions of `cap_rows * head_dim`: the row-major mirror, then the
3416            // dim-major `poolT` plane. The pitch of the plane is `cap_rows`, so it is baked at
3417            // allocation and a capacity change invalidates the plane's addressing — hence the
3418            // full re-mirror below rather than a strided forward copy of the old plane.
3419            if mirror
3420                .as_ref()
3421                .is_none_or(|m| m.len() < want * head_dim * POOL_PLANES)
3422            {
3423                let cap_rows = want.next_power_of_two().max(1024);
3424                let fresh = e.zeros(cap_rows * head_dim * POOL_PLANES)?;
3425                // The old growth path copied the mirrored prefix forward and kept `**mirrored`.
3426                // That is not sound for the plane (new pitch => every dim lands elsewhere), and a
3427                // half-addressed plane scores stale keys silently. Re-mirror from the host cache
3428                // instead, which holds every row and is the same source the append already uses.
3429                // Costs one H2D of the pooled cache per capacity DOUBLING (log2 times over a
3430                // fill), against a class of wrong-value bug this lane has already paid for twice.
3431                **mirror = Some(fresh);
3432                **mirrored = 0;
3433            }
3434            let m = mirror.as_mut().expect("allocated above");
3435            if pooled_rows > **mirrored {
3436                let delta = &pooled_keys[**mirrored * head_dim..pooled_rows * head_dim];
3437                let mut view = m.slice_mut(**mirrored * head_dim..pooled_rows * head_dim);
3438                e.gpu.stream().memcpy_htod(delta, &mut view)?;
3439                // `poolT`: keep the DIM-MAJOR twin of the same rows in the second half of the
3440                // buffer. Both layouts are maintained UNCONDITIONALLY and only the kernel choice
3441                // reads the seam. Two reasons, and the second is the important one:
3442                //
3443                //  - Experimental design. The append is then identical in both A/B arms, so the
3444                //    measurement isolates exactly the variable under test (the READ pattern) and
3445                //    the transpose cost cannot flatter or penalise either arm.
3446                //  - There is no silent-wrong-value mode. A seam that is flippable between timed
3447                //    rounds plus a layout that is only maintained while armed means an arm that
3448                //    was OFF for a while leaves the plane missing every row appended meanwhile —
3449                //    and a stale pooled plane scores stale keys, which reads as plausible output
3450                //    rather than as a failure. Maintaining both makes `**mirrored` the single
3451                //    truth for BOTH layouts, so a flip needs no rebuild and can leave nothing
3452                //    behind. (Same class as the `pooled_dev_rows` truncation trap already
3453                //    recorded at the rewind sites.)
3454                //
3455                // Instrument cost, stated: one pooled plane of extra VRAM (33.5 MB at the 262,144
3456                // target geometry, 1.6% of the ~2 GB free there) plus one transpose over the
3457                // delta — 512 rows per 2,048-token prefill chunk, 0-1 rows per decode step. When
3458                // the A/B verdict lands, the losing layout goes away in the same commit; carrying
3459                // both is an A/B instrument, not a shipping design.
3460                let cap_rows = m.len() / (head_dim * POOL_PLANES);
3461                launch_qsa_pooled_transpose(
3462                    e,
3463                    m,
3464                    **mirrored,
3465                    pooled_rows - **mirrored,
3466                    head_dim,
3467                    cap_rows,
3468                )?;
3469                **mirrored = pooled_rows;
3470            }
3471            // Per-row prepared queries (norm + rope) — the host twin's own preparation.
3472            let mut sels: Vec<RowSel> = Vec::with_capacity(t);
3473            let mut queries: Vec<f32> = Vec::new();
3474            let mut scored_rows: Vec<usize> = Vec::new();
3475            for qt in 0..t {
3476                let row = base_pos + qt;
3477                let visible = row + 1;
3478                let complete = visible / block_size;
3479                if complete <= budget_blocks {
3480                    sels.push(RowSel {
3481                        full: true,
3482                        blocks: Vec::new(),
3483                        visible,
3484                    });
3485                    continue;
3486                }
3487                let mut query = proj_rows[qt * qk_width..qt * qk_width + heads * head_dim].to_vec();
3488                host_rms_norm(&mut query, head_dim, idx_q_norm, epsilon);
3489                host_rope_at(
3490                    &mut query,
3491                    head_dim,
3492                    rope_dims,
3493                    rope_base,
3494                    yarn,
3495                    row + pos_off,
3496                );
3497                queries.extend_from_slice(&query);
3498                scored_rows.push(qt);
3499                sels.push(RowSel {
3500                    full: false,
3501                    blocks: Vec::new(),
3502                    visible,
3503                });
3504            }
3505            // Row sub-batches bounded by the score slab (default 32 M floats = 128 MB).
3506            //
3507            // TUNABLE because this constant appears to SET THE 262k PERFORMANCE CLIFF.
3508            // `qsa.idx_host` grows linearly with fill up to 120,000 (2,710 -> 3,199 ms) and then
3509            // jumps 16x to 51,235 ms — 83% of a prefill chunk — somewhere before 131,072. The
3510            // arithmetic lands exactly there: rows per sub-batch is `SCORE_CAP / complete`, and
3511            // at fill 131,072 `complete = 32,768`, so `per = 1,024` and 2,048 scored rows fit in
3512            // EXACTLY 2 sub-batches; one block deeper it becomes 3. Each sub-batch does an
3513            // `e.htod` plus an `e.uninit` of up to 128 MB and ends in a BLOCKING `dtoh`, at
3514            // depths where card 0 has ~2-4 GB free.
3515            //
3516            // The test this knob exists for: if the cliff MOVES with the cap, the mechanism is
3517            // the sub-batch transition (and the fix is a persistent pooled slab, or a cap that
3518            // keeps the transition out of the product window). If the cliff does NOT move, the
3519            // hypothesis is dead and the next suspect is the blocking dtoh count.
3520            // Default 32 reproduces today's behaviour exactly.
3521            let score_cap_mf: usize = std::env::var("MEMRA_Q4E_IDX_SCORE_CAP_MF")
3522                .ok()
3523                .and_then(|v| v.parse::<usize>().ok())
3524                .filter(|v| *v > 0)
3525                .unwrap_or(32);
3526            let score_cap: usize = score_cap_mf << 20;
3527            #[allow(non_snake_case)]
3528            let SCORE_CAP = score_cap;
3529            let mut done = 0usize;
3530            while done < scored_rows.len() {
3531                // Every row in a batch scores its OWN block count; the kernel writes a
3532                // rows x max_blocks slab and each row reads its own prefix.
3533                let batch_max = scored_rows[done..]
3534                    .iter()
3535                    .map(|&qt| (base_pos + qt + 1) / block_size)
3536                    .max()
3537                    .unwrap_or(0);
3538                let per = (SCORE_CAP / batch_max.max(1)).max(1);
3539                let n = per.min(scored_rows.len() - done);
3540                let qslab = &queries[done * heads * head_dim..(done + n) * heads * head_dim];
3541                let q_dev = e.htod(qslab)?;
3542                let mut scores_dev = e.uninit(n * batch_max)?;
3543                launch_qsa_index_score(
3544                    e,
3545                    &q_dev,
3546                    m,
3547                    &mut scores_dev,
3548                    heads,
3549                    head_dim,
3550                    batch_max,
3551                    n,
3552                    scale,
3553                )?;
3554                if idx_sel_on() {
3555                    // Device selection (`idxsel`): read back rows x budget u32 instead of
3556                    // the rows x batch_max f32 slab, and never touch the scores on the
3557                    // host at all. The audit arm below is the ONLY thing that restores
3558                    // the slab dtoh, which is why it is an instrument and not an arm.
3559                    let counts: Vec<usize> = (0..n)
3560                        .map(|i| (base_pos + scored_rows[done + i] + 1) / block_size)
3561                        .collect();
3562                    let picked =
3563                        launch_qsa_index_topk(e, &scores_dev, &counts, batch_max, budget_blocks)?;
3564                    if idx_sel_audit_on() {
3565                        let host = e.dtoh(&scores_dev)?;
3566                        let mut mismatched = 0u64;
3567                        let mut deepest = 0u64;
3568                        for i in 0..n {
3569                            let complete = counts[i];
3570                            let row_scores = &host[i * batch_max..i * batch_max + complete];
3571                            let twin = top_blocks_ascending(row_scores, budget_blocks, threads);
3572                            if twin != picked[i] {
3573                                mismatched += 1;
3574                            }
3575                            deepest = deepest.max(complete as u64);
3576                        }
3577                        IDX_SEL_AUDIT_ROWS
3578                            .fetch_add(n as u64, std::sync::atomic::Ordering::Relaxed);
3579                        IDX_SEL_AUDIT_MISMATCH
3580                            .fetch_add(mismatched, std::sync::atomic::Ordering::Relaxed);
3581                        IDX_SEL_AUDIT_MAX_BLOCKS
3582                            .fetch_max(deepest, std::sync::atomic::Ordering::Relaxed);
3583                        if mismatched > 0 {
3584                            return Err(format!(
3585                                "idxsel audit: {mismatched} of {n} device selections differ \
3586                                 from the host twin (ids or order) at fill {t_kv}"
3587                            )
3588                            .into());
3589                        }
3590                    }
3591                    for (i, blocks) in picked.into_iter().enumerate() {
3592                        sels[scored_rows[done + i]].blocks = blocks;
3593                    }
3594                } else {
3595                    let host = e.dtoh(&scores_dev)?;
3596                    for i in 0..n {
3597                        let qt = scored_rows[done + i];
3598                        let complete = (base_pos + qt + 1) / block_size;
3599                        let row_scores = &host[i * batch_max..i * batch_max + complete];
3600                        sels[qt].blocks = top_blocks_ascending(row_scores, budget_blocks, threads);
3601                    }
3602                }
3603                done += n;
3604            }
3605            for sel in &sels {
3606                if sel.visible == 0
3607                    || (!sel.full && sel.blocks.is_empty() && sel.visible % block_size == 0)
3608                {
3609                    return Err("indexer selection left a query with no visible source".into());
3610                }
3611            }
3612            return Ok(sels);
3613        }
3614    }
3615    let pooled_ref: &[f32] = pooled_keys;
3616    let select_row = |qt: usize, threads_in_row: usize| -> RowSel {
3617        let row = base_pos + qt;
3618        let position = row + pos_off;
3619        let visible = row + 1;
3620        let complete = visible / block_size;
3621        // Structural fast path (perf lane, semantic no-op): with complete <= budget the
3622        // top-k keeps EVERY complete block whatever the scores say, and the incomplete
3623        // tail is always visible — the row is the full causal prefix. Real geometry:
3624        // budget 512 x block 4 => every position < 2051 takes this path (SEMANTICS.md
3625        // §QSA); the scoring arm below stays the reference for long contexts and is
3626        // exercised by the tiny gate's budget-2 fixture at every position past 11.
3627        if complete <= budget_blocks {
3628            return RowSel {
3629                full: true,
3630                blocks: Vec::new(),
3631                visible,
3632            };
3633        }
3634        let mut query = proj_rows[qt * qk_width..qt * qk_width + heads * head_dim].to_vec();
3635        host_rms_norm(&mut query, head_dim, idx_q_norm, epsilon);
3636        host_rope_at(&mut query, head_dim, rope_dims, rope_base, yarn, position);
3637        let scores = score_blocks(
3638            &query,
3639            pooled_ref,
3640            heads,
3641            head_dim,
3642            complete,
3643            scale,
3644            threads_in_row,
3645        );
3646        let blocks = top_blocks_ascending(&scores, budget_blocks, threads_in_row);
3647        RowSel {
3648            full: false,
3649            blocks,
3650            visible,
3651        }
3652    };
3653    const ROW_PAR_MIN_WORK: usize = 1 << 16;
3654    let total_scored_blocks: usize = (0..t)
3655        .map(|qt| {
3656            let complete = (base_pos + qt + 1) / block_size;
3657            if complete <= budget_blocks {
3658                0
3659            } else {
3660                complete
3661            }
3662        })
3663        .sum();
3664    let sels: Vec<RowSel> = if t > 1 && threads > 1 && total_scored_blocks >= ROW_PAR_MIN_WORK {
3665        // Rows are independent: a work-stealing cursor over rows, each row sequential
3666        // inside (identical arithmetic to the sequential path).
3667        let cursor = std::sync::atomic::AtomicUsize::new(0);
3668        let mut out: Vec<Option<RowSel>> = (0..t).map(|_| None).collect();
3669        let slots = std::sync::Mutex::new(&mut out);
3670        std::thread::scope(|scope| {
3671            for _ in 0..threads.min(t) {
3672                scope.spawn(|| {
3673                    loop {
3674                        let qt = cursor.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
3675                        if qt >= t {
3676                            break;
3677                        }
3678                        let sel = select_row(qt, 1);
3679                        slots.lock().unwrap()[qt] = Some(sel);
3680                    }
3681                });
3682            }
3683        });
3684        out.into_iter().map(|s| s.unwrap()).collect()
3685    } else {
3686        (0..t).map(|qt| select_row(qt, threads)).collect()
3687    };
3688    for sel in &sels {
3689        if sel.visible == 0 || (!sel.full && sel.blocks.is_empty() && sel.visible % block_size == 0)
3690        {
3691            return Err("indexer selection left a query with no visible source".into());
3692        }
3693    }
3694    Ok(sels)
3695}
3696
3697/// Render row selections as the dense [t, t_kv] u8 mask the smem-bounded masked kernel
3698/// consumes — byte-identical to the historical `indexer_mask_rows` output.
3699fn rowsel_to_mask(sels: &[RowSel], block_size: usize, t_kv: usize) -> Vec<u8> {
3700    let t = sels.len();
3701    let mut mask = vec![0u8; t * t_kv];
3702    for (qt, sel) in sels.iter().enumerate() {
3703        let row = &mut mask[qt * t_kv..(qt + 1) * t_kv];
3704        if sel.full {
3705            for slot in row.iter_mut().take(sel.visible) {
3706                *slot = 1;
3707            }
3708            continue;
3709        }
3710        for &block in &sel.blocks {
3711            for offset in 0..block_size {
3712                row[block as usize * block_size + offset] = 1;
3713            }
3714        }
3715        let complete = sel.visible / block_size;
3716        for slot in row.iter_mut().take(sel.visible).skip(complete * block_size) {
3717            *slot = 1;
3718        }
3719    }
3720    mask
3721}
3722
3723/// Render row selections as ASCENDING position lists for the block-list attention
3724/// kernel: flat i32 positions + per-row (offset, count) meta. Every row is bounded by
3725/// budget*block + (block-1) + ... <= 2052 positions on real geometry, so the kernel's
3726/// smem stays fixed whatever t_kv is.
3727fn rowsel_positions(sels: &[RowSel], block_size: usize) -> (Vec<i32>, Vec<i32>, usize) {
3728    let mut flat: Vec<i32> = Vec::new();
3729    let mut meta: Vec<i32> = Vec::with_capacity(sels.len() * 2);
3730    let mut max_count = 0usize;
3731    for sel in sels {
3732        let start = flat.len();
3733        if sel.full {
3734            flat.extend(0..sel.visible as i32);
3735        } else {
3736            for &block in &sel.blocks {
3737                let first = block as usize * block_size;
3738                flat.extend(first as i32..(first + block_size) as i32);
3739            }
3740            let complete = sel.visible / block_size;
3741            flat.extend((complete * block_size) as i32..sel.visible as i32);
3742        }
3743        let count = flat.len() - start;
3744        max_count = max_count.max(count);
3745        meta.push(start as i32);
3746        meta.push(count as i32);
3747    }
3748    (flat, meta, max_count)
3749}
3750
3751/// One launch of the QSA indexer block scorer (`qsa_index_score_f32`): thread-per-block
3752/// over a [rows, n_blocks] slab. Per-score arithmetic is the host twin's verbatim (same
3753/// dim order, same relu-sum, same division by sqrt(head_dim)) — bit-identical scores.
3754#[allow(clippy::too_many_arguments)]
3755fn launch_qsa_index_score(
3756    e: &Engine,
3757    q: &CudaSlice<f32>,
3758    pooled: &CudaSlice<f32>,
3759    out: &mut CudaSlice<f32>,
3760    heads: usize,
3761    head_dim: usize,
3762    n_blocks: usize,
3763    rows: usize,
3764    scale: f32,
3765) -> Res<()> {
3766    if rows == 0 || n_blocks == 0 {
3767        return Ok(());
3768    }
3769    if out.len() < rows * n_blocks {
3770        return Err("qsa_index_score_f32: score slab too short".into());
3771    }
3772    if rows > 65535 {
3773        return Err("qsa_index_score_f32: rows exceed grid.y (caller sub-batches)".into());
3774    }
3775    // `poolT`: read the dim-major plane in the second half of the mirror (bit-identical twin —
3776    // see POOL_T_DEFAULT). The plane's pitch is the mirror's block CAPACITY, not `n_blocks`:
3777    // passing `n_blocks` would read dim d of block b as dim d of some other block for every
3778    // d > 0, which is silent wrong values, so the pitch is derived from the allocation.
3779    let cap_rows = pooled.len() / (head_dim * POOL_PLANES);
3780    let pool_t = pool_t_on();
3781    if pool_t && cap_rows < n_blocks {
3782        return Err("qsa_index_score_f32_t: pooled plane capacity below n_blocks".into());
3783    }
3784    let f = e.func(if pool_t {
3785        "qsa_index_score_f32_t"
3786    } else {
3787        "qsa_index_score_f32"
3788    });
3789    const TPB: usize = 128;
3790    let cfg = LaunchConfig {
3791        grid_dim: (n_blocks.div_ceil(TPB) as u32, rows as u32, 1),
3792        block_dim: (TPB as u32, 1, 1),
3793        shared_mem_bytes: 0,
3794    };
3795    let (h, hd, nb, r) = (heads as i32, head_dim as i32, n_blocks as i32, rows as i32);
3796    let pitch = cap_rows as i64;
3797    let stream = e.gpu.stream();
3798    if pool_t {
3799        // The plane starts at `cap_rows * head_dim`; the kernel indexes `pooled_t[d*pitch + b]`
3800        // from that base, so the slice is the plane region, not the whole buffer.
3801        let plane = pooled.slice(cap_rows * head_dim..cap_rows * head_dim * POOL_PLANES);
3802        let mut b = stream.launch_builder(&f);
3803        b.arg(q)
3804            .arg(&plane)
3805            .arg(&mut *out)
3806            .arg(&h)
3807            .arg(&hd)
3808            .arg(&nb)
3809            .arg(&r)
3810            .arg(&scale)
3811            .arg(&pitch);
3812        unsafe {
3813            b.launch(cfg)?;
3814        }
3815        return Ok(());
3816    }
3817    let mut b = stream.launch_builder(&f);
3818    b.arg(q)
3819        .arg(pooled)
3820        .arg(&mut *out)
3821        .arg(&h)
3822        .arg(&hd)
3823        .arg(&nb)
3824        .arg(&r)
3825        .arg(&scale);
3826    unsafe {
3827        b.launch(cfg)?;
3828    }
3829    Ok(())
3830}
3831
3832/// How many `cap_rows * head_dim` regions the pooled device mirror carries: the row-major
3833/// mirror, then the dim-major `poolT` plane. See the append site for why both are maintained
3834/// unconditionally (A/B isolation, and no stale-plane failure mode on a mid-run seam flip).
3835const POOL_PLANES: usize = 2;
3836
3837/// Mirror the freshly-appended pooled rows `[r0, r0+rows)` into the dim-major plane. Pure data
3838/// movement inside one buffer; `cap_rows` is the plane pitch (the mirror's block capacity).
3839fn launch_qsa_pooled_transpose(
3840    e: &Engine,
3841    buf: &mut CudaSlice<f32>,
3842    r0: usize,
3843    rows: usize,
3844    head_dim: usize,
3845    cap_rows: usize,
3846) -> Res<()> {
3847    if rows == 0 {
3848        return Ok(());
3849    }
3850    if r0 + rows > cap_rows {
3851        return Err("qsa_pooled_transpose_f32: delta exceeds the plane capacity".into());
3852    }
3853    let f = e.func("qsa_pooled_transpose_f32");
3854    const TPB: usize = 128;
3855    let cfg = LaunchConfig {
3856        grid_dim: (rows.div_ceil(TPB) as u32, head_dim as u32, 1),
3857        block_dim: (TPB as u32, 1, 1),
3858        shared_mem_bytes: 0,
3859    };
3860    let (r, hd, r0i) = (rows as i32, head_dim as i32, r0 as i32);
3861    let cap = cap_rows as i64;
3862    let stream = e.gpu.stream();
3863    let mut b = stream.launch_builder(&f);
3864    b.arg(buf).arg(&r).arg(&hd).arg(&r0i).arg(&cap);
3865    unsafe {
3866        b.launch(cfg)?;
3867    }
3868    Ok(())
3869}
3870
3871/// One launch of the device indexer top-k (`qsa_index_topk_u32`) over a score slab, plus
3872/// the structural checks that make a silent mis-write loud: every row's block count must
3873/// EXCEED the budget (so the row genuinely needs a selection and every out slot is
3874/// written), and the returned lists come back strictly ascending and in range. Returns the
3875/// `rows x budget` block ids.
3876fn launch_qsa_index_topk(
3877    e: &Engine,
3878    scores: &CudaSlice<f32>,
3879    counts: &[usize],
3880    stride: usize,
3881    budget: usize,
3882) -> Res<Vec<Vec<u32>>> {
3883    let rows = counts.len();
3884    if rows == 0 || budget == 0 {
3885        return Ok(Vec::new());
3886    }
3887    if rows > 65535 {
3888        return Err("qsa_index_topk_u32: rows exceed grid.x (caller sub-batches)".into());
3889    }
3890    if scores.len() < rows * stride {
3891        return Err("qsa_index_topk_u32: score slab too short".into());
3892    }
3893    for (r, &c) in counts.iter().enumerate() {
3894        if c <= budget || c > stride {
3895            return Err(format!(
3896                "qsa_index_topk_u32: row {r} block count {c} outside (budget {budget}, \
3897                 stride {stride}] — the caller only routes scored rows here"
3898            )
3899            .into());
3900        }
3901    }
3902    let counts_i32: Vec<i32> = counts.iter().map(|&c| c as i32).collect();
3903    let counts_dev = e.htod_i32(&counts_i32)?;
3904    // -1 fill: an unwritten slot is then VISIBLE (the check below), not a plausible block.
3905    let mut out = e.htod_i32(&vec![-1i32; rows * budget])?;
3906    let f = e.func("qsa_index_topk_u32");
3907    let cfg = LaunchConfig {
3908        grid_dim: (rows as u32, 1, 1),
3909        block_dim: (256, 1, 1),
3910        shared_mem_bytes: 0,
3911    };
3912    let (st, bu, ro) = (stride as i32, budget as i32, rows as i32);
3913    let stream = e.gpu.stream();
3914    let mut b = stream.launch_builder(&f);
3915    b.arg(scores)
3916        .arg(&counts_dev)
3917        .arg(&mut out)
3918        .arg(&st)
3919        .arg(&bu)
3920        .arg(&ro);
3921    unsafe {
3922        b.launch(cfg)?;
3923    }
3924    let host = e.gpu.stream().clone_dtoh(&out)?;
3925    e.gpu.stream().synchronize()?;
3926    let mut out_rows: Vec<Vec<u32>> = Vec::with_capacity(rows);
3927    for r in 0..rows {
3928        let row = &host[r * budget..(r + 1) * budget];
3929        let mut blocks: Vec<u32> = Vec::with_capacity(budget);
3930        let mut prev: i64 = -1;
3931        for (j, &v) in row.iter().enumerate() {
3932            if v < 0 || (v as usize) >= counts[r] || (v as i64) <= prev {
3933                return Err(format!(
3934                    "qsa_index_topk_u32: row {r} slot {j} = {v} is not a strictly ascending \
3935                     in-range block id (blocks {}, budget {budget})",
3936                    counts[r]
3937                )
3938                .into());
3939            }
3940            prev = v as i64;
3941            blocks.push(v as u32);
3942        }
3943        out_rows.push(blocks);
3944    }
3945    Ok(out_rows)
3946}
3947
3948/// One launch of the row-window column-slice copy (`copy_rows_col_f32`): append the
3949/// k-part of `rows` idx_proj rows (column offset `src_col`, row stride `src_stride`)
3950/// to the device raw-key cache at row `dst_row`. Exact byte moves, no arithmetic.
3951#[allow(clippy::too_many_arguments)]
3952fn launch_copy_rows_col(
3953    e: &Engine,
3954    src: &CudaSlice<f32>,
3955    dst: &mut CudaSlice<f32>,
3956    rows: usize,
3957    width: usize,
3958    src_stride: usize,
3959    src_col: usize,
3960    dst_row: usize,
3961) -> Res<()> {
3962    if rows == 0 {
3963        return Ok(());
3964    }
3965    if src.len() < (rows - 1) * src_stride + src_col + width || dst.len() < (dst_row + rows) * width
3966    {
3967        return Err("copy_rows_col_f32: window out of range".into());
3968    }
3969    let f = e.func("copy_rows_col_f32");
3970    let total = rows * width;
3971    let cfg = LaunchConfig::for_num_elems(total as u32);
3972    let (r, w) = (rows as i32, width as i32);
3973    let (ss, sc, dr) = (src_stride as i64, src_col as i64, dst_row as i64);
3974    let stream = e.gpu.stream();
3975    let mut b = stream.launch_builder(&f);
3976    b.arg(src)
3977        .arg(&mut *dst)
3978        .arg(&r)
3979        .arg(&w)
3980        .arg(&ss)
3981        .arg(&sc)
3982        .arg(&dr);
3983    unsafe {
3984        b.launch(cfg)?;
3985    }
3986    Ok(())
3987}
3988
3989/// One launch of the device MoE router (`qwen4exp_route_topk_f32`): per token row, the
3990/// full host_route_softmax_topk program on device (kernel doc — order-sensitive
3991/// reductions sequential on thread 0, host op order verbatim; exp through double).
3992/// `tok` = optional (slot->token map, tok_base) for the gufuse merged verify path.
3993/// Geometry guards live in the CALLER's engage condition; violations here are errors,
3994/// never silent fallbacks.
3995#[allow(clippy::too_many_arguments)]
3996fn launch_route_topk(
3997    e: &Engine,
3998    logits: &CudaSlice<f32>,
3999    sel: &mut CudaSlice<i32>,
4000    w: &mut CudaSlice<f32>,
4001    tok: Option<(&mut CudaSlice<i32>, usize)>,
4002    experts: usize,
4003    selected: usize,
4004    rows: usize,
4005) -> Res<()> {
4006    if rows == 0 {
4007        return Ok(());
4008    }
4009    if selected == 0 || selected > 32 || selected > experts {
4010        return Err("qwen4exp_route_topk_f32: selected out of range (caller guards)".into());
4011    }
4012    if experts % 2 != 0 {
4013        // The u64 key slab sits after the f32 weight slab in dynamic smem; an even
4014        // expert count keeps it 8-byte aligned (caller guards via route_dev_geometry).
4015        return Err("qwen4exp_route_topk_f32: odd expert count".into());
4016    }
4017    if logits.len() < rows * experts || sel.len() < rows * selected || w.len() < rows * selected {
4018        return Err("qwen4exp_route_topk_f32: buffer too short".into());
4019    }
4020    let smem = experts * 12; // f32 weights + u64 selection keys
4021    if smem > 48 * 1024 {
4022        return Err("qwen4exp_route_topk_f32: experts exceed the smem bound".into());
4023    }
4024    let stream = e.gpu.stream();
4025    let (tok_raw, tok_base) = match tok {
4026        Some((buf, base)) => {
4027            if buf.len() < rows * selected {
4028                return Err("qwen4exp_route_topk_f32: tok map too short".into());
4029            }
4030            (buf.device_ptr(&stream).0, base)
4031        }
4032        None => (0u64, 0usize),
4033    };
4034    let f = e.func("qwen4exp_route_topk_f32");
4035    let cfg = LaunchConfig {
4036        grid_dim: (rows as u32, 1, 1),
4037        block_dim: (128, 1, 1),
4038        shared_mem_bytes: smem as u32,
4039    };
4040    let (ex, se, ro, tb) = (
4041        experts as i32,
4042        selected as i32,
4043        rows as i32,
4044        tok_base as i32,
4045    );
4046    let floor = ROUTE_DENOM_FLOOR;
4047    let mut b = stream.launch_builder(&f);
4048    b.arg(logits)
4049        .arg(&mut *sel)
4050        .arg(&mut *w)
4051        .arg(&tok_raw)
4052        .arg(&ex)
4053        .arg(&se)
4054        .arg(&ro)
4055        .arg(&tb)
4056        .arg(&floor);
4057    unsafe {
4058        b.launch(cfg)?;
4059    }
4060    Ok(())
4061}
4062
4063/// Device route + (MEMRA_Q4E_ROUTER_AUDIT=1) the host-twin cross-check over the SAME
4064/// logits: selection ids order-exact or Err; weights within ROUTE_AUDIT_ULP_BOUND ULP,
4065/// worst observed kept for the gate receipt (`route_audit_stats`).
4066#[allow(clippy::too_many_arguments)]
4067fn route_topk_device(
4068    e: &Engine,
4069    logits: &CudaSlice<f32>,
4070    sel: &mut CudaSlice<i32>,
4071    w: &mut CudaSlice<f32>,
4072    tok: Option<(&mut CudaSlice<i32>, usize)>,
4073    experts: usize,
4074    selected: usize,
4075    rows: usize,
4076    layer: u32,
4077) -> Res<()> {
4078    launch_route_topk(e, logits, sel, w, tok, experts, selected, rows)?;
4079    if !router_audit_on() {
4080        return Ok(());
4081    }
4082    let k = selected.min(experts);
4083    let lg = e.dtoh_view(&logits.slice(0..rows * experts))?;
4084    let sel_h = e.gpu.stream().clone_dtoh(&sel.slice(0..rows * selected))?;
4085    let w_h = e.gpu.stream().clone_dtoh(&w.slice(0..rows * selected))?;
4086    // Emit the shared-format route trace off THIS readback (`trace_moe_routes`, the frozen
4087    // `memra-ep-map-v1` producer). Its own doc comment already promised exactly this — "arming
4088    // MEMRA_Q4E_ROUTER_AUDIT=1 restores a host recompute of every device route and the trace
4089    // rides THAT readback at zero new syncs ... single-card batteries trace with the audit
4090    // armed" — but the call was never made, so the tracer fired ONLY from the TP2 paths and the
4091    // shipped single-card device-routed default emitted nothing at all. The box's traces
4092    // directory was empty for that reason and not for lack of running, and the expert-placement
4093    // lane's only input silently did not exist. Prose describing a wiring that is not there is
4094    // the failure class this lane has hit twice; the wiring is here now.
4095    //
4096    // Traced from the DEVICE arrays, not from the host twin below: the trace must record the
4097    // route that actually ran. The audit's job is to prove the two agree, and it does that on
4098    // the next lines — so if they ever disagree this call has already errored out.
4099    {
4100        let routes: Vec<Vec<(usize, f32)>> = (0..rows)
4101            .map(|row| {
4102                (0..selected)
4103                    .map(|j| {
4104                        (
4105                            sel_h[row * selected + j].max(0) as usize,
4106                            w_h[row * selected + j],
4107                        )
4108                    })
4109                    .collect()
4110            })
4111            .collect();
4112        trace_moe_routes(layer, rows, &routes);
4113    }
4114    let mut worst: u32 = 0;
4115    for row in 0..rows {
4116        let twin = host_route_softmax_topk(&lg[row * experts..(row + 1) * experts], selected);
4117        if twin.len() != k {
4118            return Err("router audit: host twin emitted an unexpected selection width".into());
4119        }
4120        for (j, &(idx, wt)) in twin.iter().enumerate() {
4121            let ds = sel_h[row * selected + j];
4122            let dw = w_h[row * selected + j];
4123            if ds != idx as i32 {
4124                return Err(format!(
4125                    "router audit: selection mismatch at row {row} slot {j}: \
4126                     device {ds} vs host {idx} (host w {wt:e})"
4127                )
4128                .into());
4129            }
4130            let ulp = (dw.to_bits() as i64 - wt.to_bits() as i64).unsigned_abs();
4131            let ulp = u32::try_from(ulp).unwrap_or(u32::MAX);
4132            worst = worst.max(ulp);
4133            if ulp > ROUTE_AUDIT_ULP_BOUND {
4134                return Err(format!(
4135                    "router audit: weight ULP {ulp} > bound {ROUTE_AUDIT_ULP_BOUND} at \
4136                     row {row} slot {j}: device {dw:e} vs host {wt:e}"
4137                )
4138                .into());
4139            }
4140        }
4141    }
4142    ROUTE_AUDIT_ROWS.fetch_add(rows as u64, std::sync::atomic::Ordering::Relaxed);
4143    ROUTE_AUDIT_MAX_ULP.fetch_max(worst, std::sync::atomic::Ordering::Relaxed);
4144    Ok(())
4145}
4146
4147/// The historical mask-producing entry point, now select + render (byte-identical mask;
4148/// the TP2 decode path and the masked-kernel arm consume it).
4149// dead_code: bring-up scaffolding the in-flight qwen4exp lanes still call; not deleted in
4150// the clippy-zero lane (bit-neutral by construction).
4151#[allow(dead_code)]
4152#[allow(clippy::too_many_arguments)]
4153fn indexer_mask_rows(
4154    overlay: &MicroBlockIndexPlan,
4155    rope_base: f32,
4156    yarn: Option<(&[f32], f32)>,
4157    epsilon: f32,
4158    idx_q_norm: &[f32],
4159    idx_k_norm: &[f32],
4160    proj_rows: &[f32],
4161    raw_keys: &IdxRawCache,
4162    pooled_keys: &mut Vec<f32>,
4163    base_pos: usize,
4164    t: usize,
4165    t_kv: usize,
4166    pos_off: usize,
4167) -> Res<Vec<u8>> {
4168    let sels = indexer_select_rows(
4169        overlay,
4170        rope_base,
4171        yarn,
4172        epsilon,
4173        idx_q_norm,
4174        idx_k_norm,
4175        proj_rows,
4176        raw_keys,
4177        pooled_keys,
4178        // TP2 decode + the reference/mask arm keep the host scorer (TP2's selection runs
4179        // on card 0's projection and feeds both halves; its depths are decode-class).
4180        None,
4181        base_pos,
4182        t,
4183        t_kv,
4184        pos_off,
4185    )?;
4186    Ok(rowsel_to_mask(&sels, overlay.block_size as usize, t_kv))
4187}
4188
4189/// memra_reference `shift_right_ignore_eos` twin.
4190fn shift_right_ignore_eos(history: &[i64], shift: usize, eos: i64) -> Vec<i64> {
4191    if shift == 0 {
4192        return history.to_vec();
4193    }
4194    let mut last_eos_inclusive: i64 = -1;
4195    let mut output = Vec::with_capacity(history.len());
4196    for (position, &token) in history.iter().enumerate() {
4197        let previous_eos = last_eos_inclusive;
4198        if token == eos {
4199            last_eos_inclusive = position as i64;
4200        }
4201        let segment_start = previous_eos + 1;
4202        let position_in_segment = position as i64 - segment_start;
4203        let source = position as i64 - shift as i64;
4204        let valid = position_in_segment >= shift as i64 && source >= 0;
4205        output.push(if valid { history[source as usize] } else { eos });
4206    }
4207    output
4208}
4209
4210/// INCREMENTAL twin of `host_ngram_ids` (`plecache` seam, 262k perf lane): extend a cached
4211/// id vector to cover `token_ids` instead of rebuilding it. Returns the last `t` rows'
4212/// worth of ids, i.e. exactly what the caller slices.
4213///
4214/// Bit-identical to `host_ngram_ids` by construction, not by tolerance. Two local facts do
4215/// it. (1) `shift_right_ignore_eos` at position p emits `history[p - shift]` guarded by an
4216/// eos scan that only moves left-to-right, so its value at p depends on `history[..=p]`
4217/// alone. (2) the id loop at `token` reads only `shifted[*][context + token]`. Therefore
4218/// `ids[token]` is a pure function of `token_ids[..=token]` and never changes when a token
4219/// is appended — so appending rows is not an approximation of rebuilding them, it is the
4220/// same arithmetic in the same order on the same inputs.
4221///
4222/// A shrinking or diverging history (spec reject / rewind / a fresh sequence in a reused
4223/// state) is handled by TRUNCATING the cache to the longest common prefix and re-extending.
4224/// The check is a real prefix compare rather than a length compare, because a length-only
4225/// check would silently keep another sequence's hashes — the failure mode would be fluent
4226/// output from the wrong n-gram rows, which is invisible.
4227#[allow(clippy::too_many_arguments)]
4228fn host_ngram_ids_cached(
4229    cache_ids: &mut Vec<i64>,
4230    cache_history: &mut Vec<i64>,
4231    cache_last_eos: &mut i64,
4232    token_ids: &[u32],
4233    multipliers: &[i64],
4234    sizes: &[i64],
4235    offsets: &[i64],
4236    max_ngram: usize,
4237    heads_per_ngram: usize,
4238    eos_token_id: u32,
4239) {
4240    let context = max_ngram - 1;
4241    let eos = eos_token_id as i64;
4242    let total_heads = (max_ngram - 1) * heads_per_ngram;
4243    if cache_history.is_empty() {
4244        cache_history.extend(std::iter::repeat_n(eos, context));
4245        *cache_last_eos = context as i64 - 1; // every prefix row IS an eos
4246        cache_ids.clear();
4247    }
4248    let cached_tokens = (cache_history.len() - context).min(cache_ids.len() / total_heads);
4249    // Longest common prefix of the cached tokens and the requested ones.
4250    let mut keep = cached_tokens.min(token_ids.len());
4251    for i in 0..keep {
4252        if cache_history[context + i] != token_ids[i] as i64 {
4253            keep = i;
4254            break;
4255        }
4256    }
4257    if keep < cached_tokens {
4258        // Rewind: drop the diverged tail and rebuild the eos scan over what survives.
4259        cache_history.truncate(context + keep);
4260        cache_ids.truncate(keep * total_heads);
4261        *cache_last_eos = cache_history
4262            .iter()
4263            .rposition(|&v| v == eos)
4264            .map(|p| p as i64)
4265            .unwrap_or(-1);
4266    }
4267    for &token in &token_ids[keep..] {
4268        let position = cache_history.len();
4269        let value = token as i64;
4270        cache_history.push(value);
4271        // `shift_right_ignore_eos`: `previous_eos` is read BEFORE this position updates it.
4272        let previous_eos = *cache_last_eos;
4273        if value == eos {
4274            *cache_last_eos = position as i64;
4275        }
4276        let segment_start = previous_eos + 1;
4277        let position_in_segment = position as i64 - segment_start;
4278        let shifted_at = |shift: usize| -> i64 {
4279            if shift == 0 {
4280                return cache_history[position];
4281            }
4282            let source = position as i64 - shift as i64;
4283            if position_in_segment >= shift as i64 && source >= 0 {
4284                cache_history[source as usize]
4285            } else {
4286                eos
4287            }
4288        };
4289        // Same op order as the twin: shift 0 multiply, then xor the higher shifts in order.
4290        let mut row = vec![0i64; total_heads];
4291        for ngram in 2..=max_ngram {
4292            let head_start = (ngram - 2) * heads_per_ngram;
4293            let mut mixed = shifted_at(0).wrapping_mul(multipliers[0]);
4294            for shift in 1..ngram {
4295                mixed ^= shifted_at(shift).wrapping_mul(multipliers[shift]);
4296            }
4297            for head in 0..heads_per_ngram {
4298                let index = head_start + head;
4299                row[index] = mixed.rem_euclid(sizes[index]) + offsets[index];
4300            }
4301        }
4302        cache_ids.extend_from_slice(&row);
4303    }
4304    debug_assert_eq!(cache_ids.len(), token_ids.len() * total_heads);
4305    // Returns nothing on purpose: the caller reads the tail of `cache_ids` in place. Handing
4306    // back a `Vec` would clone the whole history's ids on every decode step (19 MB at a
4307    // 150,000-token fill), which is the O(context) cost this seam exists to delete.
4308}
4309
4310/// memra_reference `ngram_ids` twin over the FULL token history (context EOS rows
4311/// prepended); the caller slices the last `t` rows for the current chunk.
4312fn host_ngram_ids(
4313    token_ids: &[u32],
4314    multipliers: &[i64],
4315    sizes: &[i64],
4316    offsets: &[i64],
4317    max_ngram: usize,
4318    heads_per_ngram: usize,
4319    eos_token_id: u32,
4320) -> Vec<i64> {
4321    let context = max_ngram - 1;
4322    let eos = eos_token_id as i64;
4323    let total_heads = (max_ngram - 1) * heads_per_ngram;
4324    let mut history = Vec::with_capacity(context + token_ids.len());
4325    history.extend(std::iter::repeat_n(eos, context));
4326    history.extend(token_ids.iter().map(|&token| token as i64));
4327    let shifted: Vec<Vec<i64>> = (0..max_ngram)
4328        .map(|shift| shift_right_ignore_eos(&history, shift, eos))
4329        .collect();
4330    let tokens = token_ids.len();
4331    let mut ids = vec![0i64; tokens * total_heads];
4332    for ngram in 2..=max_ngram {
4333        let head_start = (ngram - 2) * heads_per_ngram;
4334        for token in 0..tokens {
4335            let position = context + token;
4336            let mut mixed = shifted[0][position].wrapping_mul(multipliers[0]);
4337            for (shift, row) in shifted.iter().enumerate().take(ngram).skip(1) {
4338                mixed ^= row[position].wrapping_mul(multipliers[shift]);
4339            }
4340            for head in 0..heads_per_ngram {
4341                let index = head_start + head;
4342                ids[token * total_heads + index] = mixed.rem_euclid(sizes[index]) + offsets[index];
4343            }
4344        }
4345    }
4346    ids
4347}
4348
4349// ---------------------------------------------------------------- kernel launchers
4350
4351#[allow(clippy::too_many_arguments)]
4352fn launch_sdpa_mask(
4353    e: &Engine,
4354    q: &CudaSlice<f32>,
4355    k: &CudaView<'_, f32>,
4356    v: &CudaView<'_, f32>,
4357    o: &mut CudaSlice<f32>,
4358    mask: &CudaSlice<u8>,
4359    head_dim: usize,
4360    n_head: usize,
4361    n_head_kv: usize,
4362    t: usize,
4363    t_kv: usize,
4364    scale: f32,
4365) -> Res<()> {
4366    if t_kv * 4 > 48 * 1024 {
4367        return Err(
4368            "sdpa_naive_mask_f32: T_kv exceeds the smem bound; the gmem twin is perf-lane work"
4369                .into(),
4370        );
4371    }
4372    let f = e.func("sdpa_naive_mask_f32");
4373    let cfg = LaunchConfig {
4374        grid_dim: (n_head as u32, t as u32, 1),
4375        block_dim: (128, 1, 1),
4376        shared_mem_bytes: (t_kv * 4) as u32,
4377    };
4378    let (hd, nh, nkv, ti, tkvi) = (
4379        head_dim as i32,
4380        n_head as i32,
4381        n_head_kv as i32,
4382        t as i32,
4383        t_kv as i32,
4384    );
4385    let stream = e.gpu.stream();
4386    let mut b = stream.launch_builder(&f);
4387    b.arg(q)
4388        .arg(k)
4389        .arg(v)
4390        .arg(o)
4391        .arg(mask)
4392        .arg(&hd)
4393        .arg(&nh)
4394        .arg(&nkv)
4395        .arg(&ti)
4396        .arg(&tkvi)
4397        .arg(&scale);
4398    unsafe {
4399        b.launch(cfg)?;
4400    }
4401    Ok(())
4402}
4403
4404/// Block-list QSA attention (long-context form): per query row, attend the row's own
4405/// ASCENDING position list (`rowsel_positions`) — smem scales with the bounded per-row
4406/// selection (<= 2052 on real geometry), never with t_kv. BIT-IDENTICAL to
4407/// `sdpa_naive_mask_f32` on the same selection: masked entries there contribute exact
4408/// 0.0 softmax/V terms in the same ascending order (gate arm + kernel oracle).
4409#[allow(clippy::too_many_arguments)]
4410fn launch_sdpa_blocklist(
4411    e: &Engine,
4412    q: &CudaSlice<f32>,
4413    k: &CudaView<'_, f32>,
4414    v: &CudaView<'_, f32>,
4415    o: &mut CudaSlice<f32>,
4416    pos: &CudaSlice<i32>,
4417    meta: &CudaSlice<i32>,
4418    head_dim: usize,
4419    n_head: usize,
4420    n_head_kv: usize,
4421    t: usize,
4422    max_count: usize,
4423    scale: f32,
4424) -> Res<()> {
4425    // positions (i32) + scores (f32) per selected entry. Production rows are bounded by
4426    // budget*block + block = 2052 entries (16.4 KB); 48 KB is the no-attribute smem cap.
4427    let smem = (max_count * 8) as u32;
4428    if smem > 48 * 1024 {
4429        return Err("sdpa_blocklist_f32: selection exceeds the smem budget".into());
4430    }
4431    let f = e.func("sdpa_blocklist_f32");
4432    let cfg = LaunchConfig {
4433        grid_dim: (n_head as u32, t as u32, 1),
4434        block_dim: (128, 1, 1),
4435        shared_mem_bytes: smem,
4436    };
4437    let (hd, nh, nkv, ti, mc) = (
4438        head_dim as i32,
4439        n_head as i32,
4440        n_head_kv as i32,
4441        t as i32,
4442        max_count as i32,
4443    );
4444    let stream = e.gpu.stream();
4445    let mut b = stream.launch_builder(&f);
4446    b.arg(q)
4447        .arg(k)
4448        .arg(v)
4449        .arg(o)
4450        .arg(pos)
4451        .arg(meta)
4452        .arg(&hd)
4453        .arg(&nh)
4454        .arg(&nkv)
4455        .arg(&ti)
4456        .arg(&mc)
4457        .arg(&scale);
4458    unsafe {
4459        b.launch(cfg)?;
4460    }
4461    Ok(())
4462}
4463
4464/// Append-quantize `t` post-RoPE K/V rows into the byte caches at slots
4465/// [base_pos, base_pos + t) (kvq lane; K=q8_0, V=q5_1).
4466#[allow(clippy::too_many_arguments)]
4467fn launch_q4e_kv_append(
4468    e: &Engine,
4469    k_rows: &CudaSlice<f32>,
4470    v_rows: &CudaSlice<f32>,
4471    k: &mut CudaSlice<u8>,
4472    v: &mut CudaSlice<u8>,
4473    base_pos: usize,
4474    t: usize,
4475    kv_dim: usize,
4476) -> Res<()> {
4477    let f = e.func("q4e_kv_append_q8q5_rows");
4478    let blocks = kv_dim.div_ceil(32);
4479    let cfg = LaunchConfig {
4480        grid_dim: (blocks as u32, t as u32, 1),
4481        block_dim: (32, 1, 1),
4482        shared_mem_bytes: 0,
4483    };
4484    let (t0, dk, dv) = (base_pos as i32, kv_dim as i32, kv_dim as i32);
4485    let (ktb, vtb) = (q8_row_bytes(kv_dim) as i64, q5_row_bytes(kv_dim) as i64);
4486    let stream = e.gpu.stream();
4487    let mut b = stream.launch_builder(&f);
4488    b.arg(k_rows)
4489        .arg(v_rows)
4490        .arg(k)
4491        .arg(v)
4492        .arg(&t0)
4493        .arg(&dk)
4494        .arg(&dv)
4495        .arg(&ktb)
4496        .arg(&vtb);
4497    unsafe {
4498        b.launch(cfg)?;
4499    }
4500    Ok(())
4501}
4502
4503/// Dequant cache rows [r0, r0+rows) into f32 buffers (gates + TP2 migration seam).
4504#[allow(clippy::too_many_arguments)]
4505fn launch_q4e_kv_dequant_rows(
4506    e: &Engine,
4507    k: &CudaSlice<u8>,
4508    v: &CudaSlice<u8>,
4509    k_out: &mut CudaSlice<f32>,
4510    v_out: &mut CudaSlice<f32>,
4511    r0: usize,
4512    rows: usize,
4513    kv_dim: usize,
4514) -> Res<()> {
4515    let f = e.func("q4e_kv_dequant_rows");
4516    let blocks = kv_dim.div_ceil(32);
4517    let cfg = LaunchConfig {
4518        grid_dim: (blocks as u32, rows as u32, 1),
4519        block_dim: (32, 1, 1),
4520        shared_mem_bytes: 0,
4521    };
4522    let (r0i, dk, dv) = (r0 as i32, kv_dim as i32, kv_dim as i32);
4523    let (ktb, vtb) = (q8_row_bytes(kv_dim) as i64, q5_row_bytes(kv_dim) as i64);
4524    let stream = e.gpu.stream();
4525    let mut b = stream.launch_builder(&f);
4526    b.arg(k)
4527        .arg(v)
4528        .arg(k_out)
4529        .arg(v_out)
4530        .arg(&r0i)
4531        .arg(&dk)
4532        .arg(&dv)
4533        .arg(&ktb)
4534        .arg(&vtb);
4535    unsafe {
4536        b.launch(cfg)?;
4537    }
4538    Ok(())
4539}
4540
4541/// Block-list QSA attention over the QUANTIZED cache (kvq lane) — the f32 launcher's
4542/// twin with byte-cache K/V and their row strides.
4543#[allow(clippy::too_many_arguments)]
4544fn launch_q4e_sdpa_blocklist_q8q5(
4545    e: &Engine,
4546    q: &CudaSlice<f32>,
4547    k: &CudaSlice<u8>,
4548    v: &CudaSlice<u8>,
4549    o: &mut CudaSlice<f32>,
4550    pos: &CudaSlice<i32>,
4551    meta: &CudaSlice<i32>,
4552    head_dim: usize,
4553    n_head: usize,
4554    n_head_kv: usize,
4555    t: usize,
4556    max_count: usize,
4557    scale: f32,
4558) -> Res<()> {
4559    let smem = (max_count * 8) as u32;
4560    if smem > 48 * 1024 {
4561        return Err("q4e_sdpa_blocklist_q8q5: selection exceeds the smem budget".into());
4562    }
4563    // `kvhoist`: the scale-hoisted twin, bit-identical, selected by seam (see KV_HOIST_DEFAULT).
4564    let f = e.func(if kv_hoist_on() {
4565        "q4e_sdpa_blocklist_q8q5_hoist"
4566    } else {
4567        "q4e_sdpa_blocklist_q8q5"
4568    });
4569    let cfg = LaunchConfig {
4570        grid_dim: (n_head as u32, t as u32, 1),
4571        block_dim: (128, 1, 1),
4572        shared_mem_bytes: smem,
4573    };
4574    let kv_dim = n_head_kv * head_dim;
4575    let (hd, nh, nkv, ti, mc) = (
4576        head_dim as i32,
4577        n_head as i32,
4578        n_head_kv as i32,
4579        t as i32,
4580        max_count as i32,
4581    );
4582    let (ktb, vtb) = (q8_row_bytes(kv_dim) as i64, q5_row_bytes(kv_dim) as i64);
4583    let stream = e.gpu.stream();
4584    let mut b = stream.launch_builder(&f);
4585    b.arg(q)
4586        .arg(k)
4587        .arg(v)
4588        .arg(o)
4589        .arg(pos)
4590        .arg(meta)
4591        .arg(&hd)
4592        .arg(&nh)
4593        .arg(&nkv)
4594        .arg(&ti)
4595        .arg(&mc)
4596        .arg(&scale)
4597        .arg(&ktb)
4598        .arg(&vtb);
4599    unsafe {
4600        b.launch(cfg)?;
4601    }
4602    Ok(())
4603}
4604
4605/// Quantize-append the k-part columns of `rows` idx_proj rows into the q8_0 device
4606/// raw-key cache (idxq=q8 x idxcache).
4607#[allow(clippy::too_many_arguments)]
4608fn launch_q4e_idx_append_q8(
4609    e: &Engine,
4610    src: &CudaSlice<f32>,
4611    dst: &mut CudaSlice<u8>,
4612    rows: usize,
4613    width: usize,
4614    src_stride: usize,
4615    src_col: usize,
4616    dst_row: usize,
4617) -> Res<()> {
4618    let f = e.func("q4e_idx_append_q8");
4619    let cfg = LaunchConfig {
4620        grid_dim: (width.div_ceil(32) as u32, rows as u32, 1),
4621        block_dim: (32, 1, 1),
4622        shared_mem_bytes: 0,
4623    };
4624    let (r, w) = (rows as i32, width as i32);
4625    let (ss, sc, dr) = (src_stride as i64, src_col as i64, dst_row as i64);
4626    let stream = e.gpu.stream();
4627    let mut b = stream.launch_builder(&f);
4628    b.arg(src)
4629        .arg(dst)
4630        .arg(&r)
4631        .arg(&w)
4632        .arg(&ss)
4633        .arg(&sc)
4634        .arg(&dr);
4635    unsafe {
4636        b.launch(cfg)?;
4637    }
4638    Ok(())
4639}
4640
4641/// Convert-append (bf16 RNE) the k-part columns into the bf16 device raw-key cache.
4642#[allow(clippy::too_many_arguments)]
4643fn launch_q4e_idx_append_bf16(
4644    e: &Engine,
4645    src: &CudaSlice<f32>,
4646    dst: &mut CudaSlice<u16>,
4647    rows: usize,
4648    width: usize,
4649    src_stride: usize,
4650    src_col: usize,
4651    dst_row: usize,
4652) -> Res<()> {
4653    let f = e.func("q4e_idx_append_bf16");
4654    let total = rows * width;
4655    let cfg = LaunchConfig {
4656        grid_dim: (total.div_ceil(256) as u32, 1, 1),
4657        block_dim: (256, 1, 1),
4658        shared_mem_bytes: 0,
4659    };
4660    let (r, w) = (rows as i32, width as i32);
4661    let (ss, sc, dr) = (src_stride as i64, src_col as i64, dst_row as i64);
4662    let stream = e.gpu.stream();
4663    let mut b = stream.launch_builder(&f);
4664    b.arg(src)
4665        .arg(dst)
4666        .arg(&r)
4667        .arg(&w)
4668        .arg(&ss)
4669        .arg(&sc)
4670        .arg(&dr);
4671    unsafe {
4672        b.launch(cfg)?;
4673    }
4674    Ok(())
4675}
4676
4677#[allow(clippy::too_many_arguments)]
4678fn launch_gdn_scan(
4679    e: &Engine,
4680    qkv: &CudaSlice<f32>,
4681    g_log: &CudaSlice<f32>,
4682    beta_raw: &CudaSlice<f32>,
4683    state: &mut CudaSlice<f32>,
4684    o: &mut CudaSlice<f32>,
4685    nk: usize,
4686    nv: usize,
4687    hk: usize,
4688    hv: usize,
4689    t: usize,
4690    scale: f32,
4691    eps: f32,
4692) -> Res<()> {
4693    if hk > 128 {
4694        return Err("gdn_scan_naive_f32: hk > 128".into());
4695    }
4696    let f = e.func("gdn_scan_naive_f32");
4697    let cfg = LaunchConfig {
4698        grid_dim: (nv as u32, 1, 1),
4699        block_dim: (hv as u32, 1, 1),
4700        shared_mem_bytes: ((2 * hk + 2) * 4) as u32,
4701    };
4702    let (nki, nvi, hki, hvi, ti) = (nk as i32, nv as i32, hk as i32, hv as i32, t as i32);
4703    let stream = e.gpu.stream();
4704    let mut b = stream.launch_builder(&f);
4705    b.arg(qkv)
4706        .arg(g_log)
4707        .arg(beta_raw)
4708        .arg(state)
4709        .arg(o)
4710        .arg(&nki)
4711        .arg(&nvi)
4712        .arg(&hki)
4713        .arg(&hvi)
4714        .arg(&ti)
4715        .arg(&scale)
4716        .arg(&eps);
4717    unsafe {
4718        b.launch(cfg)?;
4719    }
4720    Ok(())
4721}
4722
4723/// One launch of the decode-step scan twin (`gdn_scan_step_f32`, t == 1): grid
4724/// (nv, hv), block hk — one state element per thread (see the kernel doc; the
4725/// accumulation class vs the naive kernel's sequential row sums).
4726#[allow(clippy::too_many_arguments)]
4727fn launch_gdn_scan_step(
4728    e: &Engine,
4729    qkv: &CudaSlice<f32>,
4730    g_log: &CudaSlice<f32>,
4731    beta_raw: &CudaSlice<f32>,
4732    state: &mut CudaSlice<f32>,
4733    o: &mut CudaSlice<f32>,
4734    nk: usize,
4735    nv: usize,
4736    hk: usize,
4737    hv: usize,
4738    scale: f32,
4739    eps: f32,
4740) -> Res<()> {
4741    if hk % 32 != 0 || hk > 1024 {
4742        return Err("gdn_scan_step_f32: hk must be a multiple of 32 and <= 1024".into());
4743    }
4744    let f = e.func("gdn_scan_step_f32");
4745    let cfg = LaunchConfig {
4746        grid_dim: (nv as u32, hv as u32, 1),
4747        block_dim: (hk as u32, 1, 1),
4748        shared_mem_bytes: 0,
4749    };
4750    let (nki, nvi, hki, hvi) = (nk as i32, nv as i32, hk as i32, hv as i32);
4751    let stream = e.gpu.stream();
4752    let mut b = stream.launch_builder(&f);
4753    b.arg(qkv)
4754        .arg(g_log)
4755        .arg(beta_raw)
4756        .arg(state)
4757        .arg(o)
4758        .arg(&nki)
4759        .arg(&nvi)
4760        .arg(&hki)
4761        .arg(&hvi)
4762        .arg(&scale)
4763        .arg(&eps);
4764    unsafe {
4765        b.launch(cfg)?;
4766    }
4767    Ok(())
4768}
4769
4770/// Per-token step-scan launch at COLUMN `tok` of a chunk (verify-exact rows): views of
4771/// the token's post-conv row / g_log / beta / output row, the SAME kernel and grid as
4772/// the decode step — each column is bit-identical to the t == 1 decode launch.
4773#[allow(clippy::too_many_arguments)]
4774fn launch_gdn_scan_step_at(
4775    e: &Engine,
4776    conv_out: &CudaSlice<f32>,
4777    g_log: &CudaSlice<f32>,
4778    beta_raw: &CudaSlice<f32>,
4779    state: &mut CudaSlice<f32>,
4780    o: &mut CudaSlice<f32>,
4781    tok: usize,
4782    nk: usize,
4783    nv: usize,
4784    hk: usize,
4785    hv: usize,
4786    scale: f32,
4787    eps: f32,
4788) -> Res<()> {
4789    if hk % 32 != 0 || hk > 1024 {
4790        return Err("gdn_scan_step_f32: hk must be a multiple of 32 and <= 1024".into());
4791    }
4792    let conv_dim = 2 * nk * hk + nv * hv;
4793    let qv = conv_out.slice(tok * conv_dim..(tok + 1) * conv_dim);
4794    let gv = g_log.slice(tok * nv..(tok + 1) * nv);
4795    let bv = beta_raw.slice(tok * nv..(tok + 1) * nv);
4796    let mut ov = o.slice_mut(tok * nv * hv..(tok + 1) * nv * hv);
4797    let f = e.func("gdn_scan_step_f32");
4798    let cfg = LaunchConfig {
4799        grid_dim: (nv as u32, hv as u32, 1),
4800        block_dim: (hk as u32, 1, 1),
4801        shared_mem_bytes: 0,
4802    };
4803    let (nki, nvi, hki, hvi) = (nk as i32, nv as i32, hk as i32, hv as i32);
4804    let stream = e.gpu.stream();
4805    let mut b = stream.launch_builder(&f);
4806    b.arg(&qv)
4807        .arg(&gv)
4808        .arg(&bv)
4809        .arg(&mut *state)
4810        .arg(&mut ov)
4811        .arg(&nki)
4812        .arg(&nvi)
4813        .arg(&hki)
4814        .arg(&hvi)
4815        .arg(&scale)
4816        .arg(&eps);
4817    unsafe {
4818        b.launch(cfg)?;
4819    }
4820    Ok(())
4821}
4822
4823/// Per-token NAIVE-scan launch at column `tok` (t == 1 views) — the exact-verify twin
4824/// for geometries the step kernel refuses (tiny hk): identical to the t == 1 decode
4825/// dispatch on those plans.
4826#[allow(clippy::too_many_arguments)]
4827fn launch_gdn_scan_at(
4828    e: &Engine,
4829    conv_out: &CudaSlice<f32>,
4830    g_log: &CudaSlice<f32>,
4831    beta_raw: &CudaSlice<f32>,
4832    state: &mut CudaSlice<f32>,
4833    o: &mut CudaSlice<f32>,
4834    tok: usize,
4835    nk: usize,
4836    nv: usize,
4837    hk: usize,
4838    hv: usize,
4839    scale: f32,
4840    eps: f32,
4841) -> Res<()> {
4842    if hk > 128 {
4843        return Err("gdn_scan_naive_f32: hk > 128".into());
4844    }
4845    let conv_dim = 2 * nk * hk + nv * hv;
4846    let qv = conv_out.slice(tok * conv_dim..(tok + 1) * conv_dim);
4847    let gv = g_log.slice(tok * nv..(tok + 1) * nv);
4848    let bv = beta_raw.slice(tok * nv..(tok + 1) * nv);
4849    let mut ov = o.slice_mut(tok * nv * hv..(tok + 1) * nv * hv);
4850    let f = e.func("gdn_scan_naive_f32");
4851    let cfg = LaunchConfig {
4852        grid_dim: (nv as u32, 1, 1),
4853        block_dim: (hv as u32, 1, 1),
4854        shared_mem_bytes: ((2 * hk + 2) * 4) as u32,
4855    };
4856    let (nki, nvi, hki, hvi, ti) = (nk as i32, nv as i32, hk as i32, hv as i32, 1i32);
4857    let stream = e.gpu.stream();
4858    let mut b = stream.launch_builder(&f);
4859    b.arg(&qv)
4860        .arg(&gv)
4861        .arg(&bv)
4862        .arg(&mut *state)
4863        .arg(&mut ov)
4864        .arg(&nki)
4865        .arg(&nvi)
4866        .arg(&hki)
4867        .arg(&hvi)
4868        .arg(&ti)
4869        .arg(&scale)
4870        .arg(&eps);
4871    unsafe {
4872        b.launch(cfg)?;
4873    }
4874    Ok(())
4875}
4876
4877/// One launch of the fused GDN norm+gate (`rms_sigmul_f32`): dst = rms_norm(x, w) *
4878/// sigmoid(z) over `nrows` rows of `ncols` — bit-identical to the rms_norm + sigmoid +
4879/// mul chain (kernel doc).
4880#[allow(clippy::too_many_arguments)]
4881fn launch_rms_sigmul(
4882    e: &Engine,
4883    x: &CudaSlice<f32>,
4884    w: &CudaSlice<f32>,
4885    z: &CudaSlice<f32>,
4886    dst: &mut CudaSlice<f32>,
4887    ncols: usize,
4888    nrows: usize,
4889    eps: f32,
4890) -> Res<()> {
4891    let f = e.func("rms_sigmul_f32");
4892    let cfg = LaunchConfig {
4893        grid_dim: (nrows as u32, 1, 1),
4894        block_dim: (crate::rms_block(), 1, 1),
4895        shared_mem_bytes: 0,
4896    };
4897    let (nc, ep) = (ncols as i32, eps);
4898    let stream = e.gpu.stream();
4899    let mut b = stream.launch_builder(&f);
4900    b.arg(x).arg(w).arg(z).arg(dst).arg(&nc).arg(&ep);
4901    unsafe {
4902        b.launch(cfg)?;
4903    }
4904    Ok(())
4905}
4906
4907#[allow(clippy::too_many_arguments)]
4908fn launch_dwconv(
4909    e: &Engine,
4910    x: &CudaSlice<f32>,
4911    hist: &CudaSlice<f32>,
4912    w: &CudaSlice<f32>,
4913    y: &mut CudaSlice<f32>,
4914    t: usize,
4915    th: usize,
4916    c: usize,
4917    k: usize,
4918    dilation: usize,
4919    mode: i32,
4920) -> Res<()> {
4921    let f = e.func("dwconv_causal_f32");
4922    let cfg = LaunchConfig::for_num_elems((t * c) as u32);
4923    let (ti, thi, ci, ki, di) = (t as i32, th as i32, c as i32, k as i32, dilation as i32);
4924    let stream = e.gpu.stream();
4925    let mut b = stream.launch_builder(&f);
4926    b.arg(x)
4927        .arg(hist)
4928        .arg(w)
4929        .arg(y)
4930        .arg(&ti)
4931        .arg(&thi)
4932        .arg(&ci)
4933        .arg(&ki)
4934        .arg(&di)
4935        .arg(&mode);
4936    unsafe {
4937        b.launch(cfg)?;
4938    }
4939    Ok(())
4940}
4941
4942/// One routed expert's SwiGLU: gate/up GEMMs on the gathered token rows, silu_mul, down.
4943#[allow(clippy::too_many_arguments)]
4944fn run_routed_expert(
4945    e: &Engine,
4946    xg: &CudaSlice<f32>,
4947    gate: &CudaView<'_, f32>,
4948    up: &CudaView<'_, f32>,
4949    down: &CudaView<'_, f32>,
4950    m_e: usize,
4951    hidden: usize,
4952    ff: usize,
4953) -> Res<CudaSlice<f32>> {
4954    let xg_view = xg.slice(0..m_e * hidden);
4955    let mut gate_out = e.uninit(m_e * ff)?;
4956    e.linear_device_into(&xg_view, gate, &mut gate_out, m_e, hidden, ff)?;
4957    let mut up_out = e.uninit(m_e * ff)?;
4958    e.linear_device_into(&xg_view, up, &mut up_out, m_e, hidden, ff)?;
4959    let mut act = e.uninit(m_e * ff)?;
4960    e.silu_mul(&gate_out, &up_out, &mut act, m_e * ff)?;
4961    let mut down_out = e.uninit(m_e * hidden)?;
4962    e.linear_device_into(
4963        &act.slice(0..m_e * ff),
4964        down,
4965        &mut down_out,
4966        m_e,
4967        ff,
4968        hidden,
4969    )?;
4970    Ok(down_out)
4971}
4972
4973/// View-destination twin of `Engine::rms_norm` — same kernel, same block size, same args,
4974/// so BIT-IDENTICAL; it exists only so the gate can normalize into one contiguous
4975/// stream-major buffer instead of `streams` separate allocations (the fused gate kernels
4976/// need every stream in one launch). PDL is skipped: dependent launch changes scheduling,
4977/// not arithmetic.
4978fn launch_rms_norm_into_view(
4979    e: &Engine,
4980    x: &CudaSlice<f32>,
4981    w: &CudaSlice<f32>,
4982    dst: &mut cudarc::driver::CudaViewMut<'_, f32>,
4983    ncols: usize,
4984    nrows: usize,
4985    eps: f32,
4986) -> Res<()> {
4987    let kname = if Engine::norm_ilp_on() {
4988        "rms_norm_f32_v2"
4989    } else {
4990        "rms_norm_f32"
4991    };
4992    let f = e.func(kname);
4993    let cfg = LaunchConfig {
4994        grid_dim: (nrows as u32, 1, 1),
4995        block_dim: (crate::rms_block(), 1, 1),
4996        shared_mem_bytes: 0,
4997    };
4998    let (nc, ep) = (ncols as i32, eps);
4999    let stream = e.gpu.stream();
5000    let mut b = stream.launch_builder(&f);
5001    b.arg(x).arg(w).arg(dst).arg(&nc).arg(&ep);
5002    unsafe {
5003        b.launch(cfg)?;
5004    }
5005    Ok(())
5006}
5007
5008/// `hc_lowrank_reduce_f32`: low_act[t, rank] = silu(inv_streams · Σ_s parts[s, t, rank]).
5009fn launch_hc_lowrank_reduce(
5010    e: &Engine,
5011    parts: &CudaSlice<f32>,
5012    low_act: &mut CudaSlice<f32>,
5013    streams: usize,
5014    t: usize,
5015    rank: usize,
5016) -> Res<()> {
5017    let f = e.func("hc_lowrank_reduce_f32");
5018    let cfg = LaunchConfig::for_num_elems((t * rank) as u32);
5019    let (si, ti, ri) = (streams as i32, t as i32, rank as i32);
5020    let inv = 1.0f32 / streams as f32;
5021    let stream = e.gpu.stream();
5022    let mut b = stream.launch_builder(&f);
5023    b.arg(parts)
5024        .arg(low_act)
5025        .arg(&si)
5026        .arg(&ti)
5027        .arg(&ri)
5028        .arg(&inv);
5029    unsafe {
5030        b.launch(cfg)?;
5031    }
5032    Ok(())
5033}
5034
5035/// `hc_mix_epilogue_f32`: mixed = inv_streams · Σ_s sigmoid(gates_s) ⊙ normed_s.
5036fn launch_hc_mix_epilogue(
5037    e: &Engine,
5038    gates: &CudaSlice<f32>,
5039    normed: &CudaSlice<f32>,
5040    mixed: &mut CudaSlice<f32>,
5041    streams: usize,
5042    t: usize,
5043    hidden: usize,
5044) -> Res<()> {
5045    let f = e.func("hc_mix_epilogue_f32");
5046    let cfg = LaunchConfig::for_num_elems((t * hidden) as u32);
5047    let (si, ti, hi) = (streams as i32, t as i32, hidden as i32);
5048    let inv = 1.0f32 / streams as f32;
5049    let stream = e.gpu.stream();
5050    let mut b = stream.launch_builder(&f);
5051    b.arg(gates)
5052        .arg(normed)
5053        .arg(mixed)
5054        .arg(&si)
5055        .arg(&ti)
5056        .arg(&hi)
5057        .arg(&inv);
5058    unsafe {
5059        b.launch(cfg)?;
5060    }
5061    Ok(())
5062}
5063
5064/// `hc_inject_gates_f32`: out[s, t] = 2·sigmoid(inv_streams · ⟨w_s, wide_normed_t⟩).
5065fn launch_hc_inject_gates(
5066    e: &Engine,
5067    normed: &CudaSlice<f32>,
5068    w: &CudaSlice<f32>,
5069    out: &mut CudaSlice<f32>,
5070    streams: usize,
5071    t: usize,
5072    hidden: usize,
5073) -> Res<()> {
5074    let f = e.func("hc_inject_gates_f32");
5075    let cfg = LaunchConfig {
5076        grid_dim: (streams as u32, t as u32, 1),
5077        block_dim: (256, 1, 1),
5078        shared_mem_bytes: 0,
5079    };
5080    let (si, ti, hi) = (streams as i32, t as i32, hidden as i32);
5081    let inv = 1.0f32 / streams as f32;
5082    let stream = e.gpu.stream();
5083    let mut b = stream.launch_builder(&f);
5084    b.arg(normed)
5085        .arg(w)
5086        .arg(out)
5087        .arg(&si)
5088        .arg(&ti)
5089        .arg(&hi)
5090        .arg(&inv);
5091    unsafe {
5092        b.launch(cfg)?;
5093    }
5094    Ok(())
5095}
5096
5097/// Inject scalars as either per-stream rows (the item-1-era plumbing, hcmicro OFF and
5098/// the legacy gate) or the [streams, t] slab straight out of the two-stage inject
5099/// (hcmicro ON — no per-stream d2d copies; `gate_write` consumes it in one launch).
5100enum InjectOut {
5101    Rows(Vec<CudaSlice<f32>>),
5102    Slab(CudaSlice<f32>),
5103}
5104
5105/// Park an inject result back into its slots (the form is flag-determined, so takes and
5106/// puts pair up step over step).
5107fn put_inject(ws: &mut StepPool, inject: InjectOut) {
5108    match inject {
5109        InjectOut::Rows(rows) => {
5110            for (s, row) in rows.into_iter().enumerate() {
5111                ws.put_f32(INJECT_SLOTS[s], row);
5112            }
5113        }
5114        InjectOut::Slab(slab) => ws.put_f32("hc.inj_all", slab),
5115    }
5116}
5117
5118/// Take the parked inject scalars in the form the current seams produce (graph driver's
5119/// MoE tail — the mlp read gate parked them in the interior segment).
5120fn take_inject(e: &Engine, ws: &mut StepPool, streams: usize, t: usize) -> Res<InjectOut> {
5121    // The diet emits the Slab form and requires micro_inj at dispatch, so this predicate
5122    // stays in lockstep with what gate_read parked.
5123    if micro_inj_on() && hc_fused_gate_on() {
5124        Ok(InjectOut::Slab(ws.take_f32(
5125            e,
5126            "hc.inj_all",
5127            streams * t,
5128            0,
5129        )?))
5130    } else {
5131        let mut rows = Vec::with_capacity(streams);
5132        for s in 0..streams {
5133            rows.push(ws.take_f32(e, INJECT_SLOTS[s], t, 0)?);
5134        }
5135        Ok(InjectOut::Rows(rows))
5136    }
5137}
5138
5139/// `hc_norm_planes_f32`: per-(stream, token) RMSNorm over the plane pointer table into
5140/// the stream-major normed slab — one launch for all streams (hcmicro seam).
5141#[allow(clippy::too_many_arguments)]
5142fn launch_hc_norm_planes(
5143    e: &Engine,
5144    ptrs: &CudaSlice<u64>,
5145    w_stack: &CudaSlice<f32>,
5146    dst: &mut CudaSlice<f32>,
5147    hidden: usize,
5148    t: usize,
5149    streams: usize,
5150    eps: f32,
5151) -> Res<()> {
5152    let f = e.func("hc_norm_planes_f32");
5153    let cfg = LaunchConfig {
5154        grid_dim: (t as u32, streams as u32, 1),
5155        block_dim: (256, 1, 1),
5156        shared_mem_bytes: 0,
5157    };
5158    let (hi, ti) = (hidden as i32, t as i32);
5159    let stream = e.gpu.stream();
5160    let mut b = stream.launch_builder(&f);
5161    b.arg(ptrs)
5162        .arg(w_stack)
5163        .arg(dst)
5164        .arg(&hi)
5165        .arg(&ti)
5166        .arg(&eps);
5167    unsafe {
5168        b.launch(cfg)?;
5169    }
5170    Ok(())
5171}
5172
5173/// Two-stage inject (hcmicro seam): chunked partial dots (fills the card; the
5174/// single-stage kernel ran `streams` blocks) then a sequential-order reduce + sigmoid.
5175/// Deterministic — no atomics (greedy replays must stay byte-stable).
5176#[allow(clippy::too_many_arguments)]
5177fn launch_hc_inject_two_stage(
5178    e: &Engine,
5179    normed: &CudaSlice<f32>,
5180    w_f32: &CudaSlice<f32>,
5181    w_b16: Option<&CudaSlice<u8>>,
5182    partials: &mut CudaSlice<f32>,
5183    out: &mut CudaSlice<f32>,
5184    streams: usize,
5185    t: usize,
5186    hidden: usize,
5187    chunks: usize,
5188) -> Res<()> {
5189    let cfg = LaunchConfig {
5190        grid_dim: (streams as u32, t as u32, chunks as u32),
5191        block_dim: (256, 1, 1),
5192        shared_mem_bytes: 0,
5193    };
5194    let (si, ti, hi, ci) = (streams as i32, t as i32, hidden as i32, chunks as i32);
5195    let stream = e.gpu.stream();
5196    if let Some(w) = w_b16 {
5197        let f = e.func("hc_inject_partials_bf16w_f32");
5198        let mut b = stream.launch_builder(&f);
5199        b.arg(normed)
5200            .arg(w)
5201            .arg(&mut *partials)
5202            .arg(&si)
5203            .arg(&ti)
5204            .arg(&hi)
5205            .arg(&ci);
5206        unsafe {
5207            b.launch(cfg)?;
5208        }
5209    } else {
5210        let f = e.func("hc_inject_partials_f32");
5211        let mut b = stream.launch_builder(&f);
5212        b.arg(normed)
5213            .arg(w_f32)
5214            .arg(&mut *partials)
5215            .arg(&si)
5216            .arg(&ti)
5217            .arg(&hi)
5218            .arg(&ci);
5219        unsafe {
5220            b.launch(cfg)?;
5221        }
5222    }
5223    let rows = (streams * t) as i32;
5224    let inv = 1.0f32 / streams as f32;
5225    let f = e.func("hc_inject_reduce_f32");
5226    let cfg = LaunchConfig::for_num_elems((streams * t) as u32);
5227    let mut b = stream.launch_builder(&f);
5228    b.arg(&*partials).arg(out).arg(&rows).arg(&ci).arg(&inv);
5229    unsafe {
5230        b.launch(cfg)?;
5231    }
5232    Ok(())
5233}
5234
5235/// hc-diet stage 1 (`hc_diet_stage1_f32`): per (row-chunk, stream) block — RMS recompute
5236/// from the raw plane, normed row in smem, this chunk's down rows + inject partial rows.
5237/// Emits parts [S, rank], inj_parts [n_inj, S], inv [S].
5238#[allow(clippy::too_many_arguments)]
5239fn launch_hc_diet_stage1(
5240    e: &Engine,
5241    ptrs: &CudaSlice<u64>,
5242    nw_stack: &CudaSlice<f32>,
5243    wdown_b16: &CudaSlice<u8>,
5244    winj_b16: Option<&CudaSlice<u8>>,
5245    parts: &mut CudaSlice<f32>,
5246    inj_parts: &mut CudaSlice<f32>,
5247    inv_out: &mut CudaSlice<f32>,
5248    hidden: usize,
5249    rank: usize,
5250    streams: usize,
5251    t: usize,
5252    eps: f32,
5253) -> Res<()> {
5254    if hidden % 8 != 0 {
5255        return Err("hc_diet_stage1_f32: hidden % 8 != 0".into());
5256    }
5257    let n_inj = if winj_b16.is_some() { streams } else { 0 };
5258    const ROWS_PB: usize = 4;
5259    let total_rows = rank + n_inj;
5260    if parts.len() < t * streams * rank
5261        || (n_inj > 0 && inj_parts.len() < t * n_inj * streams)
5262        || inv_out.len() < t * streams
5263    {
5264        return Err("hc_diet_stage1_f32: output buffers too short".into());
5265    }
5266    let f = e.func("hc_diet_stage1_f32");
5267    let cfg = LaunchConfig {
5268        grid_dim: (
5269            total_rows.div_ceil(ROWS_PB) as u32,
5270            t as u32,
5271            streams as u32,
5272        ),
5273        block_dim: (256, 1, 1),
5274        shared_mem_bytes: (hidden * 4) as u32,
5275    };
5276    let (hi, ri, si, nji, rpb) = (
5277        hidden as i32,
5278        rank as i32,
5279        streams as i32,
5280        n_inj as i32,
5281        ROWS_PB as i32,
5282    );
5283    let winj = winj_b16.unwrap_or(wdown_b16); // unread when n_inj == 0
5284    let stream = e.gpu.stream();
5285    let mut b = stream.launch_builder(&f);
5286    b.arg(ptrs)
5287        .arg(nw_stack)
5288        .arg(wdown_b16)
5289        .arg(winj)
5290        .arg(&mut *parts)
5291        .arg(&mut *inj_parts)
5292        .arg(&mut *inv_out)
5293        .arg(&hi)
5294        .arg(&ri)
5295        .arg(&si)
5296        .arg(&nji)
5297        .arg(&rpb)
5298        .arg(&eps);
5299    unsafe {
5300        b.launch(cfg)?;
5301    }
5302    Ok(())
5303}
5304
5305/// hc-diet stage 2 (`hc_diet_stage2_f32`): low_act = silu(mean_s parts) (the
5306/// hc_lowrank_reduce association verbatim) + inj = 2*sigmoid(mean_s2 inj_parts).
5307#[allow(clippy::too_many_arguments)]
5308fn launch_hc_diet_stage2(
5309    e: &Engine,
5310    parts: &CudaSlice<f32>,
5311    inj_parts: &CudaSlice<f32>,
5312    low_act: &mut CudaSlice<f32>,
5313    inj_all: &mut CudaSlice<f32>,
5314    rank: usize,
5315    streams: usize,
5316    t: usize,
5317    with_inject: bool,
5318) -> Res<()> {
5319    let n_inj = if with_inject { streams } else { 0 };
5320    if low_act.len() < t * rank || (n_inj > 0 && inj_all.len() < n_inj * t) {
5321        return Err("hc_diet_stage2_f32: output buffers too short".into());
5322    }
5323    let f = e.func("hc_diet_stage2_f32");
5324    let cfg = LaunchConfig {
5325        grid_dim: (((rank + n_inj) as u32).div_ceil(256), t as u32, 1),
5326        block_dim: (256, 1, 1),
5327        shared_mem_bytes: 0,
5328    };
5329    let (ri, si, nji, ti) = (rank as i32, streams as i32, n_inj as i32, t as i32);
5330    let inv = 1.0f32 / streams as f32;
5331    let stream = e.gpu.stream();
5332    let mut b = stream.launch_builder(&f);
5333    b.arg(parts)
5334        .arg(inj_parts)
5335        .arg(&mut *low_act)
5336        .arg(&mut *inj_all)
5337        .arg(&ri)
5338        .arg(&si)
5339        .arg(&nji)
5340        .arg(&ti)
5341        .arg(&inv);
5342    unsafe {
5343        b.launch(cfg)?;
5344    }
5345    Ok(())
5346}
5347
5348/// hc-diet stage 3 (`hc_diet_stage3_f32`): per dim-chunk block — the up dots for all
5349/// streams from a smem low_act copy, then the mix epilogue from the stage-1 inv scalars.
5350#[allow(clippy::too_many_arguments)]
5351fn launch_hc_diet_stage3(
5352    e: &Engine,
5353    ptrs: &CudaSlice<u64>,
5354    nw_stack: &CudaSlice<f32>,
5355    inv_in: &CudaSlice<f32>,
5356    wup_b16: &CudaSlice<u8>,
5357    low_act: &CudaSlice<f32>,
5358    mixed: &mut CudaSlice<f32>,
5359    hidden: usize,
5360    rank: usize,
5361    streams: usize,
5362    t: usize,
5363) -> Res<()> {
5364    const DIMS_PB: usize = 8;
5365    if mixed.len() < t * hidden {
5366        return Err("hc_diet_stage3_f32: output buffer too short".into());
5367    }
5368    let f = e.func("hc_diet_stage3_f32");
5369    let cfg = LaunchConfig {
5370        grid_dim: (hidden.div_ceil(DIMS_PB) as u32, t as u32, 1),
5371        block_dim: (256, 1, 1),
5372        shared_mem_bytes: ((rank + DIMS_PB * streams) * 4) as u32,
5373    };
5374    let (hi, ri, si, dpb) = (hidden as i32, rank as i32, streams as i32, DIMS_PB as i32);
5375    let inv_streams = 1.0f32 / streams as f32;
5376    let stream = e.gpu.stream();
5377    let mut b = stream.launch_builder(&f);
5378    b.arg(ptrs)
5379        .arg(nw_stack)
5380        .arg(inv_in)
5381        .arg(wup_b16)
5382        .arg(low_act)
5383        .arg(&mut *mixed)
5384        .arg(&hi)
5385        .arg(&ri)
5386        .arg(&si)
5387        .arg(&dpb)
5388        .arg(&inv_streams);
5389    unsafe {
5390        b.launch(cfg)?;
5391    }
5392    Ok(())
5393}
5394
5395/// hc-diet MT stage 0 (`hc_diet_stage0_mt_f32`): the stage-1 RMS reduce EXACTLY, per
5396/// (token, stream) — bit-equal inv scalars for the weight-shared stages.
5397fn launch_hc_diet_stage0_mt(
5398    e: &Engine,
5399    ptrs: &CudaSlice<u64>,
5400    inv_out: &mut CudaSlice<f32>,
5401    hidden: usize,
5402    streams: usize,
5403    t: usize,
5404    eps: f32,
5405) -> Res<()> {
5406    if inv_out.len() < t * streams {
5407        return Err("hc_diet_stage0_mt_f32: inv buffer too short".into());
5408    }
5409    let f = e.func("hc_diet_stage0_mt_f32");
5410    let cfg = LaunchConfig {
5411        grid_dim: (t as u32, streams as u32, 1),
5412        block_dim: (256, 1, 1),
5413        shared_mem_bytes: 0,
5414    };
5415    let (hi, si, ti) = (hidden as i32, streams as i32, t as i32);
5416    let stream = e.gpu.stream();
5417    let mut b = stream.launch_builder(&f);
5418    b.arg(ptrs)
5419        .arg(&mut *inv_out)
5420        .arg(&hi)
5421        .arg(&si)
5422        .arg(&ti)
5423        .arg(&eps);
5424    unsafe {
5425        b.launch(cfg)?;
5426    }
5427    Ok(())
5428}
5429
5430/// hc-diet MT stage 1: weight rows read ONCE, tokens iterated inside with inline
5431/// normalization — per-(row, token) chains VERBATIM vs the token-grid stage 1.
5432#[allow(clippy::too_many_arguments)]
5433fn launch_hc_diet_stage1_mt(
5434    e: &Engine,
5435    ptrs: &CudaSlice<u64>,
5436    nw_stack: &CudaSlice<f32>,
5437    inv_in: &CudaSlice<f32>,
5438    wdown_b16: &CudaSlice<u8>,
5439    winj_b16: Option<&CudaSlice<u8>>,
5440    parts: &mut CudaSlice<f32>,
5441    inj_parts: &mut CudaSlice<f32>,
5442    hidden: usize,
5443    rank: usize,
5444    streams: usize,
5445    t: usize,
5446) -> Res<()> {
5447    if hidden % 8 != 0 || !(2..=12).contains(&t) {
5448        return Err("hc_diet_stage1_mt_f32: geometry".into());
5449    }
5450    let n_inj = if winj_b16.is_some() { streams } else { 0 };
5451    const ROWS_PB: usize = 4;
5452    let total_rows = rank + n_inj;
5453    if parts.len() < t * streams * rank || (n_inj > 0 && inj_parts.len() < t * n_inj * streams) {
5454        return Err("hc_diet_stage1_mt_f32: output buffers too short".into());
5455    }
5456    let f = e.func("hc_diet_stage1_mt_f32");
5457    let cfg = LaunchConfig {
5458        grid_dim: (total_rows.div_ceil(ROWS_PB) as u32, 1, streams as u32),
5459        block_dim: (256, 1, 1),
5460        shared_mem_bytes: 0,
5461    };
5462    let (hi, ri, si, nji, rpb, ti) = (
5463        hidden as i32,
5464        rank as i32,
5465        streams as i32,
5466        n_inj as i32,
5467        ROWS_PB as i32,
5468        t as i32,
5469    );
5470    let winj = winj_b16.unwrap_or(wdown_b16);
5471    let stream = e.gpu.stream();
5472    let mut b = stream.launch_builder(&f);
5473    b.arg(ptrs)
5474        .arg(nw_stack)
5475        .arg(inv_in)
5476        .arg(wdown_b16)
5477        .arg(winj)
5478        .arg(&mut *parts)
5479        .arg(&mut *inj_parts)
5480        .arg(&hi)
5481        .arg(&ri)
5482        .arg(&si)
5483        .arg(&nji)
5484        .arg(&rpb)
5485        .arg(&ti);
5486    unsafe {
5487        b.launch(cfg)?;
5488    }
5489    Ok(())
5490}
5491
5492/// hc-diet MT stage 3: up rows read once, all T low_act rows resident in smem.
5493#[allow(clippy::too_many_arguments)]
5494fn launch_hc_diet_stage3_mt(
5495    e: &Engine,
5496    ptrs: &CudaSlice<u64>,
5497    nw_stack: &CudaSlice<f32>,
5498    inv_in: &CudaSlice<f32>,
5499    wup_b16: &CudaSlice<u8>,
5500    low_act: &CudaSlice<f32>,
5501    mixed: &mut CudaSlice<f32>,
5502    hidden: usize,
5503    rank: usize,
5504    streams: usize,
5505    t: usize,
5506) -> Res<()> {
5507    const DIMS_PB: usize = 8;
5508    if !(2..=12).contains(&t) || mixed.len() < t * hidden {
5509        return Err("hc_diet_stage3_mt_f32: geometry".into());
5510    }
5511    let smem = ((t * rank + DIMS_PB * streams * t) * 4) as u32;
5512    if smem > 96 * 1024 {
5513        return Err("hc_diet_stage3_mt_f32: smem over budget".into());
5514    }
5515    let f = e.func("hc_diet_stage3_mt_f32");
5516    let cfg = LaunchConfig {
5517        grid_dim: (hidden.div_ceil(DIMS_PB) as u32, 1, 1),
5518        block_dim: (256, 1, 1),
5519        shared_mem_bytes: smem,
5520    };
5521    let (hi, ri, si, dpb, ti) = (
5522        hidden as i32,
5523        rank as i32,
5524        streams as i32,
5525        DIMS_PB as i32,
5526        t as i32,
5527    );
5528    let inv_streams = 1.0f32 / streams as f32;
5529    let stream = e.gpu.stream();
5530    let mut b = stream.launch_builder(&f);
5531    b.arg(ptrs)
5532        .arg(nw_stack)
5533        .arg(inv_in)
5534        .arg(wup_b16)
5535        .arg(low_act)
5536        .arg(&mut *mixed)
5537        .arg(&hi)
5538        .arg(&ri)
5539        .arg(&si)
5540        .arg(&dpb)
5541        .arg(&ti)
5542        .arg(&inv_streams);
5543    unsafe {
5544        b.launch(cfg)?;
5545    }
5546    Ok(())
5547}
5548
5549/// `hc_write_planes_f32`: plane_s += block_out ⊗ inj[s] for every stream in one launch
5550/// over the plane pointer table (hcmicro seam).
5551fn launch_hc_write_planes(
5552    e: &Engine,
5553    ptrs: &CudaSlice<u64>,
5554    block_out: &CudaSlice<f32>,
5555    inj: &CudaSlice<f32>,
5556    hidden: usize,
5557    t: usize,
5558    streams: usize,
5559) -> Res<()> {
5560    let f = e.func("hc_write_planes_f32");
5561    let n = (t * hidden) as u32;
5562    let cfg = LaunchConfig {
5563        grid_dim: (n.div_ceil(256), streams as u32, 1),
5564        block_dim: (256, 1, 1),
5565        shared_mem_bytes: 0,
5566    };
5567    let (hi, ti) = (hidden as i32, t as i32);
5568    let stream = e.gpu.stream();
5569    let mut b = stream.launch_builder(&f);
5570    b.arg(ptrs).arg(block_out).arg(inj).arg(&hi).arg(&ti);
5571    unsafe {
5572        b.launch(cfg)?;
5573    }
5574    Ok(())
5575}
5576
5577/// `hc_inject_gates_bf16w_f32`: the bf16-weight twin of `launch_hc_inject_gates` — same
5578/// grid, same loop order, same reduction tree, exact bf16→f32 widening, so BIT-IDENTICAL
5579/// to the f32 arm when the resident bytes match (the `bf16_twin` representability guard).
5580fn launch_hc_inject_gates_b16(
5581    e: &Engine,
5582    normed: &CudaSlice<f32>,
5583    w: &CudaSlice<u8>,
5584    out: &mut CudaSlice<f32>,
5585    streams: usize,
5586    t: usize,
5587    hidden: usize,
5588) -> Res<()> {
5589    let f = e.func("hc_inject_gates_bf16w_f32");
5590    let cfg = LaunchConfig {
5591        grid_dim: (streams as u32, t as u32, 1),
5592        block_dim: (256, 1, 1),
5593        shared_mem_bytes: 0,
5594    };
5595    let (si, ti, hi) = (streams as i32, t as i32, hidden as i32);
5596    let inv = 1.0f32 / streams as f32;
5597    let stream = e.gpu.stream();
5598    let mut b = stream.launch_builder(&f);
5599    b.arg(normed)
5600        .arg(w)
5601        .arg(out)
5602        .arg(&si)
5603        .arg(&ti)
5604        .arg(&hi)
5605        .arg(&inv);
5606    unsafe {
5607        b.launch(cfg)?;
5608    }
5609    Ok(())
5610}
5611
5612/// bf16 trunk-residency twin builder (load time). Returns the packed bf16 device bytes
5613/// iff BOTH guards pass: in_f % 8 == 0 (the kernel's uint4 vector width — geometry, not
5614/// policy) and every value is exactly bf16-representable (low 16 mantissa bits zero —
5615/// true whenever the checkpoint row was BF16, since dequant is an exact widening; the
5616/// f32 tiny fixture fails this and keeps its f32-only residency).
5617fn bf16_twin(e: &Engine, data: &[f32], in_f: usize) -> Res<Option<CudaSlice<u8>>> {
5618    if in_f % 8 != 0 {
5619        return Ok(None);
5620    }
5621    let mut bytes = Vec::with_capacity(data.len() * 2);
5622    for &v in data {
5623        let bits = v.to_bits();
5624        if bits & 0xFFFF != 0 {
5625            return Ok(None);
5626        }
5627        bytes.extend_from_slice(&((bits >> 16) as u16).to_le_bytes());
5628    }
5629    Ok(Some(e.htod_bytes(&bytes)?))
5630}
5631
5632/// One launch of `qmatvec_bf16w_f32`: y[b, tok, :out_f] = W_b(bf16) @ x_{b,tok}, f32
5633/// accumulate. Strides in ELEMENTS; `x_bstride == 0` shares one activation across the
5634/// batch (the read gate's up projection). Products are exact (bf16→f32 widening); only
5635/// the reduction tree differs from cuBLASLt — the accumulation class.
5636#[allow(clippy::too_many_arguments)]
5637fn launch_qmatvec_bf16w(
5638    e: &Engine,
5639    w: &CudaSlice<u8>,
5640    x: &CudaSlice<f32>,
5641    y: &mut CudaSlice<f32>,
5642    in_f: usize,
5643    out_f: usize,
5644    t: usize,
5645    batch: usize,
5646    w_bstride: usize,
5647    x_bstride: usize,
5648    x_tstride: usize,
5649    y_bstride: usize,
5650) -> Res<()> {
5651    if in_f % 8 != 0 || x_bstride % 8 != 0 || x_tstride % 8 != 0 {
5652        return Err("qmatvec_bf16w_f32: stride breaks the uint4/float4 vector width".into());
5653    }
5654    if y.len() < (batch - 1) * y_bstride + t * out_f {
5655        return Err("qmatvec_bf16w_f32: output buffer too short".into());
5656    }
5657    let f = e.func("qmatvec_bf16w_f32");
5658    let cfg = LaunchConfig {
5659        grid_dim: (out_f as u32, t as u32, batch as u32),
5660        block_dim: (128, 1, 1),
5661        shared_mem_bytes: 0,
5662    };
5663    let (inf, outf, ti) = (in_f as i32, out_f as i32, t as i32);
5664    let (wb, xb, xt, yb) = (
5665        w_bstride as i64,
5666        x_bstride as i64,
5667        x_tstride as i64,
5668        y_bstride as i64,
5669    );
5670    let stream = e.gpu.stream();
5671    let mut b = stream.launch_builder(&f);
5672    b.arg(w)
5673        .arg(x)
5674        .arg(y)
5675        .arg(&inf)
5676        .arg(&outf)
5677        .arg(&ti)
5678        .arg(&wb)
5679        .arg(&xb)
5680        .arg(&xt)
5681        .arg(&yb);
5682    unsafe {
5683        b.launch(cfg)?;
5684    }
5685    Ok(())
5686}
5687
5688/// Stacked bf16 twin over several same-in_f projections (the proj-stack seam): concat
5689/// the host f32 rows and build one packed twin. `None` under the same guards as
5690/// `bf16_twin` (in_f % 8, exact representability of EVERY part). The stack REPLACES the
5691/// per-mat twins (VRAM-neutral): the per-mat arm launches against row-offset VIEWS of
5692/// the stack — same bytes, same kernel, bit-identical to separate residency.
5693fn bf16_stack_twin(e: &Engine, parts: &[&[f32]], in_f: usize) -> Res<Option<CudaSlice<u8>>> {
5694    let mut cat: Vec<f32> = Vec::with_capacity(parts.iter().map(|p| p.len()).sum());
5695    for p in parts {
5696        cat.extend_from_slice(p);
5697    }
5698    bf16_twin(e, &cat, in_f)
5699}
5700
5701/// Required-stack twin (the TP2 `need_twin` posture).
5702fn need_stack_twin(e: &Engine, parts: &[&[f32]], in_f: usize, what: &str) -> Res<CudaSlice<u8>> {
5703    bf16_stack_twin(e, parts, in_f)?.ok_or_else(|| {
5704        format!("qwen4exp_gpu tp2: {what} has no exact bf16 stack twin (in_f {in_f})").into()
5705    })
5706}
5707
5708/// One `qmatvec_bf16w_f32` launch against a ROW-OFFSET VIEW of a stacked twin (the
5709/// per-mat arm of the proj-stack seam): W = stack rows [row_off, row_off+out_f), batch 1.
5710/// Identical kernel, grid, and bytes as a separately-resident twin => bit-identical.
5711#[allow(clippy::too_many_arguments)]
5712fn launch_qmatvec_bf16w_off(
5713    e: &Engine,
5714    w_stack: &CudaSlice<u8>,
5715    row_off: usize,
5716    x: &CudaSlice<f32>,
5717    y: &mut CudaSlice<f32>,
5718    in_f: usize,
5719    out_f: usize,
5720    t: usize,
5721) -> Res<()> {
5722    if in_f % 8 != 0 {
5723        return Err("qmatvec_bf16w_f32: stride breaks the uint4/float4 vector width".into());
5724    }
5725    if y.len() < t * out_f {
5726        return Err("qmatvec_bf16w_f32: output buffer too short".into());
5727    }
5728    let byte_off = row_off * in_f * 2;
5729    if w_stack.len() < byte_off + out_f * in_f * 2 {
5730        return Err("qmatvec_bf16w_f32: stacked twin shorter than the row window".into());
5731    }
5732    let wv = w_stack.slice(byte_off..w_stack.len());
5733    let f = e.func("qmatvec_bf16w_f32");
5734    let cfg = LaunchConfig {
5735        grid_dim: (out_f as u32, t as u32, 1),
5736        block_dim: (128, 1, 1),
5737        shared_mem_bytes: 0,
5738    };
5739    let (inf, outf, ti) = (in_f as i32, out_f as i32, t as i32);
5740    let (wb, xb, xt, yb) = (0i64, 0i64, in_f as i64, 0i64);
5741    let stream = e.gpu.stream();
5742    let mut b = stream.launch_builder(&f);
5743    b.arg(&wv)
5744        .arg(x)
5745        .arg(y)
5746        .arg(&inf)
5747        .arg(&outf)
5748        .arg(&ti)
5749        .arg(&wb)
5750        .arg(&xb)
5751        .arg(&xt)
5752        .arg(&yb);
5753    unsafe {
5754        b.launch(cfg)?;
5755    }
5756    Ok(())
5757}
5758
5759/// `qmatvec_bf16w_f32` against row-offset W, x, and y VIEWS (t == 1): the per-selected-
5760/// expert arm of the DeviceBf16 draft bank (mtp-spec lane) — expert `e`'s projection is
5761/// rows [w_row_off, w_row_off+out_f) of the resident [E*out_f, in_f] bf16 stack. Same
5762/// kernel and per-row program as every other qmatvec_bf16w launch (exact-widening
5763/// products, block-128 reduce) => rows are bit-identical to a separately-resident twin.
5764#[allow(clippy::too_many_arguments)]
5765fn launch_qmatvec_bf16w_off_into(
5766    e: &Engine,
5767    w_stack: &CudaSlice<u8>,
5768    w_row_off: usize,
5769    x: &CudaSlice<f32>,
5770    x_off: usize,
5771    y: &mut CudaSlice<f32>,
5772    y_off: usize,
5773    in_f: usize,
5774    out_f: usize,
5775) -> Res<()> {
5776    if in_f % 8 != 0 {
5777        return Err("qmatvec_bf16w_f32: stride breaks the uint4/float4 vector width".into());
5778    }
5779    let byte_off = w_row_off * in_f * 2;
5780    if w_stack.len() < byte_off + out_f * in_f * 2 {
5781        return Err("qmatvec_bf16w_f32: bank shorter than the expert row window".into());
5782    }
5783    if x.len() < x_off + in_f || y.len() < y_off + out_f {
5784        return Err("qmatvec_bf16w_f32: operand views out of range".into());
5785    }
5786    let wv = w_stack.slice(byte_off..w_stack.len());
5787    let xv = x.slice(x_off..x_off + in_f);
5788    let mut yv = y.slice_mut(y_off..y_off + out_f);
5789    let f = e.func("qmatvec_bf16w_f32");
5790    let cfg = LaunchConfig {
5791        grid_dim: (out_f as u32, 1, 1),
5792        block_dim: (128, 1, 1),
5793        shared_mem_bytes: 0,
5794    };
5795    let (inf, outf, ti) = (in_f as i32, out_f as i32, 1i32);
5796    let (wb, xb, xt, yb) = (0i64, 0i64, in_f as i64, 0i64);
5797    let stream = e.gpu.stream();
5798    let mut b = stream.launch_builder(&f);
5799    b.arg(&wv)
5800        .arg(&xv)
5801        .arg(&mut yv)
5802        .arg(&inf)
5803        .arg(&outf)
5804        .arg(&ti)
5805        .arg(&wb)
5806        .arg(&xb)
5807        .arg(&xt)
5808        .arg(&yb);
5809    unsafe {
5810        b.launch(cfg)?;
5811    }
5812    Ok(())
5813}
5814
5815/// Device-selected expert launch over a DeviceBf16 bank (`qmatvec_bf16w_sel_f32`,
5816/// devtwin lane): one launch per projection covers every routed expert — slot s reads
5817/// its expert id from the DEVICE `sel` array at `sel_off + s` and writes y at s*out_f.
5818/// Per-row program qmatvec_bf16w_f32 VERBATIM => bit-identical to the per-slot
5819/// `launch_qmatvec_bf16w_off_into` chain (asserted by the bf16 oracle's sel mode).
5820#[allow(clippy::too_many_arguments)]
5821fn launch_qmatvec_bf16w_sel(
5822    e: &Engine,
5823    bank: &CudaSlice<u8>,
5824    sel: &CudaSlice<i32>,
5825    sel_off: usize,
5826    x: &CudaSlice<f32>,
5827    x_off: usize,
5828    // Per-slot activation stride in elements: 0 = shared row (gate/up), in_f = each
5829    // slot its own row (down over the act slab).
5830    x_sstride: usize,
5831    y: &mut CudaSlice<f32>,
5832    n_sel: usize,
5833    in_f: usize,
5834    out_f: usize,
5835) -> Res<()> {
5836    if in_f % 8 != 0 {
5837        return Err("qmatvec_bf16w_sel_f32: stride breaks the uint4/float4 vector width".into());
5838    }
5839    if sel.len() < sel_off + n_sel
5840        || x.len() < x_off + (n_sel - 1) * x_sstride + in_f
5841        || y.len() < n_sel * out_f
5842        || n_sel == 0
5843    {
5844        return Err("qmatvec_bf16w_sel_f32: operand views out of range".into());
5845    }
5846    let sv = sel.slice(sel_off..sel_off + n_sel);
5847    let xv = x.slice(x_off..x.len());
5848    let f = e.func("qmatvec_bf16w_sel_f32");
5849    let cfg = LaunchConfig {
5850        grid_dim: (out_f as u32, 1, n_sel as u32),
5851        block_dim: (128, 1, 1),
5852        shared_mem_bytes: 0,
5853    };
5854    let (inf, outf, ns) = (in_f as i32, out_f as i32, n_sel as i32);
5855    let xs = x_sstride as i64;
5856    let stream = e.gpu.stream();
5857    let mut b = stream.launch_builder(&f);
5858    b.arg(bank)
5859        .arg(&sv)
5860        .arg(&xv)
5861        .arg(&mut *y)
5862        .arg(&inf)
5863        .arg(&outf)
5864        .arg(&ns)
5865        .arg(&xs);
5866    unsafe {
5867        b.launch(cfg)?;
5868    }
5869    Ok(())
5870}
5871
5872/// Multi-token weight-shared launch (`qmatvec_bf16w_mt_f32`, mtp-spec verify): one
5873/// block per output row reads W once and fills EVERY token's output — per (row, token)
5874/// bit-identical to the per-token grid (kernel doc). 2 <= t <= 12; `w_row_off` selects
5875/// a row window of a stacked twin.
5876#[allow(clippy::too_many_arguments)]
5877fn launch_qmatvec_bf16w_mt(
5878    e: &Engine,
5879    w_stack: &CudaSlice<u8>,
5880    w_row_off: usize,
5881    x: &CudaSlice<f32>,
5882    y: &mut CudaSlice<f32>,
5883    in_f: usize,
5884    out_f: usize,
5885    t: usize,
5886) -> Res<()> {
5887    if in_f % 8 != 0 {
5888        return Err("qmatvec_bf16w_mt_f32: in_f % 8 != 0".into());
5889    }
5890    if !(2..=12).contains(&t) {
5891        return Err("qmatvec_bf16w_mt_f32: t out of range (2..=12)".into());
5892    }
5893    let byte_off = w_row_off * in_f * 2;
5894    if w_stack.len() < byte_off + out_f * in_f * 2 || y.len() < t * out_f || x.len() < t * in_f {
5895        return Err("qmatvec_bf16w_mt_f32: operands out of range".into());
5896    }
5897    let wv = w_stack.slice(byte_off..w_stack.len());
5898    let f = e.func("qmatvec_bf16w_mt_f32");
5899    let cfg = LaunchConfig {
5900        grid_dim: (out_f as u32, 1, 1),
5901        block_dim: (128, 1, 1),
5902        shared_mem_bytes: 0,
5903    };
5904    let (inf, outf, ti) = (in_f as i32, out_f as i32, t as i32);
5905    let (wb, xb, xt, yb) = (0i64, 0i64, in_f as i64, 0i64);
5906    let stream = e.gpu.stream();
5907    let mut b = stream.launch_builder(&f);
5908    b.arg(&wv)
5909        .arg(x)
5910        .arg(y)
5911        .arg(&inf)
5912        .arg(&outf)
5913        .arg(&ti)
5914        .arg(&wb)
5915        .arg(&xb)
5916        .arg(&xt)
5917        .arg(&yb);
5918    unsafe {
5919        b.launch(cfg)?;
5920    }
5921    Ok(())
5922}
5923
5924/// Trunk dense linear off a STACKED bf16 twin (proj-stack residency): the bf16 arm is a
5925/// row-offset view launch when the twin exists and the trunk seam is on, else the f32
5926/// cuBLASLt path.
5927#[allow(clippy::too_many_arguments)]
5928fn linear_trunk_stacked_into(
5929    e: &Engine,
5930    w_f32: &CudaSlice<f32>,
5931    stack_b16: &Option<CudaSlice<u8>>,
5932    row_off: usize,
5933    x: &CudaSlice<f32>,
5934    y: &mut CudaSlice<f32>,
5935    t: usize,
5936    in_f: usize,
5937    out_f: usize,
5938) -> Res<()> {
5939    if trunk_bf16_on() {
5940        if let Some(w) = stack_b16 {
5941            if (2..=12).contains(&t) && verify_mt_on() {
5942                return launch_qmatvec_bf16w_mt(e, w, row_off, x, y, in_f, out_f, t);
5943            }
5944            return launch_qmatvec_bf16w_off(e, w, row_off, x, y, in_f, out_f, t);
5945        }
5946    }
5947    if w_f32.len() < in_f * out_f {
5948        return Err(
5949            "qwen4exp_gpu: trunk f32 original dropped (trunk_f32_diet) — the bf16 \
5950                    twin path is required (keep trunk seams ON)"
5951                .into(),
5952        );
5953    }
5954    e.linear_device_into(x, w_f32, y, t, in_f, out_f)
5955}
5956
5957/// One launch of `qmatvec_bf16w_multi4_f32`: the row-stacked twin against ONE t==1
5958/// activation, each output row routed into its original destination buffer by row range
5959/// (raw device pointers — no copies). Per-row math is qmatvec_bf16w_f32 VERBATIM, so
5960/// outputs are BIT-IDENTICAL to the per-mat launches this replaces.
5961fn launch_qmatvec_bf16w_multi4(
5962    e: &Engine,
5963    w_stack: &CudaSlice<u8>,
5964    x: &CudaSlice<f32>,
5965    parts: &[(&CudaSlice<f32>, usize)],
5966    in_f: usize,
5967) -> Res<()> {
5968    if in_f % 8 != 0 {
5969        return Err("qmatvec_bf16w_multi4_f32: in_f % 8 != 0".into());
5970    }
5971    if parts.is_empty() || parts.len() > 4 {
5972        return Err("qmatvec_bf16w_multi4_f32: 1..=4 parts".into());
5973    }
5974    let total: usize = parts.iter().map(|&(_, r)| r).sum();
5975    if w_stack.len() < total * in_f * 2 {
5976        return Err("qmatvec_bf16w_multi4_f32: stacked twin shorter than the row plan".into());
5977    }
5978    let stream = e.gpu.stream();
5979    let mut ptrs = [0u64; 4];
5980    let mut rows = [0i32; 4];
5981    for (i, &(buf, r)) in parts.iter().enumerate() {
5982        if buf.len() < r {
5983            return Err("qmatvec_bf16w_multi4_f32: destination shorter than its rows".into());
5984        }
5985        ptrs[i] = buf.device_ptr(&stream).0;
5986        rows[i] = r as i32;
5987    }
5988    let f = e.func("qmatvec_bf16w_multi4_f32");
5989    let cfg = LaunchConfig {
5990        grid_dim: (total as u32, 1, 1),
5991        block_dim: (128, 1, 1),
5992        shared_mem_bytes: 0,
5993    };
5994    let inf = in_f as i32;
5995    let mut b = stream.launch_builder(&f);
5996    b.arg(w_stack)
5997        .arg(x)
5998        .arg(&ptrs[0])
5999        .arg(&rows[0])
6000        .arg(&ptrs[1])
6001        .arg(&rows[1])
6002        .arg(&ptrs[2])
6003        .arg(&rows[2])
6004        .arg(&ptrs[3])
6005        .arg(&rows[3])
6006        .arg(&inf);
6007    unsafe {
6008        b.launch(cfg)?;
6009    }
6010    Ok(())
6011}
6012
6013/// Trunk dense linear into a caller-provided buffer: the bf16 twin (one
6014/// `qmatvec_bf16w_f32` launch) when resident and the seam is on, else the f32
6015/// cuBLASLt path — the A/B twin (the step-workspace form, item 2a).
6016#[allow(clippy::too_many_arguments)]
6017fn linear_trunk_into(
6018    e: &Engine,
6019    w_f32: &CudaSlice<f32>,
6020    w_b16: &Option<CudaSlice<u8>>,
6021    x: &CudaSlice<f32>,
6022    y: &mut CudaSlice<f32>,
6023    t: usize,
6024    in_f: usize,
6025    out_f: usize,
6026) -> Res<()> {
6027    if trunk_bf16_on() {
6028        if let Some(w) = w_b16 {
6029            if (2..=12).contains(&t) && verify_mt_on() {
6030                return launch_qmatvec_bf16w_mt(e, w, 0, x, y, in_f, out_f, t);
6031            }
6032            return launch_qmatvec_bf16w(e, w, x, y, in_f, out_f, t, 1, 0, 0, in_f, 0);
6033        }
6034    }
6035    if w_f32.len() < in_f * out_f {
6036        return Err(
6037            "qwen4exp_gpu: trunk f32 original dropped (trunk_f32_diet) — the bf16 \
6038                    twin path is required (keep trunk seams ON)"
6039                .into(),
6040        );
6041    }
6042    e.linear_device_into(x, w_f32, y, t, in_f, out_f)
6043}
6044
6045/// One launch of the grouped selected-experts matvec: y[slot, :out_f] =
6046/// macros[sel[slot]] × (W_{sel[slot]} @ x_slot) over the AS-STORED modelopt bank (no
6047/// repack). `x_stride` = 0 shares one activation row across slots (gate/up); = in_f
6048/// reads per-slot rows (down). Dispatches the v2 kernel (uint4 code loads + 2 rows per
6049/// warp — perf lane item 3) when the seam is on and the geometry admits it
6050/// (in_f % 32 == 0, out_f % 2 == 0); v1 is the fallback and the A/B twin. Round 3 adds
6051/// the v3 kernel (4 rows/warp, `set_sel_v3`, out_f % 4 == 0) ahead of v2 in the chain.
6052#[allow(clippy::too_many_arguments)]
6053fn launch_nvfp4_sel_matvec(
6054    e: &Engine,
6055    codes: &CudaSlice<u8>,
6056    scales: &CudaSlice<u8>,
6057    macros_dev: &CudaSlice<f32>,
6058    sel: &CudaSlice<i32>,
6059    x: &CudaSlice<f32>,
6060    y: &mut CudaSlice<f32>,
6061    n_sel: usize,
6062    in_f: usize,
6063    out_f: usize,
6064    x_stride: usize,
6065) -> Res<()> {
6066    if in_f % 16 != 0 {
6067        return Err("qmatvec_nvfp4_modelopt_sel_f32: in_f % 16 != 0".into());
6068    }
6069    if y.len() < n_sel * out_f {
6070        return Err("qmatvec_nvfp4_modelopt_sel_f32: output shorter than n_sel*out_f".into());
6071    }
6072    // Sub-warp pair groups (`selgroup`, default AUTO since 2026-09-02) take precedence over the v3/v2/v1
6073    // chain when the geometry tiles exactly; `(g=32, rows=4)` reproduces v3's bits.
6074    let grp = sel_group_resolve(sel_group_dn(), in_f, out_f);
6075    let v3 = grp.is_none() && sel_v3_on() && in_f % 32 == 0 && out_f % 4 == 0;
6076    let v2 = grp.is_none() && !v3 && sel_v2_on() && in_f % 32 == 0 && out_f % 2 == 0;
6077    let f = e.func(if grp.is_some() {
6078        "qmatvec_nvfp4_modelopt_sel_g_f32"
6079    } else if v3 {
6080        "qmatvec_nvfp4_modelopt_sel_f32_v3"
6081    } else if v2 {
6082        "qmatvec_nvfp4_modelopt_sel_f32_v2"
6083    } else {
6084        "qmatvec_nvfp4_modelopt_sel_f32"
6085    });
6086    // Warp packing (4 warps/block) was tried here and REVERTED: measured NEGATIVE on
6087    // decode (plain arm 14.38 -> 15.13 ms) and flat on verify sel (mtp6 battery,
6088    // spec/mtp6) — the sel slice is not SM-block-slot-limited. The kernels keep the
6089    // lane-based indexing (identical at block 32); launch stays one warp per block. The
6090    // `selgroup` kernels honour `blockDim.x >> 5` too, but this lane deliberately leaves
6091    // block 32 alone so the A/B attributes ONE change (the lane partition) — a warps-per-
6092    // block knob would re-open the reverted measurement as a second free variable.
6093    let grid_x = match grp {
6094        Some((g, rows)) => out_f / ((32 / g) * rows),
6095        None if v3 => out_f / 4,
6096        None if v2 => out_f / 2,
6097        None => out_f,
6098    };
6099    let cfg = LaunchConfig {
6100        grid_dim: (grid_x as u32, n_sel as u32, 1),
6101        block_dim: (32, 1, 1),
6102        shared_mem_bytes: 0,
6103    };
6104    let (inf, outf) = (in_f as i32, out_f as i32);
6105    let xs = x_stride as i64;
6106    let (gi, ri) = grp.map_or((0i32, 0i32), |(g, rows)| (g as i32, rows as i32));
6107    let stream = e.gpu.stream();
6108    let mut b = stream.launch_builder(&f);
6109    b.arg(codes)
6110        .arg(scales)
6111        .arg(macros_dev)
6112        .arg(sel)
6113        .arg(x)
6114        .arg(y)
6115        .arg(&inf)
6116        .arg(&outf)
6117        .arg(&xs);
6118    if grp.is_some() {
6119        b.arg(&gi).arg(&ri);
6120    }
6121    unsafe {
6122        b.launch(cfg)?;
6123    }
6124    Ok(())
6125}
6126
6127/// One launch of the fused gate+up+silu sel matvec
6128/// (`qmatvec_nvfp4_modelopt_sel_gu_silu_f32`): act[slot, :ff] = silu(gate) * up over
6129/// the shared activation row. `sel`/`pack_raw` pick the addressing mode (host sel
6130/// array vs the TP2 count-gated pack blob). Bit-identical to the v3 gate + v3 up +
6131/// silu_mul chain (kernel doc).
6132#[allow(clippy::too_many_arguments)]
6133fn launch_nvfp4_sel_gu_silu(
6134    e: &Engine,
6135    gate: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
6136    up: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
6137    sel: Option<&CudaSlice<i32>>,
6138    pack_raw: u64,
6139    n_sel: usize,
6140    x: &CudaSlice<f32>,
6141    act: &mut CudaSlice<f32>,
6142    in_f: usize,
6143    ff: usize,
6144    // (slot -> token map, x token stride): ONE launch over every verify column's
6145    // routed experts (per-slot program unchanged — bit-identical). None = shared x.
6146    tok: Option<(&CudaSlice<i32>, usize)>,
6147) -> Res<()> {
6148    if in_f % 32 != 0 || ff % 4 != 0 {
6149        return Err("qmatvec_nvfp4_modelopt_sel_gu_silu_f32: geometry".into());
6150    }
6151    if act.len() < n_sel * ff {
6152        return Err("qmatvec_nvfp4_modelopt_sel_gu_silu_f32: act buffer too short".into());
6153    }
6154    if sel.is_none() == (pack_raw == 0) {
6155        return Err("qmatvec_nvfp4_modelopt_sel_gu_silu_f32: exactly one of sel/pack".into());
6156    }
6157    // Sub-warp pair groups (`selgroup`, default AUTO since 2026-09-02); `(g=32, rows=4)` reproduces the
6158    // shipped kernel's bits, pack and tok_map modes included.
6159    let grp = sel_group_resolve(sel_group_gu(), in_f, ff);
6160    let f = e.func(if grp.is_some() {
6161        "qmatvec_nvfp4_modelopt_sel_gu_silu_g_f32"
6162    } else {
6163        "qmatvec_nvfp4_modelopt_sel_gu_silu_f32"
6164    });
6165    // Warp packing reverted (see launch_nvfp4_sel_matvec): one warp per block.
6166    let grid_x = match grp {
6167        Some((g, rows)) => ff / ((32 / g) * rows),
6168        None => ff / 4,
6169    };
6170    let cfg = LaunchConfig {
6171        grid_dim: (grid_x as u32, n_sel as u32, 1),
6172        block_dim: (32, 1, 1),
6173        shared_mem_bytes: 0,
6174    };
6175    let (inf, ffi, ms) = (in_f as i32, ff as i32, n_sel as i32);
6176    let (gi, ri) = grp.map_or((0i32, 0i32), |(g, rows)| (g as i32, rows as i32));
6177    let stream = e.gpu.stream();
6178    let mut b = stream.launch_builder(&f);
6179    b.arg(gate.0)
6180        .arg(gate.1)
6181        .arg(gate.2)
6182        .arg(up.0)
6183        .arg(up.1)
6184        .arg(up.2);
6185    match sel {
6186        Some(s) => {
6187            b.arg(s);
6188        }
6189        None => {
6190            // unread in pack mode; any live device pointer keeps the arg slot filled
6191            b.arg(gate.2);
6192        }
6193    }
6194    let stream2 = e.gpu.stream();
6195    let (tok_raw, x_tstride) = match tok {
6196        Some((tm, stride)) => (tm.device_ptr(&stream2).0, stride as i64),
6197        None => (0u64, 0i64),
6198    };
6199    b.arg(&pack_raw)
6200        .arg(&ms)
6201        .arg(x)
6202        .arg(&mut *act)
6203        .arg(&inf)
6204        .arg(&ffi)
6205        .arg(&tok_raw)
6206        .arg(&x_tstride);
6207    if grp.is_some() {
6208        b.arg(&gi).arg(&ri);
6209    }
6210    unsafe {
6211        b.launch(cfg)?;
6212    }
6213    Ok(())
6214}
6215
6216/// One row of the MoE routed-union cost probe (`moeu` lane, mtp13).
6217#[derive(Debug, Clone, Copy)]
6218pub struct MoeUnionRow {
6219    /// Verify columns fed (t). 1 = the plain-decode reference shape.
6220    pub t: usize,
6221    /// (token, expert) pairs dispatched = the grid.y extent of both launches.
6222    pub slots: usize,
6223    /// DISTINCT experts among those slots — the only quantity a union gather changes.
6224    pub union_size: usize,
6225    /// Median us/launch of the fused gate+up+silu sel matvec.
6226    pub gu_us: f64,
6227    /// Median us/launch of the down sel matvec.
6228    pub down_us: f64,
6229    /// (max-min)/median over the arm's reps. Reported so a reader can see whether an arm's
6230    /// delta against another arm is inside its own noise; LAW:interleaved-ab wants every arm
6231    /// to report its spread, and at realistic union sizes this lever's delta is smaller than
6232    /// this column.
6233    pub gu_spread_rel: f64,
6234    pub down_spread_rel: f64,
6235}
6236
6237/// COST INSTRUMENT for the MoE routed-union lever (`moeu`), and the reason it exists
6238/// instead of a kernel: the union gather changes exactly ONE thing about the MoE verify
6239/// section — how many DISTINCT experts' NVFP4 bytes the chunk reads — while leaving the
6240/// per-slot arithmetic, the slot count and the launch geometry alone. So the lever can be
6241/// priced WITHOUT writing it, by running the shipped kernels at a fixed slot count and
6242/// varying only the number of distinct experts those slots name.
6243///
6244/// The three-point decomposition each sweep yields, at t verify columns and k selected:
6245///
6246/// - `slots = t*k, union = t*k` — TODAY. Every slot reads its expert's bytes; duplicates
6247///   across tokens re-read (the kernel doc says so in as many words: "the weight banks are
6248///   read once per selected slot either way — the launch count is what drops").
6249/// - `slots = t*k, union = U` — the IDEALISED union gather: same arithmetic, same slots,
6250///   only `U` experts' bytes touched. A real union-major kernel cannot beat this by much
6251///   and cannot be slower on traffic, so this row is the lever's payoff, measured.
6252/// - `slots = k, union = k` — the t=1 plain reference, for the round arithmetic.
6253///
6254/// If the middle row does not beat the first, the section's cost is not the duplicated
6255/// bytes and the lever has no surface REGARDLESS of what the routed union sizes turn out
6256/// to be — the card's 128 MiB L2 is large enough to hold a whole chunk's routed working
6257/// set at this geometry (60 slots x 1.76 MiB gate+up = 105.5 MiB), so the hardware may
6258/// already be deduplicating what the kernel re-reads.
6259///
6260/// SYNTHETIC BANKS, stated because a probe that looks like a gate is how a wrong number
6261/// gets quoted later. This loads NO checkpoint: it allocates a bank of the serving
6262/// geometry (`experts` x `ff` x `hidden` gate + up, `experts` x `hidden` x `ff` down) and
6263/// fills it with deterministic pseudo-random bytes. That is sound for a TRAFFIC and
6264/// LATENCY probe and for nothing else: the NVFP4 lane program is branch-free and
6265/// data-independent (LUT extract, fixed shfl tree), so bytes decide addresses and never
6266/// control flow. Scale bytes are held in a modest ue4m3 range so the f32 chain stays in
6267/// normal range; no output of this probe is a correctness claim and none is compared to an
6268/// oracle. Expert ids are SPREAD across the bank by a fixed stride, because a clustered
6269/// id set would make the sweep measure address locality instead of distinct-byte count.
6270///
6271/// Numbers from this probe are per-LAUNCH; the section cost is per LAYER (one gu + one
6272/// down launch each) times the model's MoE layer count.
6273pub fn moe_union_cost_probe(
6274    e: &Engine,
6275    experts: usize,
6276    hidden: usize,
6277    ff: usize,
6278    selected: usize,
6279    t: usize,
6280    reps: usize,
6281) -> Res<Vec<MoeUnionRow>> {
6282    if hidden % 32 != 0 || ff % 4 != 0 {
6283        return Err("moe_union_cost_probe: needs the gufuse geometry (hidden%32, ff%4)".into());
6284    }
6285    if selected == 0 || t == 0 || reps == 0 {
6286        return Err("moe_union_cost_probe: selected/t/reps must be non-zero".into());
6287    }
6288    // Deterministic byte fill. Codes index a 16-entry LUT so every byte is legal; scale
6289    // bytes are confined to a mid ue4m3 range so no product leaves normal f32 range.
6290    let code_byte = |i: usize| -> u8 { (i.wrapping_mul(2_654_435_761) >> 13) as u8 };
6291    let scale_byte = |i: usize| -> u8 { 0x38 | ((i.wrapping_mul(40_503) >> 7) & 0x07) as u8 };
6292    let mk = |n: usize, f: &dyn Fn(usize) -> u8| -> Res<CudaSlice<u8>> {
6293        let host: Vec<u8> = (0..n).map(f).collect();
6294        let d = e.htod_bytes(&host)?;
6295        drop(host);
6296        Ok(d)
6297    };
6298    // gate/up: [experts, ff, hidden]; down: [experts, hidden, ff]. Gate and up get
6299    // SEPARATE allocations on purpose — aliasing them would halve the distinct bytes and
6300    // silently turn the sweep into a cache-hit measurement.
6301    let gu_codes_n = experts * ff * (hidden / 2);
6302    let gu_scales_n = experts * ff * (hidden / 16);
6303    let dn_codes_n = experts * hidden * (ff / 2);
6304    let dn_scales_n = experts * hidden * (ff / 16);
6305    let gc = mk(gu_codes_n, &code_byte)?;
6306    let gs = mk(gu_scales_n, &scale_byte)?;
6307    let uc = mk(gu_codes_n, &|i| code_byte(i ^ 0x5A5A_5A5A))?;
6308    let us = mk(gu_scales_n, &|i| scale_byte(i ^ 0x3C3C_3C3C))?;
6309    let dc = mk(dn_codes_n, &|i| code_byte(i ^ 0x0F0F_0F0F))?;
6310    let ds = mk(dn_scales_n, &|i| scale_byte(i ^ 0x1111_1111))?;
6311    let gm = e.htod(&vec![1.0f32; experts])?;
6312    let um = e.htod(&vec![1.0f32; experts])?;
6313    let dm = e.htod(&vec![1.0f32; experts])?;
6314    // Activations: small normal values, one row per verify column.
6315    let mixed_h: Vec<f32> = (0..t * hidden)
6316        .map(|i| ((i.wrapping_mul(40_503) % 1000) as f32) / 4000.0 - 0.125)
6317        .collect();
6318    let mixed = e.htod(&mixed_h)?;
6319
6320    // Spread candidate expert ids over the whole bank by a fixed stride.
6321    let pool: Vec<i32> = {
6322        let stride = (experts / (t * selected).max(1)).max(1);
6323        (0..t * selected)
6324            .map(|i| ((i * stride) % experts) as i32)
6325            .collect()
6326    };
6327
6328    let mut rows: Vec<MoeUnionRow> = Vec::new();
6329    // (t, union target). `new` fresh experts per extra column: union = k + (t-1)*new.
6330    let mut cells: Vec<(usize, usize)> = vec![(1, selected)];
6331    for new in 0..=selected {
6332        cells.push((t, selected + (t - 1) * new));
6333    }
6334    // Build EVERY cell's device state first, then interleave the arms rep by rep.
6335    //
6336    // WHY THE ARMS ARE INTERLEAVED AND NOT SWEPT (LAW:interleaved-ab): the union sizes are
6337    // arms of a perf A/B, and a contiguous block per arm ordered monotonically in union size
6338    // lets any clock/thermal drift over the run masquerade as a union effect -- in this
6339    // sweep's natural order (small union first) drift would INFLATE the apparent payoff,
6340    // which is the direction that would have made a dead lever look alive. Interleaving puts
6341    // every arm at every point of the drift curve.
6342    struct Cell {
6343        t: usize,
6344        slots: usize,
6345        union_size: usize,
6346        sel: CudaSlice<i32>,
6347        tokm: CudaSlice<i32>,
6348        act: CudaSlice<f32>,
6349        partial: CudaSlice<f32>,
6350        gu: Vec<f64>,
6351        dn: Vec<f64>,
6352    }
6353    let mut built: Vec<Cell> = Vec::with_capacity(cells.len());
6354    for (cells_t, want_union) in cells {
6355        let slots = cells_t * selected;
6356        // Build the slot->expert map: column 0 takes the first k of the pool; each later
6357        // column re-uses `shared` of column 0's experts and takes `new` fresh ones. Within
6358        // a column the ids stay DISTINCT, which is what top-k routing guarantees.
6359        let new = if cells_t > 1 {
6360            (want_union - selected) / (cells_t - 1)
6361        } else {
6362            0
6363        };
6364        let shared = selected - new;
6365        let mut sel_h: Vec<i32> = Vec::with_capacity(slots);
6366        let mut tok_h: Vec<i32> = Vec::with_capacity(slots);
6367        let mut fresh = selected;
6368        for col in 0..cells_t {
6369            if col == 0 {
6370                sel_h.extend_from_slice(&pool[0..selected]);
6371            } else {
6372                sel_h.extend_from_slice(&pool[0..shared]);
6373                for _ in 0..new {
6374                    sel_h.push(pool[fresh % pool.len()]);
6375                    fresh += 1;
6376                }
6377            }
6378            for _ in 0..selected {
6379                tok_h.push(col as i32);
6380            }
6381        }
6382        let union_size = {
6383            let mut u: Vec<i32> = sel_h.clone();
6384            u.sort_unstable();
6385            u.dedup();
6386            u.len()
6387        };
6388        built.push(Cell {
6389            t: cells_t,
6390            slots,
6391            union_size,
6392            sel: e.htod_i32(&sel_h)?,
6393            tokm: e.htod_i32(&tok_h)?,
6394            act: e.zeros(slots * ff)?,
6395            partial: e.zeros(slots * hidden)?,
6396            gu: Vec::with_capacity(reps),
6397            dn: Vec::with_capacity(reps),
6398        });
6399    }
6400    // Rep 0 is a warmed throwaway for EVERY arm: the first launch of a width pays workspace
6401    // allocation and a cold instruction cache (the scan_warm lesson).
6402    for rep in 0..(reps + 1) {
6403        for c in built.iter_mut() {
6404            let tok_arg = if c.t > 1 {
6405                Some((&c.tokm, hidden))
6406            } else {
6407                None
6408            };
6409            e.stream().synchronize()?;
6410            let t0 = std::time::Instant::now();
6411            launch_nvfp4_sel_gu_silu(
6412                e,
6413                (&gc, &gs, &gm),
6414                (&uc, &us, &um),
6415                Some(&c.sel),
6416                0,
6417                c.slots,
6418                &mixed,
6419                &mut c.act,
6420                hidden,
6421                ff,
6422                tok_arg,
6423            )?;
6424            e.stream().synchronize()?;
6425            let t1 = std::time::Instant::now();
6426            launch_nvfp4_sel_matvec(
6427                e,
6428                &dc,
6429                &ds,
6430                &dm,
6431                &c.sel,
6432                &c.act,
6433                &mut c.partial,
6434                c.slots,
6435                ff,
6436                hidden,
6437                ff,
6438            )?;
6439            e.stream().synchronize()?;
6440            let t2 = std::time::Instant::now();
6441            if rep > 0 {
6442                c.gu.push(t1.duration_since(t0).as_secs_f64() * 1e6);
6443                c.dn.push(t2.duration_since(t1).as_secs_f64() * 1e6);
6444            }
6445        }
6446    }
6447    let stat = |v: &[f64]| -> (f64, f64) {
6448        let mut s = v.to_vec();
6449        s.sort_by(|a, b| a.partial_cmp(b).unwrap());
6450        let med = s[s.len() / 2];
6451        // Spread of the decision statistic, so a reader can see whether an arm's delta is
6452        // inside its own noise (the escalation rule's input).
6453        let spread = if med > 0.0 {
6454            (s[s.len() - 1] - s[0]) / med
6455        } else {
6456            0.0
6457        };
6458        (med, spread)
6459    };
6460    for c in &built {
6461        let (gu_us, gu_spread) = stat(&c.gu);
6462        let (down_us, down_spread) = stat(&c.dn);
6463        rows.push(MoeUnionRow {
6464            t: c.t,
6465            slots: c.slots,
6466            union_size: c.union_size,
6467            gu_us,
6468            down_us,
6469            gu_spread_rel: gu_spread,
6470            down_spread_rel: down_spread,
6471        });
6472    }
6473    Ok(rows)
6474}
6475
6476/// One row of the sel-kernel SHAPE cost probe (`downsel` lane, mtp14).
6477#[derive(Debug, Clone)]
6478pub struct SelShapeRow {
6479    /// Verify columns fed (t). 1 = the plain-decode shape.
6480    pub t: usize,
6481    /// (token, expert) slots = grid.y of both launches.
6482    pub slots: usize,
6483    /// The `selgroup` spec this arm ran (`off` = the shipped v3 / gufuse kernels).
6484    pub arm: String,
6485    /// Resolved (g, rows) per family, and the grid.x each launch used — the whole point of
6486    /// the table is that a shape trades lane occupancy against warp count, so both have to
6487    /// be readable next to the time.
6488    pub gu_shape: String,
6489    pub dn_shape: String,
6490    pub gu_grid_x: usize,
6491    pub dn_grid_x: usize,
6492    pub gu_us: f64,
6493    pub down_us: f64,
6494    pub gu_spread_rel: f64,
6495    pub down_spread_rel: f64,
6496}
6497
6498/// Cost probe for the sel matvecs' SUB-WARP pair-group shapes (`downsel` lane, mtp14),
6499/// on synthetic banks of the serving geometry with NO checkpoint (~1.3 GiB, ~30 s) — so it
6500/// interleaves between any other lane's cells the way the `moeu` probe does.
6501///
6502/// WHAT IT MEASURES. `moe_union_probe` established that this section is per-slot-work bound
6503/// (KNEE:q4e-sel-slots-not-bytes). Per-slot work is what an idle lane wastes, and at this
6504/// artifact's geometry the pair loop leaves 37.5% of the down launch's lanes and 16.7% of
6505/// the gate+up launch's lane-slots empty. This probe runs the SAME slots, the SAME distinct
6506/// experts and the SAME banks through each candidate lane partition, so the only thing
6507/// varying between arms is the shape.
6508///
6509/// TWO CONTROLS BUILT IN, because a shape table without them is unreadable:
6510///
6511/// 1. **`off` vs `dn:32:4+gu:32:4`.** The second arm is the sub-warp kernel at the shape
6512///    where it degenerates to the shipped program — bit-identical output (gated by
6513///    `gate_nvfp4_sel_group`). It went in as a noise floor (LAW:ab-arm-identity applied to a
6514///    perf table: an arm running the same program must measure the same) and it EARNED its
6515///    place by not being one — it reproducibly measures a few percent faster than `off`,
6516///    because the source restructure changes nvcc's scheduling for identical bits. So
6517///    `arm / off` mixes two effects and only `arm / control` is the shape's. Anyone reading
6518///    this table for a shape claim reads the control-relative column.
6519/// 2. **Per-arm spread**, reported per arm, never averaged away.
6520///
6521/// Arms are interleaved REP BY REP (LAW:interleaved-ab / TRAP:monotone-sweep-inflates-the-
6522/// lever): a shape ladder run as contiguous blocks would let clock/thermal drift over the
6523/// run read as a shape effect, and the natural order (baseline first) inflates the payoff.
6524/// Rep 0 of every arm is a warmed throwaway (the `scan_warm` lesson).
6525///
6526/// TIMING ARM: hold `flock -x` around the WHOLE invocation, and never quote a row measured
6527/// on the rig (LAW:rig-gpu-exactness-only — the rig is for the exactness arms above).
6528#[allow(clippy::too_many_arguments)]
6529pub fn sel_shape_cost_probe(
6530    e: &Engine,
6531    experts: usize,
6532    hidden: usize,
6533    ff: usize,
6534    selected: usize,
6535    t: usize,
6536    reps: usize,
6537    arms: &[String],
6538) -> Res<Vec<SelShapeRow>> {
6539    if hidden % 32 != 0 || ff % 4 != 0 {
6540        return Err("sel_shape_cost_probe: needs the gufuse geometry (hidden%32, ff%4)".into());
6541    }
6542    if selected == 0 || t == 0 || reps == 0 || arms.is_empty() {
6543        return Err("sel_shape_cost_probe: selected/t/reps/arms must be non-empty".into());
6544    }
6545    let saved = sel_group_spec();
6546    let out = sel_shape_cost_probe_inner(e, experts, hidden, ff, selected, t, reps, arms);
6547    set_sel_group(&saved);
6548    out
6549}
6550
6551#[allow(clippy::too_many_arguments)]
6552fn sel_shape_cost_probe_inner(
6553    e: &Engine,
6554    experts: usize,
6555    hidden: usize,
6556    ff: usize,
6557    selected: usize,
6558    t: usize,
6559    reps: usize,
6560    arms: &[String],
6561) -> Res<Vec<SelShapeRow>> {
6562    // Bank fill and the honesty notes are `moe_union_cost_probe`'s, deliberately: codes
6563    // index a 16-entry LUT so every byte is legal, scale bytes sit in a mid ue4m3 range so
6564    // no product leaves normal f32 range, and gate/up get SEPARATE allocations (aliasing
6565    // them would halve the distinct bytes). No output is compared to an oracle here — that
6566    // is `gate_nvfp4_sel_group`'s job; this is a latency arm only.
6567    let code_byte = |i: usize| -> u8 { (i.wrapping_mul(2_654_435_761) >> 13) as u8 };
6568    let scale_byte = |i: usize| -> u8 { 0x38 | ((i.wrapping_mul(40_503) >> 7) & 0x07) as u8 };
6569    let mk = |n: usize, f: &dyn Fn(usize) -> u8| -> Res<CudaSlice<u8>> {
6570        let host: Vec<u8> = (0..n).map(f).collect();
6571        let d = e.htod_bytes(&host)?;
6572        drop(host);
6573        Ok(d)
6574    };
6575    let gc = mk(experts * ff * (hidden / 2), &code_byte)?;
6576    let gs = mk(experts * ff * (hidden / 16), &scale_byte)?;
6577    let uc = mk(experts * ff * (hidden / 2), &|i| code_byte(i ^ 0x5A5A_5A5A))?;
6578    let us = mk(experts * ff * (hidden / 16), &|i| {
6579        scale_byte(i ^ 0x3C3C_3C3C)
6580    })?;
6581    let dc = mk(experts * hidden * (ff / 2), &|i| code_byte(i ^ 0x0F0F_0F0F))?;
6582    let ds = mk(experts * hidden * (ff / 16), &|i| {
6583        scale_byte(i ^ 0x1111_1111)
6584    })?;
6585    let gm = e.htod(&vec![1.0f32; experts])?;
6586    let um = e.htod(&vec![1.0f32; experts])?;
6587    let dm = e.htod(&vec![1.0f32; experts])?;
6588    let mixed_h: Vec<f32> = (0..t * hidden)
6589        .map(|i| ((i.wrapping_mul(40_503) % 1000) as f32) / 4000.0 - 0.125)
6590        .collect();
6591    let mixed = e.htod(&mixed_h)?;
6592
6593    // ONE routing shape for every arm: `slots` distinct experts spread across the bank by a
6594    // fixed stride. Distinct, because a shape change must not be read through a cache-hit
6595    // difference — the union axis is `moe_union_probe`'s and it is already priced dead.
6596    let slots = t * selected;
6597    let stride = (experts / slots.max(1)).max(1);
6598    let sel_h: Vec<i32> = (0..slots)
6599        .map(|i| ((i * stride) % experts) as i32)
6600        .collect();
6601    let tok_h: Vec<i32> = (0..slots).map(|i| (i / selected) as i32).collect();
6602    let sel = e.htod_i32(&sel_h)?;
6603    let tokm = e.htod_i32(&tok_h)?;
6604    let mut act = e.zeros(slots * ff)?;
6605    let mut partial = e.zeros(slots * hidden)?;
6606
6607    struct Arm {
6608        spec: String,
6609        gu_shape: String,
6610        dn_shape: String,
6611        gu_grid_x: usize,
6612        dn_grid_x: usize,
6613        gu: Vec<f64>,
6614        dn: Vec<f64>,
6615    }
6616    let describe = |code: u32, in_f: usize, out_f: usize| -> (String, usize) {
6617        match sel_group_resolve(code, in_f, out_f) {
6618            Some((g, rows)) => {
6619                let rpw = (32 / g) * rows;
6620                (format!("g{g}r{rows}/rpw{rpw}"), out_f / rpw)
6621            }
6622            None => ("shipped".to_string(), out_f / 4),
6623        }
6624    };
6625    let mut built: Vec<Arm> = Vec::with_capacity(arms.len());
6626    for spec in arms {
6627        if !set_sel_group(spec) {
6628            return Err(format!("sel_shape_cost_probe: bad arm spec {spec:?}").into());
6629        }
6630        let (gu_shape, gu_grid_x) = describe(sel_group_gu(), hidden, ff);
6631        let (dn_shape, dn_grid_x) = describe(sel_group_dn(), ff, hidden);
6632        built.push(Arm {
6633            spec: spec.clone(),
6634            gu_shape,
6635            dn_shape,
6636            gu_grid_x,
6637            dn_grid_x,
6638            gu: Vec::with_capacity(reps),
6639            dn: Vec::with_capacity(reps),
6640        });
6641    }
6642    let tok_arg = if t > 1 { Some((&tokm, hidden)) } else { None };
6643    for rep in 0..(reps + 1) {
6644        for a in built.iter_mut() {
6645            // Arm identity is re-asserted every rep, not set once outside the loop: the
6646            // interleave is the whole point, and a seam left over from the previous arm
6647            // would silently measure it twice.
6648            set_sel_group(&a.spec);
6649            e.stream().synchronize()?;
6650            let t0 = std::time::Instant::now();
6651            launch_nvfp4_sel_gu_silu(
6652                e,
6653                (&gc, &gs, &gm),
6654                (&uc, &us, &um),
6655                Some(&sel),
6656                0,
6657                slots,
6658                &mixed,
6659                &mut act,
6660                hidden,
6661                ff,
6662                tok_arg,
6663            )?;
6664            e.stream().synchronize()?;
6665            let t1 = std::time::Instant::now();
6666            launch_nvfp4_sel_matvec(
6667                e,
6668                &dc,
6669                &ds,
6670                &dm,
6671                &sel,
6672                &act,
6673                &mut partial,
6674                slots,
6675                ff,
6676                hidden,
6677                ff,
6678            )?;
6679            e.stream().synchronize()?;
6680            let t2 = std::time::Instant::now();
6681            if rep > 0 {
6682                a.gu.push(t1.duration_since(t0).as_secs_f64() * 1e6);
6683                a.dn.push(t2.duration_since(t1).as_secs_f64() * 1e6);
6684            }
6685        }
6686    }
6687    let stat = |v: &[f64]| -> (f64, f64) {
6688        let mut s = v.to_vec();
6689        s.sort_by(|a, b| a.partial_cmp(b).unwrap());
6690        let med = s[s.len() / 2];
6691        let spread = if med > 0.0 {
6692            (s[s.len() - 1] - s[0]) / med
6693        } else {
6694            0.0
6695        };
6696        (med, spread)
6697    };
6698    Ok(built
6699        .iter()
6700        .map(|a| {
6701            let (gu_us, gu_spread_rel) = stat(&a.gu);
6702            let (down_us, down_spread_rel) = stat(&a.dn);
6703            SelShapeRow {
6704                t,
6705                slots,
6706                arm: a.spec.clone(),
6707                gu_shape: a.gu_shape.clone(),
6708                dn_shape: a.dn_shape.clone(),
6709                gu_grid_x: a.gu_grid_x,
6710                dn_grid_x: a.dn_grid_x,
6711                gu_us,
6712                down_us,
6713                gu_spread_rel,
6714                down_spread_rel,
6715            }
6716        })
6717        .collect())
6718}
6719
6720/// Sequential slot-combine over a WINDOW of a taller partial slab (mtp-spec verify):
6721/// rows [x_row0, x_row0+n_rows) x weights [w_off..] into y row `y_row` — the
6722/// axpy_rows_seq_f32 chain VERBATIM over that window (per-token combine order equals
6723/// the decode combine).
6724#[allow(clippy::too_many_arguments)]
6725fn launch_axpy_rows_seq_at(
6726    e: &Engine,
6727    x: &CudaSlice<f32>,
6728    x_row0: usize,
6729    w: &CudaSlice<f32>,
6730    w_off: usize,
6731    y: &mut CudaSlice<f32>,
6732    y_row: usize,
6733    width: usize,
6734    n_rows: usize,
6735) -> Res<()> {
6736    if x.len() < (x_row0 + n_rows) * width
6737        || w.len() < w_off + n_rows
6738        || y.len() < (y_row + 1) * width
6739    {
6740        return Err("axpy_rows_seq_f32: window out of range".into());
6741    }
6742    let xv = x.slice(x_row0 * width..(x_row0 + n_rows) * width);
6743    let wv = w.slice(w_off..w_off + n_rows);
6744    let mut yv = y.slice_mut(y_row * width..(y_row + 1) * width);
6745    let f = e.func("axpy_rows_seq_f32");
6746    let cfg = LaunchConfig::for_num_elems(width as u32);
6747    let (wi, nr) = (width as i32, n_rows as i32);
6748    let stream = e.gpu.stream();
6749    let mut b = stream.launch_builder(&f);
6750    b.arg(&xv).arg(&wv).arg(&mut yv).arg(&wi).arg(&nr);
6751    unsafe {
6752        b.launch(cfg)?;
6753    }
6754    Ok(())
6755}
6756
6757/// Kernel-vs-host oracle for the grouped decode kernel (`qmatvec_nvfp4_modelopt_sel_f32`).
6758/// The tiny four-arm gate cannot reach that kernel (the tiny down projection is BF16 by
6759/// geometry, so the grouped path never engages there); this synthetic arm gates the
6760/// kernel directly against the host decoder chain (`dsv4::dequant_nvfp4_expert` + host
6761/// f32 matvec): deterministic codes/scales including planted NaN scale bytes (modelopt
6762/// NaN -> 0.0) , mixed pow2/non-pow2 macros (the real mint's class), duplicate slots in
6763/// `sel`, and BOTH x_stride modes (shared gate/up row, per-slot down rows). Products are
6764/// exact; only summation order differs from the host chain — tolerance 1e-5 rel.
6765pub fn gate_nvfp4_sel_matvec(e: &Engine) -> Res<String> {
6766    let mut lcg = 0x2545_f491_u64;
6767    let mut next_u32 = move || -> u32 {
6768        lcg = lcg
6769            .wrapping_mul(6364136223846793005)
6770            .wrapping_add(1442695040888963407);
6771        (lcg >> 33) as u32
6772    };
6773    let macros = [
6774        1.0f32,
6775        0.5,
6776        5.9945243e-5, // the measured non-pow2 mint class
6777        2.0,
6778        0.25,
6779        3.7e-3,
6780        1.0,
6781        8.0,
6782    ];
6783    let sel_host: Vec<i32> = vec![3, 5, 3, 0]; // duplicate slot on purpose
6784    let n_sel = sel_host.len();
6785    let mut worst = (0.0f32, 0.0f32); // (max_abs, max_rel)
6786    // Shapes + per-mode seam forcing pick the dispatched kernel: v3 modes force the
6787    // 4-row kernel (its guard is out_f % 4 == 0, which the v2 shapes also satisfy, so
6788    // the seam is toggled per mode and restored to the shipped default after); v2
6789    // shapes take the 2-row kernel with v3 off; in_f 48 and the odd out_f take the v1
6790    // fallback — all three kernels and every geometry guard are gated in one pass.
6791    for (mode, out_f, in_f) in [
6792        ("gate_up_v1", 16usize, 48usize),
6793        ("down_v1", 32, 16),
6794        ("gate_up_v1_oddrows", 7, 64),
6795        ("gate_up_v2", 16, 64),
6796        ("down_v2", 32, 32),
6797        ("gate_up_v3", 16, 64),
6798        ("down_v3", 32, 32),
6799        ("gate_up_v3_v2rows", 6, 64), // out_f % 4 != 0 falls v3 -> v2 under the v3 seam
6800    ] {
6801        set_sel_v3(mode.contains("v3"));
6802        let n_expert = macros.len();
6803        let mut codes = vec![0u8; n_expert * out_f * in_f / 2];
6804        for byte in &mut codes {
6805            *byte = next_u32() as u8;
6806        }
6807        let mut scales = vec![0u8; n_expert * out_f * in_f / 16];
6808        for byte in &mut scales {
6809            *byte = (next_u32() as u8) & 0xBF; // mag < 0x40 keeps magnitudes tame
6810        }
6811        scales[0] = 0x7F; // NaN code -> 0.0 (modelopt convention), pinned here
6812        scales[3] = 0xFF; // signed NaN code -> 0.0 too
6813        let x_stride = if mode.starts_with("down") { in_f } else { 0 };
6814        let x_rows = if x_stride == 0 { 1 } else { n_sel };
6815        let x_host: Vec<f32> = (0..x_rows * in_f)
6816            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
6817            .collect();
6818        let codes_dev = e.htod_bytes(&codes)?;
6819        let scales_dev = e.htod_bytes(&scales)?;
6820        let macros_dev = e.htod(&macros)?;
6821        let sel_dev = e.htod_i32(&sel_host)?;
6822        let x_dev = e.htod(&x_host)?;
6823        let mut y_dev = e.uninit(n_sel * out_f)?;
6824        launch_nvfp4_sel_matvec(
6825            e,
6826            &codes_dev,
6827            &scales_dev,
6828            &macros_dev,
6829            &sel_dev,
6830            &x_dev,
6831            &mut y_dev,
6832            n_sel,
6833            in_f,
6834            out_f,
6835            x_stride,
6836        )?;
6837        let y = e.dtoh(&y_dev)?;
6838        let wbytes = out_f * in_f / 2;
6839        let sbytes = out_f * in_f / 16;
6840        for (slot, &expert) in sel_host.iter().enumerate() {
6841            let expert = expert as usize;
6842            let w = memra_gguf::dsv4::dequant_nvfp4_expert(
6843                &codes[expert * wbytes..(expert + 1) * wbytes],
6844                &scales[expert * sbytes..(expert + 1) * sbytes],
6845                macros[expert],
6846                out_f,
6847                in_f,
6848            );
6849            let xrow = &x_host[slot * x_stride..slot * x_stride + in_f];
6850            for o in 0..out_f {
6851                let mut want = 0.0f32;
6852                for i in 0..in_f {
6853                    want += w[o * in_f + i] * xrow[i];
6854                }
6855                let got = y[slot * out_f + o];
6856                let abs = (want - got).abs();
6857                let rel = abs / want.abs().max(1.0);
6858                if abs > worst.0 {
6859                    worst.0 = abs;
6860                }
6861                if rel > worst.1 {
6862                    worst.1 = rel;
6863                }
6864                if rel > 1e-5 {
6865                    return Err(format!(
6866                        "nvfp4-sel-matvec oracle: {mode} slot {slot} row {o}: want {want} \
6867                         got {got} (rel {rel:.3e})"
6868                    )
6869                    .into());
6870                }
6871            }
6872        }
6873    }
6874    set_sel_v3(SEL_V3_DEFAULT);
6875
6876    // gufuse mode: the fused gate+up+silu kernel must be BIT-IDENTICAL to the
6877    // v3 gate launch + v3 up launch + silu_mul chain (same per-row arithmetic, same
6878    // epilogue element form — kernel doc). Byte-compare, plus the count-gated pack
6879    // twin's dead-slot sentinel.
6880    {
6881        set_sel_v3(true);
6882        let (ff, in_f) = (16usize, 64usize);
6883        let n_expert = macros.len();
6884        let mut mk = |seed: u8| -> (Vec<u8>, Vec<u8>) {
6885            let mut codes = vec![0u8; n_expert * ff * in_f / 2];
6886            for byte in &mut codes {
6887                *byte = (next_u32() as u8) ^ seed;
6888            }
6889            let mut scales = vec![0u8; n_expert * ff * in_f / 16];
6890            for byte in &mut scales {
6891                *byte = (next_u32() as u8) & 0xBF;
6892            }
6893            scales[1] = 0x7F; // NaN scale byte -> 0.0
6894            (codes, scales)
6895        };
6896        let (g_codes, g_scales) = mk(0x00);
6897        let (u_codes, u_scales) = mk(0x5A);
6898        let gmac: Vec<f32> = macros.to_vec();
6899        let umac: Vec<f32> = macros.iter().map(|m| m * 0.5).collect();
6900        let x_host: Vec<f32> = (0..in_f)
6901            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
6902            .collect();
6903        let gc = e.htod_bytes(&g_codes)?;
6904        let gs = e.htod_bytes(&g_scales)?;
6905        let gm = e.htod(&gmac)?;
6906        let uc = e.htod_bytes(&u_codes)?;
6907        let us = e.htod_bytes(&u_scales)?;
6908        let um = e.htod(&umac)?;
6909        let sel_dev = e.htod_i32(&sel_host)?;
6910        let x_dev = e.htod(&x_host)?;
6911        // Chain arm: v3 gate + v3 up + silu_mul.
6912        let mut yg = e.uninit(n_sel * ff)?;
6913        let mut yu = e.uninit(n_sel * ff)?;
6914        launch_nvfp4_sel_matvec(
6915            e, &gc, &gs, &gm, &sel_dev, &x_dev, &mut yg, n_sel, in_f, ff, 0,
6916        )?;
6917        launch_nvfp4_sel_matvec(
6918            e, &uc, &us, &um, &sel_dev, &x_dev, &mut yu, n_sel, in_f, ff, 0,
6919        )?;
6920        let mut act_chain = e.zeros(n_sel * ff)?;
6921        e.silu_mul(&yg, &yu, &mut act_chain, n_sel * ff)?;
6922        // Fused arm.
6923        let mut act_fused = e.zeros(n_sel * ff)?;
6924        launch_nvfp4_sel_gu_silu(
6925            e,
6926            (&gc, &gs, &gm),
6927            (&uc, &us, &um),
6928            Some(&sel_dev),
6929            0,
6930            n_sel,
6931            &x_dev,
6932            &mut act_fused,
6933            in_f,
6934            ff,
6935            None,
6936        )?;
6937        let a = e.dtoh(&act_chain)?;
6938        let b = e.dtoh(&act_fused)?;
6939        for (i, (&x1, &x2)) in a.iter().zip(&b).enumerate() {
6940            if x1.to_bits() != x2.to_bits() {
6941                return Err(format!(
6942                    "nvfp4-sel-matvec oracle: gufuse idx {i} not bit-identical \
6943                     (chain {x1} fused {x2})"
6944                )
6945                .into());
6946            }
6947        }
6948        // Pack twin: live count 2 of 4 — live slots bit-match, dead slots keep the
6949        // sentinel.
6950        let pack_bytes = tp2_pack_bytes(&sel_host[..2], &[0.5, 0.25], n_sel);
6951        let pack = e.htod_bytes(&pack_bytes)?;
6952        let pack_raw = {
6953            let stream = e.gpu.stream();
6954            pack.device_ptr(&stream).0
6955        };
6956        let sentinel = vec![-777.0f32; n_sel * ff];
6957        let mut act_pack = e.htod(&sentinel)?;
6958        launch_nvfp4_sel_gu_silu(
6959            e,
6960            (&gc, &gs, &gm),
6961            (&uc, &us, &um),
6962            None,
6963            pack_raw,
6964            n_sel,
6965            &x_dev,
6966            &mut act_pack,
6967            in_f,
6968            ff,
6969            None,
6970        )?;
6971        let c = e.dtoh(&act_pack)?;
6972        for slot in 0..n_sel {
6973            for o in 0..ff {
6974                let got = c[slot * ff + o];
6975                if slot < 2 {
6976                    if got.to_bits() != a[slot * ff + o].to_bits() {
6977                        return Err(format!(
6978                            "nvfp4-sel-matvec oracle: gufuse pack slot {slot} o {o} \
6979                             not bit-identical"
6980                        )
6981                        .into());
6982                    }
6983                } else if got != -777.0 {
6984                    return Err(format!(
6985                        "nvfp4-sel-matvec oracle: gufuse pack dead slot {slot} written"
6986                    )
6987                    .into());
6988                }
6989            }
6990        }
6991        // tok_map twin (mtp-spec verify merge): TWO tokens' slots in ONE launch via the
6992        // slot->token map must bit-match per-token launches over each token's x row.
6993        {
6994            let t2 = 2usize;
6995            let x2_host: Vec<f32> = (0..t2 * in_f)
6996                .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
6997                .collect();
6998            let x2 = e.htod(&x2_host)?;
6999            let tok_host: Vec<i32> = (0..n_sel).map(|s| (s % t2) as i32).collect();
7000            let tokm = e.htod_i32(&tok_host)?;
7001            let mut act_map = e.zeros(n_sel * ff)?;
7002            launch_nvfp4_sel_gu_silu(
7003                e,
7004                (&gc, &gs, &gm),
7005                (&uc, &us, &um),
7006                Some(&sel_dev),
7007                0,
7008                n_sel,
7009                &x2,
7010                &mut act_map,
7011                in_f,
7012                ff,
7013                Some((&tokm, in_f)),
7014            )?;
7015            let got = e.dtoh(&act_map)?;
7016            for tok in 0..t2 {
7017                let slots: Vec<usize> = (0..n_sel).filter(|s| s % t2 == tok).collect();
7018                let sel_tok: Vec<i32> = slots.iter().map(|&s| sel_host[s]).collect();
7019                let sel_tok_dev = e.htod_i32(&sel_tok)?;
7020                let xrow = e.htod(&x2_host[tok * in_f..(tok + 1) * in_f])?;
7021                let mut act_tok = e.zeros(sel_tok.len() * ff)?;
7022                launch_nvfp4_sel_gu_silu(
7023                    e,
7024                    (&gc, &gs, &gm),
7025                    (&uc, &us, &um),
7026                    Some(&sel_tok_dev),
7027                    0,
7028                    sel_tok.len(),
7029                    &xrow,
7030                    &mut act_tok,
7031                    in_f,
7032                    ff,
7033                    None,
7034                )?;
7035                let want = e.dtoh(&act_tok)?;
7036                for (local, &slot) in slots.iter().enumerate() {
7037                    for o in 0..ff {
7038                        let a = got[slot * ff + o];
7039                        let b = want[local * ff + o];
7040                        if a.to_bits() != b.to_bits() {
7041                            return Err(format!(
7042                                "nvfp4-sel-matvec oracle: gufuse tok_map slot {slot} o {o} \
7043                                 not bit-identical (map {a} per-token {b})"
7044                            )
7045                            .into());
7046                        }
7047                    }
7048                }
7049            }
7050        }
7051        set_sel_v3(SEL_V3_DEFAULT);
7052    }
7053    Ok(format!(
7054        "nvfp4-sel-matvec kernel oracle: worst abs {:.3e} rel {:.3e} over gate_up+down \
7055         v1/v2/v3 modes, NaN scales + non-pow2 macros + duplicate slots; gufuse \
7056         BIT-IDENTICAL to the v3+silu chain incl. the count-gated pack twin + the \
7057         tok_map verify merge",
7058        worst.0, worst.1
7059    ))
7060}
7061
7062/// Kernel oracle for the SUB-WARP pair-group sel matvecs (`selgroup`, downsel lane mtp14),
7063/// at the artifact's REAL MoE geometry — which is the whole point of the arm: the defect
7064/// being fixed is a property of `pairs = in_f/32` against a 32-lane loop, so it only exists
7065/// at `in_f = 640` (pairs 20, lanes 20-31 idle) and `in_f = 2560` (pairs 80, 3-vs-2 tail).
7066/// A tiny fixture has `pairs` 1 or 2 and cannot reach either shape; both are gated here.
7067///
7068/// Three claims, in ascending strength:
7069///
7070/// 1. **`(g=32, rows=4)` is BIT-IDENTICAL to the shipped v3 / gufuse kernels.** The
7071///    sub-warp form degenerates to their exact program at that shape (same per-lane pair
7072///    set, same 5-step tree, same write lane), so this is a byte compare, not a tolerance.
7073///    It is what makes the seam a rollback rather than a rewrite, and it is the arm that
7074///    would catch a per-row expression drift introduced while restructuring.
7075/// 2. **Every other shape is within the sel oracle's accumulation-class tolerance
7076///    (1e-5 rel) of the HOST DECODER CHAIN** (`dsv4::dequant_nvfp4_expert` + host f32
7077///    matvec), the same reference and the same bound `gate_nvfp4_sel_matvec` holds v1/v2/v3
7078///    to. Those shapes DO change the order the pairs are summed in — a lane chains several
7079///    pairs and the tree is shallower — so bit-identity is not the right claim and asserting
7080///    it would be a lie that happened to pass at some shapes.
7081/// 3. **The fusion property survives the reshape:** `gu_g` is bit-identical to
7082///    `sel_g` gate + `sel_g` up + `silu_mul` at the SAME `(g, rows)`, with the count-gated
7083///    pack twin and the slot->token verify merge included.
7084///
7085/// Same hostile inputs as the shipped arm: planted modelopt NaN scale bytes (0x7F/0xFF ->
7086/// 0.0), mixed pow2 / non-pow2 (the real mint's amax class) macros, a DUPLICATE expert in
7087/// `sel`, and both `x_stride` modes (shared gate/up row, per-slot down rows).
7088pub fn gate_nvfp4_sel_group(e: &Engine) -> Res<String> {
7089    let saved = sel_group_spec();
7090    let out = gate_nvfp4_sel_group_inner(e);
7091    // Restore on BOTH paths: a gate arm that leaks a seam leaves every later arm measuring
7092    // a shape nobody asked for (the seam_state save/restore lesson).
7093    set_sel_group(&saved);
7094    set_sel_v3(SEL_V3_DEFAULT);
7095    out
7096}
7097
7098fn gate_nvfp4_sel_group_inner(e: &Engine) -> Res<String> {
7099    let mut lcg = 0x2545_f491_u64; // the shipped sel arm's seed, deliberately
7100    let mut next_u32 = move || -> u32 {
7101        lcg = lcg
7102            .wrapping_mul(6364136223846793005)
7103            .wrapping_add(1442695040888963407);
7104        (lcg >> 33) as u32
7105    };
7106    let macros = [
7107        1.0f32,
7108        0.5,
7109        5.9945243e-5, // the measured non-pow2 mint class
7110        2.0,
7111        0.25,
7112        3.7e-3,
7113        1.0,
7114        8.0,
7115    ];
7116    let n_expert = macros.len();
7117    let sel_host: Vec<i32> = vec![3, 5, 3, 0]; // duplicate slot on purpose
7118    let n_sel = sel_host.len();
7119    let mut worst = (0.0f32, 0.0f32);
7120    let mut shapes_checked = 0usize;
7121    let mut bits_checked = 0usize;
7122    let mut calib: Vec<String> = Vec::new();
7123
7124    // ---- single-bank family (down projection AND the unfused gate/up shape) -------------
7125    // (label, out_f, in_f, per-slot x rows). The two REAL rows are the launches the verify
7126    // chunk actually dispatches: down out_f=hidden 2560 / in_f=ff 640, and the gate/up
7127    // shape out_f=ff 640 / in_f=hidden 2560 (SEMANTICS.md "MoE (L510-527)": experts fused
7128    // gate_up [512,1280,2560], down [512,2560,640]).
7129    for (geom, out_f, in_f, per_slot_x) in [
7130        ("down_real", 2560usize, 640usize, true),
7131        ("gateup_real", 640, 2560, false),
7132        ("down_tiny", 32, 32, true),
7133        ("gateup_tiny", 16, 64, false),
7134    ] {
7135        let mut codes = vec![0u8; n_expert * out_f * in_f / 2];
7136        for byte in &mut codes {
7137            *byte = next_u32() as u8;
7138        }
7139        let mut scales = vec![0u8; n_expert * out_f * in_f / 16];
7140        for byte in &mut scales {
7141            *byte = (next_u32() as u8) & 0xBF; // mag < 0x40 keeps magnitudes tame
7142        }
7143        scales[0] = 0x7F; // modelopt NaN code -> 0.0
7144        scales[3] = 0xFF; // signed NaN code -> 0.0 too
7145        let x_stride = if per_slot_x { in_f } else { 0 };
7146        let x_rows = if per_slot_x { n_sel } else { 1 };
7147        let x_host: Vec<f32> = (0..x_rows * in_f)
7148            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7149            .collect();
7150        let codes_dev = e.htod_bytes(&codes)?;
7151        let scales_dev = e.htod_bytes(&scales)?;
7152        let macros_dev = e.htod(&macros)?;
7153        let sel_dev = e.htod_i32(&sel_host)?;
7154        let x_dev = e.htod(&x_host)?;
7155        let run = |spec: &str| -> Res<Vec<f32>> {
7156            set_sel_group(spec);
7157            let mut y = e.uninit(n_sel * out_f)?;
7158            launch_nvfp4_sel_matvec(
7159                e,
7160                &codes_dev,
7161                &scales_dev,
7162                &macros_dev,
7163                &sel_dev,
7164                &x_dev,
7165                &mut y,
7166                n_sel,
7167                in_f,
7168                out_f,
7169                x_stride,
7170            )?;
7171            e.dtoh(&y)
7172        };
7173        // The shipped arm (seam OFF) and the host reference, built once per geometry. The
7174        // shipped arm is not just a bit-identity control: its OWN deviation from the host
7175        // chain is this geometry's calibration (see `class_tol` below). PIN sel_v3 rather
7176        // than inheriting ambient seam state (revuto, PR #27): under `selv3=0` in
7177        // MEMRA_Q4E_SEAMS the "shipped" control would silently become the v2 kernel and
7178        // the calibration would be measured against the wrong program — mirror the fused
7179        // family, which pins its control the same way.
7180        set_sel_v3(true);
7181        let shipped = run("off")?;
7182        let wbytes = out_f * in_f / 2;
7183        let sbytes = out_f * in_f / 16;
7184        let mut want = vec![0.0f32; n_sel * out_f];
7185        for (slot, &expert) in sel_host.iter().enumerate() {
7186            let expert = expert as usize;
7187            let w = memra_gguf::dsv4::dequant_nvfp4_expert(
7188                &codes[expert * wbytes..(expert + 1) * wbytes],
7189                &scales[expert * sbytes..(expert + 1) * sbytes],
7190                macros[expert],
7191                out_f,
7192                in_f,
7193            );
7194            let xrow = &x_host[slot * x_stride..slot * x_stride + in_f];
7195            for o in 0..out_f {
7196                let mut acc = 0.0f32;
7197                for i in 0..in_f {
7198                    acc += w[o * in_f + i] * xrow[i];
7199                }
7200                want[slot * out_f + o] = acc;
7201            }
7202        }
7203        // The SHIPPED kernel's own worst deviation from the host chain, at THIS width. This
7204        // is the arm's calibration, and measuring it is load-bearing rather than tidy:
7205        // `gate_nvfp4_sel_matvec`'s 1e-5 rel bound was set on TINY shapes (in_f 16-64) and
7206        // does NOT transfer to the real MoE widths — a length-`in_f` f32 reduction has an
7207        // order-dependent error that grows with the sum, and at in_f=640 the SHIPPED v3
7208        // kernel already measures ~2.7e-5 against the exact host chain. Holding a reshaped
7209        // twin to 1e-5 there would fail it for being a different (equally valid) summation
7210        // order of a sum the shipped kernel cannot hold to 1e-5 either.
7211        let ship_vs_host = want
7212            .iter()
7213            .zip(&shipped)
7214            .map(|(&w, &s)| (w - s).abs() / w.abs().max(1.0))
7215            .fold(0.0f32, f32::max);
7216        // Same-accumulation-class bound: no worse than 4x what the kernel we ship already
7217        // deviates by, with a floor so the tiny geometries (where the shipped kernel can be
7218        // near-exact) do not set an unreachable bar.
7219        let class_tol = (4.0 * ship_vs_host).max(1e-5);
7220        calib.push(format!(
7221            "{geom} ship_vs_host={ship_vs_host:.3e} tol={class_tol:.3e}"
7222        ));
7223        // Every shape the ladder can pin at this geometry, plus AUTO and the control.
7224        // `dn:1:1` is the extreme: one output row per LANE, no shfl reduce at all — kept in
7225        // the oracle because it is the arm most likely to expose an indexing error, even
7226        // though its coalescing makes it a poor perf candidate.
7227        for spec in [
7228            "dn:32:4", "dn:auto", "dn:16:4", "dn:16:2", "dn:8:4", "dn:8:2", "dn:8:1", "dn:4:4",
7229            "dn:4:2", "dn:4:1", "dn:2:4", "dn:2:2", "dn:2:1", "dn:1:1",
7230        ] {
7231            let Some((g, rows)) = sel_group_resolve(
7232                match spec {
7233                    "dn:auto" => SEL_GROUP_AUTO,
7234                    _ => {
7235                        let (gs, rs) = spec.trim_start_matches("dn:").split_once(':').unwrap();
7236                        (gs.parse::<u32>().unwrap() << 8) | rs.parse::<u32>().unwrap()
7237                    }
7238                },
7239                in_f,
7240                out_f,
7241            ) else {
7242                continue; // geometry cannot tile this shape — the launcher takes v3
7243            };
7244            let got = run(spec)?;
7245            shapes_checked += 1;
7246            if (g, rows) == (32, 4) {
7247                // Claim 1: the degenerate shape IS v3.
7248                for (i, (&a, &b)) in shipped.iter().zip(&got).enumerate() {
7249                    if a.to_bits() != b.to_bits() {
7250                        return Err(format!(
7251                            "sel-group oracle: {geom} g=32 rows=4 idx {i} NOT bit-identical to \
7252                             the shipped v3 kernel (v3 {a} group {b}) — the sub-warp form must \
7253                             degenerate to v3 exactly"
7254                        )
7255                        .into());
7256                    }
7257                }
7258                bits_checked += shipped.len();
7259            }
7260            // Claim 2: same accumulation class as the kernel we ship. Checked BOTH ways —
7261            // against the exact host chain, and against the shipped kernel's own output.
7262            // The second is the one that would catch a reshape that drifted while staying
7263            // coincidentally close to the reference.
7264            for (i, (&w, &got)) in want.iter().zip(&got).enumerate() {
7265                let abs = (w - got).abs();
7266                let rel = abs / w.abs().max(1.0);
7267                worst.0 = worst.0.max(abs);
7268                worst.1 = worst.1.max(rel);
7269                if rel > class_tol {
7270                    return Err(format!(
7271                        "sel-group oracle: {geom} {spec} (g={g} rows={rows}) idx {i} vs HOST \
7272                         chain: want {w} got {got} (rel {rel:.3e} > tol {class_tol:.3e}, \
7273                         shipped v3 itself is {ship_vs_host:.3e})"
7274                    )
7275                    .into());
7276                }
7277            }
7278            for (i, (&s, &got)) in shipped.iter().zip(&got).enumerate() {
7279                let rel = (s - got).abs() / s.abs().max(1.0);
7280                if rel > class_tol {
7281                    return Err(format!(
7282                        "sel-group oracle: {geom} {spec} (g={g} rows={rows}) idx {i} vs SHIPPED \
7283                         v3: v3 {s} group {got} (rel {rel:.3e} > tol {class_tol:.3e})"
7284                    )
7285                    .into());
7286                }
7287            }
7288        }
7289        set_sel_group("off");
7290    }
7291
7292    // ---- fused gate+up+silu family -----------------------------------------------------
7293    // Claim 3: the fusion survives the reshape. The chain arm runs the SAME (g, rows) on
7294    // the single-bank kernel, so a mismatch is the fusion breaking, not the shape.
7295    for (geom, ff, in_f) in [("gu_real", 640usize, 2560usize), ("gu_tiny", 16, 64)] {
7296        let mut mk = |seed: u8| -> (Vec<u8>, Vec<u8>) {
7297            let mut codes = vec![0u8; n_expert * ff * in_f / 2];
7298            for byte in &mut codes {
7299                *byte = (next_u32() as u8) ^ seed;
7300            }
7301            let mut scales = vec![0u8; n_expert * ff * in_f / 16];
7302            for byte in &mut scales {
7303                *byte = (next_u32() as u8) & 0xBF;
7304            }
7305            scales[1] = 0x7F; // NaN scale byte -> 0.0
7306            (codes, scales)
7307        };
7308        let (g_codes, g_scales) = mk(0x00);
7309        let (u_codes, u_scales) = mk(0x5A);
7310        let gmac: Vec<f32> = macros.to_vec();
7311        let umac: Vec<f32> = macros.iter().map(|m| m * 0.5).collect();
7312        let x_host: Vec<f32> = (0..in_f)
7313            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7314            .collect();
7315        let gc = e.htod_bytes(&g_codes)?;
7316        let gs = e.htod_bytes(&g_scales)?;
7317        let gm = e.htod(&gmac)?;
7318        let uc = e.htod_bytes(&u_codes)?;
7319        let us = e.htod_bytes(&u_scales)?;
7320        let um = e.htod(&umac)?;
7321        let sel_dev = e.htod_i32(&sel_host)?;
7322        let x_dev = e.htod(&x_host)?;
7323        set_sel_group("off");
7324        set_sel_v3(true);
7325        let shipped_fused = {
7326            let mut act = e.zeros(n_sel * ff)?;
7327            launch_nvfp4_sel_gu_silu(
7328                e,
7329                (&gc, &gs, &gm),
7330                (&uc, &us, &um),
7331                Some(&sel_dev),
7332                0,
7333                n_sel,
7334                &x_dev,
7335                &mut act,
7336                in_f,
7337                ff,
7338                None,
7339            )?;
7340            e.dtoh(&act)?
7341        };
7342        for spec in ["32:4", "auto", "16:4", "16:2", "8:4", "8:1", "4:4"] {
7343            let Some((g, rows)) = sel_group_resolve(
7344                match spec {
7345                    "auto" => SEL_GROUP_AUTO,
7346                    _ => {
7347                        let (gs, rs) = spec.split_once(':').unwrap();
7348                        (gs.parse::<u32>().unwrap() << 8) | rs.parse::<u32>().unwrap()
7349                    }
7350                },
7351                in_f,
7352                ff,
7353            ) else {
7354                continue;
7355            };
7356            // Chain arm at the same shape: sel_g(gate) + sel_g(up) + silu_mul.
7357            set_sel_group(&format!("dn:{spec}+gu:off"));
7358            let mut yg = e.uninit(n_sel * ff)?;
7359            let mut yu = e.uninit(n_sel * ff)?;
7360            launch_nvfp4_sel_matvec(
7361                e, &gc, &gs, &gm, &sel_dev, &x_dev, &mut yg, n_sel, in_f, ff, 0,
7362            )?;
7363            launch_nvfp4_sel_matvec(
7364                e, &uc, &us, &um, &sel_dev, &x_dev, &mut yu, n_sel, in_f, ff, 0,
7365            )?;
7366            let mut act_chain = e.zeros(n_sel * ff)?;
7367            e.silu_mul(&yg, &yu, &mut act_chain, n_sel * ff)?;
7368            let chain = e.dtoh(&act_chain)?;
7369            // Fused arm at the same shape.
7370            set_sel_group(&format!("dn:off+gu:{spec}"));
7371            let mut act_fused = e.zeros(n_sel * ff)?;
7372            launch_nvfp4_sel_gu_silu(
7373                e,
7374                (&gc, &gs, &gm),
7375                (&uc, &us, &um),
7376                Some(&sel_dev),
7377                0,
7378                n_sel,
7379                &x_dev,
7380                &mut act_fused,
7381                in_f,
7382                ff,
7383                None,
7384            )?;
7385            let fused = e.dtoh(&act_fused)?;
7386            for (i, (&a, &b)) in chain.iter().zip(&fused).enumerate() {
7387                if a.to_bits() != b.to_bits() {
7388                    return Err(format!(
7389                        "sel-group oracle: {geom} gu {spec} (g={g} rows={rows}) idx {i} fused \
7390                         NOT bit-identical to the same-shape chain (chain {a} fused {b})"
7391                    )
7392                    .into());
7393                }
7394            }
7395            bits_checked += chain.len();
7396            shapes_checked += 1;
7397            if (g, rows) == (32, 4) {
7398                for (i, (&a, &b)) in shipped_fused.iter().zip(&fused).enumerate() {
7399                    if a.to_bits() != b.to_bits() {
7400                        return Err(format!(
7401                            "sel-group oracle: {geom} gu g=32 rows=4 idx {i} NOT bit-identical \
7402                             to the shipped gufuse kernel (gufuse {a} group {b})"
7403                        )
7404                        .into());
7405                    }
7406                }
7407                bits_checked += shipped_fused.len();
7408            }
7409        }
7410        // Count-gated pack twin and the slot->token verify merge, under AUTO — the two
7411        // addressing modes the serving path uses that the plain arm above does not reach.
7412        set_sel_group("dn:off+gu:auto");
7413        if sel_group_resolve(SEL_GROUP_AUTO, in_f, ff).is_some() {
7414            let auto_plain = {
7415                let mut act = e.zeros(n_sel * ff)?;
7416                launch_nvfp4_sel_gu_silu(
7417                    e,
7418                    (&gc, &gs, &gm),
7419                    (&uc, &us, &um),
7420                    Some(&sel_dev),
7421                    0,
7422                    n_sel,
7423                    &x_dev,
7424                    &mut act,
7425                    in_f,
7426                    ff,
7427                    None,
7428                )?;
7429                e.dtoh(&act)?
7430            };
7431            let pack_bytes = tp2_pack_bytes(&sel_host[..2], &[0.5, 0.25], n_sel);
7432            let pack = e.htod_bytes(&pack_bytes)?;
7433            let pack_raw = {
7434                let stream = e.gpu.stream();
7435                pack.device_ptr(&stream).0
7436            };
7437            let sentinel = vec![-777.0f32; n_sel * ff];
7438            let mut act_pack = e.htod(&sentinel)?;
7439            launch_nvfp4_sel_gu_silu(
7440                e,
7441                (&gc, &gs, &gm),
7442                (&uc, &us, &um),
7443                None,
7444                pack_raw,
7445                n_sel,
7446                &x_dev,
7447                &mut act_pack,
7448                in_f,
7449                ff,
7450                None,
7451            )?;
7452            let packed = e.dtoh(&act_pack)?;
7453            for slot in 0..n_sel {
7454                for o in 0..ff {
7455                    let got = packed[slot * ff + o];
7456                    if slot < 2 {
7457                        if got.to_bits() != auto_plain[slot * ff + o].to_bits() {
7458                            return Err(format!(
7459                                "sel-group oracle: {geom} gu auto pack slot {slot} o {o} not \
7460                                 bit-identical to the sel-array arm"
7461                            )
7462                            .into());
7463                        }
7464                    } else if got != -777.0 {
7465                        return Err(format!(
7466                            "sel-group oracle: {geom} gu auto pack dead slot {slot} written"
7467                        )
7468                        .into());
7469                    }
7470                }
7471            }
7472            // tok_map: two tokens' slots in ONE launch must bit-match per-token launches.
7473            let t2 = 2usize;
7474            let x2_host: Vec<f32> = (0..t2 * in_f)
7475                .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7476                .collect();
7477            let x2 = e.htod(&x2_host)?;
7478            let tok_host: Vec<i32> = (0..n_sel).map(|s| (s % t2) as i32).collect();
7479            let tokm = e.htod_i32(&tok_host)?;
7480            let mut act_map = e.zeros(n_sel * ff)?;
7481            launch_nvfp4_sel_gu_silu(
7482                e,
7483                (&gc, &gs, &gm),
7484                (&uc, &us, &um),
7485                Some(&sel_dev),
7486                0,
7487                n_sel,
7488                &x2,
7489                &mut act_map,
7490                in_f,
7491                ff,
7492                Some((&tokm, in_f)),
7493            )?;
7494            let mapped = e.dtoh(&act_map)?;
7495            for tok in 0..t2 {
7496                let slots: Vec<usize> = (0..n_sel).filter(|s| s % t2 == tok).collect();
7497                let sel_tok: Vec<i32> = slots.iter().map(|&s| sel_host[s]).collect();
7498                let sel_tok_dev = e.htod_i32(&sel_tok)?;
7499                let xrow = e.htod(&x2_host[tok * in_f..(tok + 1) * in_f])?;
7500                let mut act_tok = e.zeros(sel_tok.len() * ff)?;
7501                launch_nvfp4_sel_gu_silu(
7502                    e,
7503                    (&gc, &gs, &gm),
7504                    (&uc, &us, &um),
7505                    Some(&sel_tok_dev),
7506                    0,
7507                    sel_tok.len(),
7508                    &xrow,
7509                    &mut act_tok,
7510                    in_f,
7511                    ff,
7512                    None,
7513                )?;
7514                let want = e.dtoh(&act_tok)?;
7515                for (local, &slot) in slots.iter().enumerate() {
7516                    for o in 0..ff {
7517                        let a = mapped[slot * ff + o];
7518                        let b = want[local * ff + o];
7519                        if a.to_bits() != b.to_bits() {
7520                            return Err(format!(
7521                                "sel-group oracle: {geom} gu auto tok_map slot {slot} o {o} not \
7522                                 bit-identical (map {a} per-token {b})"
7523                            )
7524                            .into());
7525                        }
7526                    }
7527                }
7528            }
7529            bits_checked += auto_plain.len() + mapped.len();
7530        }
7531        set_sel_group("off");
7532    }
7533
7534    Ok(format!(
7535        "nvfp4-sel-GROUP kernel oracle: {shapes_checked} (geometry, shape) cells over REAL \
7536         MoE geometry (down 2560x640 pairs=20, gate_up 640x2560 pairs=80) + tiny, worst abs \
7537         {:.3e} rel {:.3e} vs the host decoder chain; (g=32,rows=4) BIT-IDENTICAL to the \
7538         shipped v3 and gufuse kernels and every shape's fused arm BIT-IDENTICAL to its \
7539         same-shape chain ({bits_checked} f32 byte-compared), incl. the count-gated pack \
7540         twin + the tok_map verify merge; NaN scales + non-pow2 macros + duplicate slots; \
7541         per-geometry class calibration [{}]",
7542        worst.0,
7543        worst.1,
7544        calib.join("; ")
7545    ))
7546}
7547
7548/// REAL-GEOMETRY oracle for the round-4 hyper-gate diet (the tiny plan's rank 4 fails
7549/// the %8 geometry guard, so the tiny arms never reach these kernels): the THREE-launch
7550/// diet chain (stage 1/2/3) vs the classic fused chain (hc_norm_planes + batched bf16w
7551/// down + lowrank reduce + batched bf16w up + mix epilogue + two-stage inject) on
7552/// IDENTICAL bf16 weights at streams 4, hidden 2560, rank 320, t 1. Tolerance class
7553/// (new reduce widths; 1e-4 rel, worst reported) over low_act, the inject slab, and
7554/// mixed.
7555pub fn gate_hc_diet_kernels(e: &Engine) -> Res<String> {
7556    let (streams, hidden, rank, t) = (4usize, 2560usize, 320usize, 1usize);
7557    let wide = streams * hidden;
7558    let mut lcg = 0x8badf00d_u64;
7559    let mut next_f32 = move || -> f32 {
7560        lcg = lcg
7561            .wrapping_mul(6364136223846793005)
7562            .wrapping_add(1442695040888963407);
7563        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
7564    };
7565    let mut rand_vec = |n: usize| -> Vec<f32> { (0..n).map(|_| next_f32()).collect() };
7566    // bf16-representable weights (truncate the low mantissa bits) so bf16_twin builds.
7567    let to_b16_vals = |v: Vec<f32>| -> Vec<f32> {
7568        v.into_iter()
7569            .map(|x| f32::from_bits(x.to_bits() & 0xFFFF_0000))
7570            .collect()
7571    };
7572    let planes_host: Vec<Vec<f32>> = (0..streams).map(|_| rand_vec(t * hidden)).collect();
7573    let planes: Vec<CudaSlice<f32>> = planes_host
7574        .iter()
7575        .map(|v| e.htod(v))
7576        .collect::<Result<_, _>>()?;
7577    let ptr_vals: Vec<u64> = {
7578        let stream = e.gpu.stream();
7579        planes.iter().map(|p| p.device_ptr(&stream).0).collect()
7580    };
7581    let ptrs = e.htod_u64(&ptr_vals)?;
7582    let norm_stack_host = rand_vec(wide);
7583    let norm_stack = e.htod(&norm_stack_host)?;
7584    let down_host = to_b16_vals(rand_vec(streams * rank * hidden));
7585    let up_host = to_b16_vals(rand_vec(streams * hidden * rank));
7586    let inj_host = to_b16_vals(rand_vec(streams * wide));
7587    let down_b16 = bf16_twin(e, &down_host, hidden)?.ok_or("hc-diet oracle: down twin")?;
7588    let up_b16 = bf16_twin(e, &up_host, rank)?.ok_or("hc-diet oracle: up twin")?;
7589    let inj_b16 = bf16_twin(e, &inj_host, hidden)?.ok_or("hc-diet oracle: inject twin")?;
7590    let inj_f32 = e.htod(&inj_host)?;
7591    let eps = 1e-6f32;
7592
7593    // Classic fused chain (the current default path) on the same operands.
7594    let mut normed = e.zeros(streams * t * hidden)?;
7595    launch_hc_norm_planes(e, &ptrs, &norm_stack, &mut normed, hidden, t, streams, eps)?;
7596    let mut parts_c = e.zeros(streams * t * rank)?;
7597    launch_qmatvec_bf16w(
7598        e,
7599        &down_b16,
7600        &normed,
7601        &mut parts_c,
7602        hidden,
7603        rank,
7604        t,
7605        streams,
7606        rank * hidden,
7607        t * hidden,
7608        hidden,
7609        t * rank,
7610    )?;
7611    let mut low_c = e.zeros(t * rank)?;
7612    launch_hc_lowrank_reduce(e, &parts_c, &mut low_c, streams, t, rank)?;
7613    let mut gates_c = e.zeros(streams * t * hidden)?;
7614    launch_qmatvec_bf16w(
7615        e,
7616        &up_b16,
7617        &low_c,
7618        &mut gates_c,
7619        rank,
7620        hidden,
7621        t,
7622        streams,
7623        hidden * rank,
7624        0,
7625        rank,
7626        t * hidden,
7627    )?;
7628    let mut mixed_c = e.zeros(t * hidden)?;
7629    launch_hc_mix_epilogue(e, &gates_c, &normed, &mut mixed_c, streams, t, hidden)?;
7630    let mut partials_c = e.zeros(streams * t * 16)?;
7631    let mut all_c = e.zeros(streams * t)?;
7632    launch_hc_inject_two_stage(
7633        e,
7634        &normed,
7635        &inj_f32,
7636        Some(&inj_b16),
7637        &mut partials_c,
7638        &mut all_c,
7639        streams,
7640        t,
7641        hidden,
7642        16,
7643    )?;
7644
7645    // Diet chain.
7646    let mut parts_d = e.zeros(streams * rank)?;
7647    let mut injp_d = e.zeros(streams * streams)?;
7648    let mut inv_d = e.zeros(streams)?;
7649    launch_hc_diet_stage1(
7650        e,
7651        &ptrs,
7652        &norm_stack,
7653        &down_b16,
7654        Some(&inj_b16),
7655        &mut parts_d,
7656        &mut injp_d,
7657        &mut inv_d,
7658        hidden,
7659        rank,
7660        streams,
7661        1,
7662        eps,
7663    )?;
7664    let mut low_d = e.zeros(rank)?;
7665    let mut all_d = e.zeros(streams)?;
7666    launch_hc_diet_stage2(
7667        e, &parts_d, &injp_d, &mut low_d, &mut all_d, rank, streams, 1, true,
7668    )?;
7669    let mut mixed_d = e.zeros(hidden)?;
7670    launch_hc_diet_stage3(
7671        e,
7672        &ptrs,
7673        &norm_stack,
7674        &inv_d,
7675        &up_b16,
7676        &low_d,
7677        &mut mixed_d,
7678        hidden,
7679        rank,
7680        streams,
7681        1,
7682    )?;
7683
7684    let mut worst = 0.0f32;
7685    let check = |name: &str, a: &[f32], b: &[f32], worst: &mut f32| -> Res<()> {
7686        for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
7687            let rel = (x - y).abs() / y.abs().max(1.0);
7688            if rel > *worst {
7689                *worst = rel;
7690            }
7691            if rel > 1e-4 {
7692                return Err(format!(
7693                    "hc-diet oracle: {name} idx {i}: diet {x} classic {y} (rel {rel:.3e})"
7694                )
7695                .into());
7696            }
7697        }
7698        Ok(())
7699    };
7700    check("low_act", &e.dtoh(&low_d)?, &e.dtoh(&low_c)?, &mut worst)?;
7701    check("inject", &e.dtoh(&all_d)?, &e.dtoh(&all_c)?, &mut worst)?;
7702    check("mixed", &e.dtoh(&mixed_d)?, &e.dtoh(&mixed_c)?, &mut worst)?;
7703
7704    // Token-dim extension (mtp-spec verify chunks): the SAME kernels at t = 3 must
7705    // produce per-token rows BIT-IDENTICAL to three t = 1 launches at plane offsets —
7706    // the spec byte-identity contract for the read gates.
7707    {
7708        let t3 = 3usize;
7709        let planes3_host: Vec<Vec<f32>> = (0..streams).map(|_| rand_vec(t3 * hidden)).collect();
7710        let planes3: Vec<CudaSlice<f32>> = planes3_host
7711            .iter()
7712            .map(|v| e.htod(v))
7713            .collect::<Result<_, _>>()?;
7714        let ptr_vals3: Vec<u64> = {
7715            let stream = e.gpu.stream();
7716            planes3.iter().map(|p| p.device_ptr(&stream).0).collect()
7717        };
7718        let ptrs3 = e.htod_u64(&ptr_vals3)?;
7719        let mut parts3 = e.zeros(t3 * streams * rank)?;
7720        let mut injp3 = e.zeros(t3 * streams * streams)?;
7721        let mut inv3 = e.zeros(t3 * streams)?;
7722        launch_hc_diet_stage1(
7723            e,
7724            &ptrs3,
7725            &norm_stack,
7726            &down_b16,
7727            Some(&inj_b16),
7728            &mut parts3,
7729            &mut injp3,
7730            &mut inv3,
7731            hidden,
7732            rank,
7733            streams,
7734            t3,
7735            eps,
7736        )?;
7737        let mut low3 = e.zeros(t3 * rank)?;
7738        let mut all3 = e.zeros(streams * t3)?;
7739        launch_hc_diet_stage2(
7740            e, &parts3, &injp3, &mut low3, &mut all3, rank, streams, t3, true,
7741        )?;
7742        let mut mixed3 = e.zeros(t3 * hidden)?;
7743        launch_hc_diet_stage3(
7744            e,
7745            &ptrs3,
7746            &norm_stack,
7747            &inv3,
7748            &up_b16,
7749            &low3,
7750            &mut mixed3,
7751            hidden,
7752            rank,
7753            streams,
7754            t3,
7755        )?;
7756        let low3_h = e.dtoh(&low3)?;
7757        let all3_h = e.dtoh(&all3)?;
7758        let mixed3_h = e.dtoh(&mixed3)?;
7759        // MT weight-shared stages (set_verify_mt): stage0 inv + stage1_mt parts +
7760        // stage3_mt mixed must be BIT-IDENTICAL to the token-grid stages above.
7761        {
7762            let mut inv_mt = e.zeros(t3 * streams)?;
7763            launch_hc_diet_stage0_mt(e, &ptrs3, &mut inv_mt, hidden, streams, t3, eps)?;
7764            let mut parts_mt = e.zeros(t3 * streams * rank)?;
7765            let mut injp_mt = e.zeros(t3 * streams * streams)?;
7766            launch_hc_diet_stage1_mt(
7767                e,
7768                &ptrs3,
7769                &norm_stack,
7770                &inv_mt,
7771                &down_b16,
7772                Some(&inj_b16),
7773                &mut parts_mt,
7774                &mut injp_mt,
7775                hidden,
7776                rank,
7777                streams,
7778                t3,
7779            )?;
7780            let mut low_mt = e.zeros(t3 * rank)?;
7781            let mut all_mt = e.zeros(streams * t3)?;
7782            launch_hc_diet_stage2(
7783                e,
7784                &parts_mt,
7785                &injp_mt,
7786                &mut low_mt,
7787                &mut all_mt,
7788                rank,
7789                streams,
7790                t3,
7791                true,
7792            )?;
7793            let mut mixed_mt = e.zeros(t3 * hidden)?;
7794            launch_hc_diet_stage3_mt(
7795                e,
7796                &ptrs3,
7797                &norm_stack,
7798                &inv_mt,
7799                &up_b16,
7800                &low_mt,
7801                &mut mixed_mt,
7802                hidden,
7803                rank,
7804                streams,
7805                t3,
7806            )?;
7807            let bit_check_mt = |name: &str, a: &[f32], b: &[f32]| -> Res<()> {
7808                for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
7809                    if x.to_bits() != y.to_bits() {
7810                        return Err(format!(
7811                            "hc-diet mt oracle: {name} idx {i}: mt {x} vs grid {y} NOT \
7812                             bit-identical"
7813                        )
7814                        .into());
7815                    }
7816                }
7817                Ok(())
7818            };
7819            bit_check_mt("inv", &e.dtoh(&inv_mt)?, &e.dtoh(&inv3)?)?;
7820            bit_check_mt("low_act", &e.dtoh(&low_mt)?, &low3_h)?;
7821            bit_check_mt("inject", &e.dtoh(&all_mt)?, &all3_h)?;
7822            bit_check_mt("mixed", &e.dtoh(&mixed_mt)?, &mixed3_h)?;
7823        }
7824        let bit_check = |name: &str, a: &[f32], b: &[f32]| -> Res<()> {
7825            for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
7826                if x.to_bits() != y.to_bits() {
7827                    return Err(format!(
7828                        "hc-diet t-ext oracle: {name} idx {i}: t3 {x} vs t1 {y} NOT bit-identical"
7829                    )
7830                    .into());
7831                }
7832            }
7833            Ok(())
7834        };
7835        for tok in 0..t3 {
7836            let ptr_tok: Vec<u64> = ptr_vals3
7837                .iter()
7838                .map(|&base| base + (tok * hidden * 4) as u64)
7839                .collect();
7840            let ptrs_tok = e.htod_u64(&ptr_tok)?;
7841            let mut parts1 = e.zeros(streams * rank)?;
7842            let mut injp1 = e.zeros(streams * streams)?;
7843            let mut inv1 = e.zeros(streams)?;
7844            launch_hc_diet_stage1(
7845                e,
7846                &ptrs_tok,
7847                &norm_stack,
7848                &down_b16,
7849                Some(&inj_b16),
7850                &mut parts1,
7851                &mut injp1,
7852                &mut inv1,
7853                hidden,
7854                rank,
7855                streams,
7856                1,
7857                eps,
7858            )?;
7859            let mut low1 = e.zeros(rank)?;
7860            let mut all1 = e.zeros(streams)?;
7861            launch_hc_diet_stage2(
7862                e, &parts1, &injp1, &mut low1, &mut all1, rank, streams, 1, true,
7863            )?;
7864            let mut mixed1 = e.zeros(hidden)?;
7865            launch_hc_diet_stage3(
7866                e,
7867                &ptrs_tok,
7868                &norm_stack,
7869                &inv1,
7870                &up_b16,
7871                &low1,
7872                &mut mixed1,
7873                hidden,
7874                rank,
7875                streams,
7876                1,
7877            )?;
7878            bit_check(
7879                "low_act",
7880                &low3_h[tok * rank..(tok + 1) * rank],
7881                &e.dtoh(&low1)?,
7882            )?;
7883            let all1_h = e.dtoh(&all1)?;
7884            let col: Vec<f32> = (0..streams).map(|s| all3_h[s * t3 + tok]).collect();
7885            bit_check("inject", &col, &all1_h)?;
7886            bit_check(
7887                "mixed",
7888                &mixed3_h[tok * hidden..(tok + 1) * hidden],
7889                &e.dtoh(&mixed1)?,
7890            )?;
7891        }
7892    }
7893    Ok(format!(
7894        "hc-diet real-geometry oracle: streams 4 hidden 2560 rank 320, worst rel \
7895         {worst:.3e} vs the classic fused chain at t 1; t 3 token-dim AND the mt \
7896         weight-shared stages BIT-IDENTICAL to per-token t 1 launches"
7897    ))
7898}
7899
7900/// Kernel-vs-host oracle for the bf16 trunk matvec (`qmatvec_bf16w_f32`). The tiny
7901/// four-arm gate's FIXTURE weights are random f32 (never bf16-representable), so its
7902/// bf16 twins are skipped by the value guard there and only the dir arms exercise the
7903/// path end to end; this synthetic arm gates the kernel directly against a host f32
7904/// matvec over identical bf16-widened weights: batch > 1, BOTH x_bstride modes (shared
7905/// plane like the up projection, per-batch planes like down), t > 1, negative/denormal
7906/// bf16 values, and a non-multiple-of-blockDim group count. Products are exact; only
7907/// summation order differs from the sequential host chain — tolerance 1e-5 rel.
7908/// REAL-GEOMETRY oracle for the hcmicro kernels (streams 4, hidden 2560, t 10 — the
7909/// artifact's read-gate shape, which the tiny plan (streams 2, hidden 16) cannot
7910/// reach). Each micro kernel runs against the classic composition it replaces on the
7911/// same random inputs: batched plane norms vs per-stream rms_norm, the two-stage inject
7912/// vs the single-stage kernel, the slab write vs the add_scaled_rows chain. Born from
7913/// the perf7 incident: the bundle shipped tiny-green and broke real prefill at layer 0.
7914pub fn gate_hc_micro_kernels(e: &Engine) -> Res<String> {
7915    let (streams, hidden, t) = (4usize, 2560usize, 10usize);
7916    let wide = streams * hidden;
7917    let mut lcg = 0x1357_9bdf_u64;
7918    let mut next_f32 = move || -> f32 {
7919        lcg = lcg
7920            .wrapping_mul(6364136223846793005)
7921            .wrapping_add(1442695040888963407);
7922        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
7923    };
7924    let mut rand_vec = |n: usize| -> Vec<f32> { (0..n).map(|_| next_f32()).collect() };
7925    let planes_host: Vec<Vec<f32>> = (0..streams).map(|_| rand_vec(t * hidden)).collect();
7926    let planes: Vec<CudaSlice<f32>> = planes_host
7927        .iter()
7928        .map(|v| e.htod(v))
7929        .collect::<Result<_, _>>()?;
7930    let ptr_vals: Vec<u64> = {
7931        let stream = e.gpu.stream();
7932        planes.iter().map(|p| p.device_ptr(&stream).0).collect()
7933    };
7934    let ptrs = e.htod_u64(&ptr_vals)?;
7935    let mut worst = 0.0f32;
7936    let check = |name: &str, a: &[f32], b: &[f32], worst: &mut f32| -> Res<()> {
7937        for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
7938            let rel = (x - y).abs() / y.abs().max(1.0);
7939            if rel > *worst {
7940                *worst = rel;
7941            }
7942            if rel > 1e-4 {
7943                return Err(format!(
7944                    "hc-micro oracle: {name} idx {i}: micro {x} classic {y} (rel {rel:.3e})"
7945                )
7946                .into());
7947            }
7948        }
7949        Ok(())
7950    };
7951
7952    // (a) batched plane norms vs per-stream rms_norm_into_view.
7953    let norm_stack_host = rand_vec(wide);
7954    let norm_stack = e.htod(&norm_stack_host)?;
7955    let eps = 1e-6f32;
7956    let mut normed_a = e.zeros(streams * t * hidden)?;
7957    launch_hc_norm_planes(
7958        e,
7959        &ptrs,
7960        &norm_stack,
7961        &mut normed_a,
7962        hidden,
7963        t,
7964        streams,
7965        eps,
7966    )?;
7967    let mut normed_b = e.zeros(streams * t * hidden)?;
7968    for s in 0..streams {
7969        let w = e.htod(&norm_stack_host[s * hidden..(s + 1) * hidden])?;
7970        let mut dst = normed_b.slice_mut(s * t * hidden..(s + 1) * t * hidden);
7971        launch_rms_norm_into_view(e, &planes[s], &w, &mut dst, hidden, t, eps)?;
7972    }
7973    check("norm", &e.dtoh(&normed_a)?, &e.dtoh(&normed_b)?, &mut worst)?;
7974
7975    // (b) two-stage inject vs the single-stage kernel, over the SAME normed slab.
7976    let inj_w_host = rand_vec(streams * wide);
7977    let inj_w = e.htod(&inj_w_host)?;
7978    let mut all_a = e.zeros(streams * t)?;
7979    let mut partials = e.zeros(streams * t * 16)?;
7980    launch_hc_inject_two_stage(
7981        e,
7982        &normed_b,
7983        &inj_w,
7984        None,
7985        &mut partials,
7986        &mut all_a,
7987        streams,
7988        t,
7989        hidden,
7990        16,
7991    )?;
7992    let mut all_b = e.zeros(streams * t)?;
7993    launch_hc_inject_gates(e, &normed_b, &inj_w, &mut all_b, streams, t, hidden)?;
7994    check("inject", &e.dtoh(&all_a)?, &e.dtoh(&all_b)?, &mut worst)?;
7995
7996    // (c) slab write vs the add_scaled_rows chain, from identical plane states.
7997    let block_out = e.htod(&rand_vec(t * hidden))?;
7998    launch_hc_write_planes(e, &ptrs, &block_out, &all_b, hidden, t, streams)?;
7999    let mut expect: Vec<Vec<f32>> = Vec::with_capacity(streams);
8000    let all_host = e.dtoh(&all_b)?;
8001    let bo_host = e.dtoh(&block_out)?;
8002    for (s, base) in planes_host.iter().enumerate() {
8003        let mut rows = base.clone();
8004        for tok in 0..t {
8005            let g = all_host[s * t + tok];
8006            for d in 0..hidden {
8007                rows[tok * hidden + d] += bo_host[tok * hidden + d] * g;
8008            }
8009        }
8010        expect.push(rows);
8011    }
8012    for (s, plane) in planes.iter().enumerate() {
8013        check(
8014            &format!("write plane {s}"),
8015            &e.dtoh(plane)?,
8016            &expect[s],
8017            &mut worst,
8018        )?;
8019    }
8020    Ok(format!(
8021        "hc-micro real-geometry oracle: streams 4 hidden 2560 t 10, worst rel {worst:.3e} \
8022         over norm/inject/write vs the classic composition"
8023    ))
8024}
8025
8026/// REAL-GEOMETRY oracle for the perf-round-3 GDN kernels (the tiny plan cannot reach
8027/// either: hk 4 fails the step twin's warp guard, and the fused norm's win is only
8028/// meaningful at real widths). (a) `gdn_scan_step_f32` vs `gdn_scan_naive_f32` at t=1
8029/// on identical inputs and state copies — same per-element math, block-tree vs
8030/// sequential row sums, so tolerance-gated (1e-4 rel, worst reported); covers the
8031/// artifact geometry (nk 16, nv 48, hk/hv 128 — head sharing h%nk) and the minimum
8032/// hk=32 shape. (b) `rms_sigmul_f32` vs the rms_norm + sigmoid + mul chain it replaces
8033/// — asserted BIT-IDENTICAL (the kernel is rms_norm_f32-verbatim + sigmoid_f32 with no
8034/// contraction seam).
8035/// Block-list attention kernel oracle (long-context lane), real QSA geometry (hd 256,
8036/// 24/2 heads). Arm A: masked kernel vs block-list kernel over the SAME selections at
8037/// t_kv 4096 — BIT identity (the masked kernel's -1e30 entries contribute exact-0 terms
8038/// in the same ascending order; see the kernel comment). Arm B: t_kv 16384 — past the
8039/// masked kernel's smem bound, where only the block-list form runs — vs a HOST f32 twin
8040/// of the same phase order (expf vs libm exp differ in ULPs; tolerance class).
8041/// Selections come through the PRODUCTION renderers (`rowsel_to_mask`/`rowsel_positions`)
8042/// so the emission code is gated with the kernel.
8043pub fn gate_sdpa_blocklist(e: &Engine) -> Res<String> {
8044    let mut lcg = 0x51ee_7bad_u64;
8045    let mut next_f32 = move || -> f32 {
8046        lcg = lcg
8047            .wrapping_mul(6364136223846793005)
8048            .wrapping_add(1442695040888963407);
8049        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
8050    };
8051    let (hd, nh, nkv, t) = (256usize, 24usize, 2usize, 3usize);
8052    let block_size = 4usize;
8053    let scale = 1.0 / (hd as f32).sqrt();
8054    let mut bit_rows = 0usize;
8055    let mut worst_rel = 0.0f32;
8056    for (t_kv, vs_masked) in [(4096usize, true), (16384usize, false)] {
8057        let q_host: Vec<f32> = (0..t * nh * hd).map(|_| next_f32()).collect();
8058        let k_host: Vec<f32> = (0..t_kv * nkv * hd).map(|_| next_f32()).collect();
8059        let v_host: Vec<f32> = (0..t_kv * nkv * hd).map(|_| next_f32()).collect();
8060        // Per-row selections: row 0 full causal prefix; rows 1/2 scored-form block lists
8061        // (stride-3 / tail-heavy) with the always-visible incomplete tail.
8062        let sels: Vec<RowSel> = (0..t)
8063            .map(|qt| {
8064                let visible = t_kv - t + qt + 1;
8065                let complete = visible / block_size;
8066                // A full-prefix row (production: complete <= budget) only in the
8067                // 4096 case — its position list scales with `visible`, and the
8068                // 16384 full form would blow the 48 KB smem cap production never
8069                // approaches (full rows are <= 2052 positions there).
8070                if qt == 0 && vs_masked {
8071                    return RowSel {
8072                        full: true,
8073                        blocks: Vec::new(),
8074                        visible,
8075                    };
8076                }
8077                let stride = if qt == 1 { 3 } else { 7 };
8078                let blocks: Vec<u32> = (0..complete as u32)
8079                    .rev()
8080                    .step_by(stride)
8081                    .take(512)
8082                    .collect::<Vec<_>>()
8083                    .into_iter()
8084                    .rev()
8085                    .collect();
8086                RowSel {
8087                    full: false,
8088                    blocks,
8089                    visible,
8090                }
8091            })
8092            .collect();
8093        let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
8094        let q = e.htod(&q_host)?;
8095        let k = e.htod(&k_host)?;
8096        let v = e.htod(&v_host)?;
8097        let pos = e.htod_i32(&pos_flat)?;
8098        let meta_dev = e.htod_i32(&meta)?;
8099        let mut o_list = e.zeros(t * nh * hd)?;
8100        launch_sdpa_blocklist(
8101            e,
8102            &q,
8103            &k.slice(0..t_kv * nkv * hd),
8104            &v.slice(0..t_kv * nkv * hd),
8105            &mut o_list,
8106            &pos,
8107            &meta_dev,
8108            hd,
8109            nh,
8110            nkv,
8111            t,
8112            max_count,
8113            scale,
8114        )?;
8115        let ours = e.dtoh(&o_list)?;
8116        if vs_masked {
8117            let mask = rowsel_to_mask(&sels, block_size, t_kv);
8118            let mask_dev = e.htod_bytes(&mask)?;
8119            let mut o_mask = e.zeros(t * nh * hd)?;
8120            launch_sdpa_mask(
8121                e,
8122                &q,
8123                &k.slice(0..t_kv * nkv * hd),
8124                &v.slice(0..t_kv * nkv * hd),
8125                &mut o_mask,
8126                &mask_dev,
8127                hd,
8128                nh,
8129                nkv,
8130                t,
8131                t_kv,
8132                scale,
8133            )?;
8134            let masked = e.dtoh(&o_mask)?;
8135            for (i, (a, b)) in masked.iter().zip(ours.iter()).enumerate() {
8136                if a.to_bits() != b.to_bits() {
8137                    return Err(format!(
8138                        "sdpa_blocklist vs masked: bit mismatch at {i}: {a} vs {b} (t_kv {t_kv})"
8139                    )
8140                    .into());
8141                }
8142            }
8143            bit_rows = t * nh * hd;
8144        } else {
8145            // HOST twin, same phase order: per (row, head) dots ascending over the
8146            // selection, single-pass max/exp/normalize, weighted V ascending.
8147            for qt in 0..t {
8148                let off = meta[2 * qt] as usize;
8149                let count = meta[2 * qt + 1] as usize;
8150                for head in 0..nh {
8151                    let kvh = head / (nh / nkv);
8152                    let qrow = &q_host[(qt * nh + head) * hd..(qt * nh + head + 1) * hd];
8153                    let mut scores: Vec<f32> = (0..count)
8154                        .map(|i| {
8155                            let p = pos_flat[off + i] as usize;
8156                            let krow = &k_host[(p * nkv + kvh) * hd..(p * nkv + kvh + 1) * hd];
8157                            let mut acc = 0.0f32;
8158                            for d in 0..hd {
8159                                acc += qrow[d] * krow[d];
8160                            }
8161                            acc * scale
8162                        })
8163                        .collect();
8164                    let mx = scores.iter().copied().fold(-1e30f32, f32::max);
8165                    let mut sum = 0.0f32;
8166                    for s in scores.iter_mut() {
8167                        *s = (*s - mx).exp();
8168                        sum += *s;
8169                    }
8170                    let inv = 1.0 / sum;
8171                    for s in scores.iter_mut() {
8172                        *s *= inv;
8173                    }
8174                    for d in 0..hd {
8175                        let mut acc = 0.0f32;
8176                        for (i, s) in scores.iter().enumerate() {
8177                            let p = pos_flat[off + i] as usize;
8178                            acc += s * v_host[(p * nkv + kvh) * hd + d];
8179                        }
8180                        let got = ours[(qt * nh + head) * hd + d];
8181                        let rel = (got - acc).abs() / acc.abs().max(1e-3);
8182                        worst_rel = worst_rel.max(rel);
8183                        if rel > 1e-4 {
8184                            return Err(format!(
8185                                "sdpa_blocklist vs host twin: rel {rel} at row {qt} head {head} \
8186                                 dim {d} (t_kv {t_kv})"
8187                            )
8188                            .into());
8189                        }
8190                    }
8191                }
8192            }
8193        }
8194    }
8195    Ok(format!(
8196        "sdpa-blocklist oracle: BIT-IDENTICAL to the masked kernel over {bit_rows} values \
8197         (t_kv 4096, full+stride selections); past the mask bound (t_kv 16384) worst rel \
8198         {worst_rel:.3e} vs the host twin"
8199    ))
8200}
8201
8202/// kvq/idxq kernel oracles (KV-quant lane). Four pins, all BIT-exact:
8203/// (1) the append-quantize kernels vs the host quantize twins (q8_0 K rows, q5_1 V
8204///     rows) over random + adversarial blocks (zeros, half-ulp rounding ties, subnormal
8205///     scales, constant blocks) at real (512) and padded-tail (40) widths;
8206/// (2) the row-dequant kernel vs the host dequant twins on those bytes;
8207/// (3) the FUSED quantized block-list attention vs the composition
8208///     "q4e_kv_dequant_rows then sdpa_blocklist_f32" — the load-bearing oracle: it
8209///     proves in-kernel dequant reads the same f32 values the storage contract defines
8210///     (the qsa_index_score 1-ULP FMA lesson made both sides explicit-intrinsic);
8211/// (4) the indexer q8/bf16 device appenders vs the host cache twins (the idxcache
8212///     host/device interleave contract).
8213/// Caveat, stated: blocks mixing +0.0 and -0.0 are outside the pin (fminf/fmaxf zero
8214/// sign order is unspecified); projection outputs do not produce signed-zero ties.
8215pub fn gate_kvq_kernels(e: &Engine) -> Res<String> {
8216    let mut lcg = 0x6b_7671_5eed_u64; // "kvq"-seeded LCG
8217    let mut next_f32 = move || -> f32 {
8218        lcg = lcg
8219            .wrapping_mul(6364136223846793005)
8220            .wrapping_add(1442695040888963407);
8221        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
8222    };
8223    let mut report = Vec::new();
8224
8225    // ---- (1) + (2): quantize + dequant twins ----
8226    for &dim in &[512usize, 40usize] {
8227        let rows = 9usize;
8228        let mut host_rows_f: Vec<f32> = (0..rows * dim).map(|_| next_f32()).collect();
8229        // Adversarial rows: 0 = all zeros; 1 = constant block (d == 0 path for q5's
8230        // mx == mn); 2 = rounding ties (values at exact half steps of the block scale).
8231        for v in host_rows_f[0..dim].iter_mut() {
8232            *v = 0.0;
8233        }
8234        for v in host_rows_f[dim..2 * dim].iter_mut() {
8235            *v = 0.75;
8236        }
8237        for (i, v) in host_rows_f[2 * dim..3 * dim].iter_mut().enumerate() {
8238            // amax = 1.0 at lane 0; others sit at k*(1/127)*0.5 half-steps.
8239            *v = if i == 0 {
8240                1.0
8241            } else {
8242                (i as f32) * 0.5 / 127.0
8243            };
8244        }
8245        // Subnormal-scale row.
8246        for v in host_rows_f[3 * dim..4 * dim].iter_mut() {
8247            *v *= 1e-40;
8248        }
8249        let dev_rows = e.htod(&host_rows_f)?;
8250        let mut kq = e.alloc_u8(rows * q8_row_bytes(dim))?;
8251        let mut vq = e.alloc_u8(rows * q5_row_bytes(dim))?;
8252        launch_q4e_kv_append(e, &dev_rows, &dev_rows, &mut kq, &mut vq, 0, rows, dim)?;
8253        let kq_host = e.dtoh_u8(&kq)?;
8254        let vq_host = e.dtoh_u8(&vq)?;
8255        let mut k_twin = Vec::new();
8256        let mut v_twin = Vec::new();
8257        for r in 0..rows {
8258            host_quant_q8_row(&host_rows_f[r * dim..(r + 1) * dim], dim, &mut k_twin);
8259            host_quant_q5_row(&host_rows_f[r * dim..(r + 1) * dim], dim, &mut v_twin);
8260        }
8261        if kq_host != k_twin {
8262            let i = kq_host.iter().zip(&k_twin).position(|(a, b)| a != b);
8263            return Err(format!("kvq q8 quantize twin: byte mismatch at {i:?} (dim {dim})").into());
8264        }
8265        if vq_host != v_twin {
8266            let i = vq_host.iter().zip(&v_twin).position(|(a, b)| a != b);
8267            return Err(format!("kvq q5 quantize twin: byte mismatch at {i:?} (dim {dim})").into());
8268        }
8269        // Dequant twin.
8270        let mut kf = e.zeros(rows * dim)?;
8271        let mut vf = e.zeros(rows * dim)?;
8272        launch_q4e_kv_dequant_rows(e, &kq, &vq, &mut kf, &mut vf, 0, rows, dim)?;
8273        let kf_host = e.dtoh(&kf)?;
8274        let vf_host = e.dtoh(&vf)?;
8275        let mut kf_twin = Vec::new();
8276        let mut vf_twin = Vec::new();
8277        host_deq_q8_rows(&kq_host, 0, rows, dim, &mut kf_twin);
8278        host_deq_q5_rows(&vq_host, 0, rows, dim, &mut vf_twin);
8279        for (i, (a, b)) in kf_host.iter().zip(&kf_twin).enumerate() {
8280            if a.to_bits() != b.to_bits() {
8281                return Err(format!("kvq q8 dequant twin: bit mismatch at {i} (dim {dim})").into());
8282            }
8283        }
8284        for (i, (a, b)) in vf_host.iter().zip(&vf_twin).enumerate() {
8285            if a.to_bits() != b.to_bits() {
8286                return Err(format!("kvq q5 dequant twin: bit mismatch at {i} (dim {dim})").into());
8287            }
8288        }
8289        report.push(format!("quant+dequant twins dim {dim}: BYTE/BIT-IDENTICAL"));
8290    }
8291
8292    // ---- (3) fused quant attention vs the dequant-rows composition ----
8293    {
8294        let (hd, nh, nkv, t) = (256usize, 24usize, 2usize, 3usize);
8295        let kv_dim = nkv * hd;
8296        let block_size = 4usize;
8297        let scale = 1.0 / (hd as f32).sqrt();
8298        let t_kv = 4096usize;
8299        let q_host: Vec<f32> = (0..t * nh * hd).map(|_| next_f32()).collect();
8300        let k_host: Vec<f32> = (0..t_kv * kv_dim).map(|_| next_f32()).collect();
8301        let v_host: Vec<f32> = (0..t_kv * kv_dim).map(|_| next_f32()).collect();
8302        let k_rows = e.htod(&k_host)?;
8303        let v_rows = e.htod(&v_host)?;
8304        let mut kq = e.alloc_u8(t_kv * q8_row_bytes(kv_dim))?;
8305        let mut vq = e.alloc_u8(t_kv * q5_row_bytes(kv_dim))?;
8306        launch_q4e_kv_append(e, &k_rows, &v_rows, &mut kq, &mut vq, 0, t_kv, kv_dim)?;
8307        // Selections: one full-prefix row + two scored stride rows (the
8308        // gate_sdpa_blocklist shapes, bounded to the production smem class).
8309        let sels: Vec<RowSel> = (0..t)
8310            .map(|qt| {
8311                let visible = (t_kv - t + qt + 1).min(2052);
8312                if qt == 0 {
8313                    return RowSel {
8314                        full: true,
8315                        blocks: Vec::new(),
8316                        visible,
8317                    };
8318                }
8319                let complete = (t_kv - t + qt + 1) / block_size;
8320                let stride = if qt == 1 { 3 } else { 7 };
8321                let blocks: Vec<u32> = (0..complete as u32)
8322                    .rev()
8323                    .step_by(stride)
8324                    .take(512)
8325                    .collect::<Vec<_>>()
8326                    .into_iter()
8327                    .rev()
8328                    .collect();
8329                RowSel {
8330                    full: false,
8331                    blocks,
8332                    visible: t_kv - t + qt + 1,
8333                }
8334            })
8335            .collect();
8336        let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
8337        let q = e.htod(&q_host)?;
8338        let pos = e.htod_i32(&pos_flat)?;
8339        let meta_dev = e.htod_i32(&meta)?;
8340        let mut o_fused = e.zeros(t * nh * hd)?;
8341        launch_q4e_sdpa_blocklist_q8q5(
8342            e,
8343            &q,
8344            &kq,
8345            &vq,
8346            &mut o_fused,
8347            &pos,
8348            &meta_dev,
8349            hd,
8350            nh,
8351            nkv,
8352            t,
8353            max_count,
8354            scale,
8355        )?;
8356        let mut k_deq = e.zeros(t_kv * kv_dim)?;
8357        let mut v_deq = e.zeros(t_kv * kv_dim)?;
8358        launch_q4e_kv_dequant_rows(e, &kq, &vq, &mut k_deq, &mut v_deq, 0, t_kv, kv_dim)?;
8359        let mut o_comp = e.zeros(t * nh * hd)?;
8360        launch_sdpa_blocklist(
8361            e,
8362            &q,
8363            &k_deq.slice(0..t_kv * kv_dim),
8364            &v_deq.slice(0..t_kv * kv_dim),
8365            &mut o_comp,
8366            &pos,
8367            &meta_dev,
8368            hd,
8369            nh,
8370            nkv,
8371            t,
8372            max_count,
8373            scale,
8374        )?;
8375        let fused = e.dtoh(&o_fused)?;
8376        let comp = e.dtoh(&o_comp)?;
8377        for (i, (a, b)) in fused.iter().zip(&comp).enumerate() {
8378            if a.to_bits() != b.to_bits() {
8379                return Err(format!(
8380                    "kvq fused attention vs dequant composition: bit mismatch at {i}: {a} vs {b}"
8381                )
8382                .into());
8383            }
8384        }
8385        // ---- (3b) `kvhoist` vs the un-hoisted kernel, SAME real geometry ----
8386        // The hoist is a pure read-pattern change (fp16 K block scale loaded once per 32-element
8387        // block instead of once per element), so the bar is bit-identity and nothing weaker.
8388        //
8389        // This arm rides arm (3)'s geometry deliberately: hd=256 is EIGHT 32-element blocks per
8390        // head slice and nkv=2 means the second KV head starts at element 256, so the hoisted
8391        // loop's block walk and its `e0 = kv_head*head_dim` offset are both genuinely exercised.
8392        // At a tiny head_dim the loop would run ONE iteration and the per-block scale advance —
8393        // the only thing the seam changes — would never be taken. That is precisely the
8394        // tiny-green/real-broken shape this lane has been bitten by twice, so the arm is written
8395        // where it cannot happen rather than trusted to a comment.
8396        {
8397            let was = kv_hoist_on();
8398            set_kv_hoist(true);
8399            let mut o_hoist = e.zeros(t * nh * hd)?;
8400            let launched = launch_q4e_sdpa_blocklist_q8q5(
8401                e,
8402                &q,
8403                &kq,
8404                &vq,
8405                &mut o_hoist,
8406                &pos,
8407                &meta_dev,
8408                hd,
8409                nh,
8410                nkv,
8411                t,
8412                max_count,
8413                scale,
8414            );
8415            set_kv_hoist(was);
8416            launched?;
8417            let hoist = e.dtoh(&o_hoist)?;
8418            let mut worst: Option<(usize, f32, f32)> = None;
8419            for (i, (a, b)) in hoist.iter().zip(&fused).enumerate() {
8420                if a.to_bits() != b.to_bits() && worst.is_none() {
8421                    worst = Some((i, *a, *b));
8422                }
8423            }
8424            if let Some((i, a, b)) = worst {
8425                return Err(format!(
8426                    "kvhoist vs un-hoisted q8q5 blocklist: bit mismatch at {i}: {a} vs {b} \
8427                     (hd={hd} nh={nh} nkv={nkv} t={t} t_kv={t_kv} max_count={max_count})"
8428                )
8429                .into());
8430            }
8431            // A no-op arm would also compare equal. Prove the seam actually selected the other
8432            // kernel: `kv_hoist_on()` gates the `e.func` name, and an unknown name would have
8433            // failed the launch above rather than silently falling through — so a green compare
8434            // plus a completed launch under the armed seam is the engagement evidence. State the
8435            // count so a zero-value compare cannot pass as a pass.
8436            report.push(format!(
8437                "kvhoist vs un-hoisted q8q5 blocklist: BIT-IDENTICAL over {} values \
8438                 (real geometry hd={hd} nh={nh} nkv={nkv}, {} blocks/head slice, max_count={max_count})",
8439                t * nh * hd,
8440                hd / 32
8441            ));
8442        }
8443        report.push(format!(
8444            "fused q8q5 blocklist vs dequant+f32 composition: BIT-IDENTICAL over {} values",
8445            t * nh * hd
8446        ));
8447    }
8448
8449    // ---- (4) indexer appenders vs the host cache twins ----
8450    {
8451        let idx_dim = 128usize;
8452        let qk_width = 5 * idx_dim; // 4 query heads + 1 key head
8453        let rows = 7usize;
8454        let src_host: Vec<f32> = (0..rows * qk_width).map(|_| next_f32()).collect();
8455        let src = e.htod(&src_host)?;
8456        let q_off = 4 * idx_dim;
8457        // q8 arm.
8458        let mut dst_q8 = e.alloc_u8((rows + 2) * q8_row_bytes(idx_dim))?;
8459        launch_q4e_idx_append_q8(e, &src, &mut dst_q8, rows, idx_dim, qk_width, q_off, 2)?;
8460        let got = e.dtoh_u8(&dst_q8)?;
8461        let mut twin = vec![0u8; 2 * q8_row_bytes(idx_dim)];
8462        for r in 0..rows {
8463            host_quant_q8_row(
8464                &src_host[r * qk_width + q_off..(r + 1) * qk_width],
8465                idx_dim,
8466                &mut twin,
8467            );
8468        }
8469        if got[2 * q8_row_bytes(idx_dim)..] != twin[2 * q8_row_bytes(idx_dim)..] {
8470            return Err("idxq q8 append twin: byte mismatch".into());
8471        }
8472        // bf16 arm.
8473        let mut dst_bf = unsafe { e.gpu.stream().alloc::<u16>((rows + 2) * idx_dim)? };
8474        e.gpu.stream().memset_zeros(&mut dst_bf)?;
8475        launch_q4e_idx_append_bf16(e, &src, &mut dst_bf, rows, idx_dim, qk_width, q_off, 2)?;
8476        let got_bf: Vec<u16> = {
8477            let v = e
8478                .gpu
8479                .stream()
8480                .clone_dtoh(&dst_bf.slice(0..(rows + 2) * idx_dim))?;
8481            e.gpu.stream().synchronize()?;
8482            v
8483        };
8484        for r in 0..rows {
8485            for c in 0..idx_dim {
8486                let want = f32_to_bf16_rne(src_host[r * qk_width + q_off + c]);
8487                if got_bf[(2 + r) * idx_dim + c] != want {
8488                    return Err(format!("idxq bf16 append twin: mismatch row {r} col {c}").into());
8489                }
8490            }
8491        }
8492        report.push("idx q8/bf16 appenders vs host twins: BYTE-IDENTICAL".to_string());
8493    }
8494
8495    Ok(format!("kvq kernel oracles: {}", report.join("; ")))
8496}
8497
8498/// Device QSA index-scorer oracle at REAL indexer geometry (4 heads x 128, block 4):
8499/// `qsa_index_score_f32` vs the host twin's arithmetic, BIT for BIT, over a block count
8500/// past the real budget (so the scoring arm — not the structural fast path — is what
8501/// runs), plus the top-k SET equality that the selection actually depends on.
8502pub fn gate_qsa_index_score(e: &Engine) -> Res<String> {
8503    let mut lcg = 0xfeed_1234_u64;
8504    let mut next_f32 = move || -> f32 {
8505        lcg = lcg
8506            .wrapping_mul(6364136223846793005)
8507            .wrapping_add(1442695040888963407);
8508        (((lcg >> 33) as u32) % 4000) as f32 / 2000.0 - 1.0
8509    };
8510    let (heads, head_dim) = (4usize, 128usize);
8511    let scale = (head_dim as f32).sqrt();
8512    let budget = 512usize;
8513    let mut worst_rows = 0usize;
8514    for (rows, n_blocks) in [(1usize, 4096usize), (7, 1031)] {
8515        let q_host: Vec<f32> = (0..rows * heads * head_dim).map(|_| next_f32()).collect();
8516        let pooled_host: Vec<f32> = (0..n_blocks * head_dim).map(|_| next_f32()).collect();
8517        let q = e.htod(&q_host)?;
8518        let pooled = e.htod(&pooled_host)?;
8519        let mut scores_dev = e.uninit(rows * n_blocks)?;
8520        launch_qsa_index_score(
8521            e,
8522            &q,
8523            &pooled,
8524            &mut scores_dev,
8525            heads,
8526            head_dim,
8527            n_blocks,
8528            rows,
8529            scale,
8530        )?;
8531        let got = e.dtoh(&scores_dev)?;
8532        for row in 0..rows {
8533            let qr = &q_host[row * heads * head_dim..(row + 1) * heads * head_dim];
8534            let host = score_blocks(qr, &pooled_host, heads, head_dim, n_blocks, scale, 1);
8535            for (b, want) in host.iter().enumerate() {
8536                let g = got[row * n_blocks + b];
8537                if g.to_bits() != want.to_bits() {
8538                    return Err(format!(
8539                        "qsa_index_score: bit mismatch row {row} block {b}: {g} vs host {want}"
8540                    )
8541                    .into());
8542                }
8543            }
8544            let a = top_blocks_ascending(&host, budget, 1);
8545            let b = top_blocks_ascending(&got[row * n_blocks..(row + 1) * n_blocks], budget, 1);
8546            if a != b {
8547                return Err(format!("qsa_index_score: top-k set differs at row {row}").into());
8548            }
8549            worst_rows += 1;
8550        }
8551    }
8552    // ---- `poolT`: the dim-major plane, through the SAME host-twin bar ----
8553    // Validates the whole chain, not just the kernel: the transpose kernel writes the plane from
8554    // the row-major region on device, and the transposed score kernel reads it. Bit-identity to
8555    // the host twin (not merely to the row-major device kernel) is the bar, because the row-major
8556    // kernel is itself gated against the host above — comparing only device-to-device would let a
8557    // shared mistake pass twice.
8558    //
8559    // The case is chosen to catch the ONE mistake this layout invites: `cap_rows != n_blocks`.
8560    // The plane's pitch is the mirror's block CAPACITY, and the mirror grows to a power of two
8561    // while `n_blocks` is whatever the fill happens to be — so `cap_rows == n_blocks` is the
8562    // ABNORMAL state, and a kernel handed `n_blocks` as its pitch would read dim d of block b as
8563    // dim d of a different block for every d > 0. That is silent wrong values, and it would be
8564    // green in any gate where the two numbers happen to coincide. Here they deliberately do not
8565    // (1031 blocks in a 4096-block plane), and a second case pins the aligned edge.
8566    let mut pool_t_rows = 0usize;
8567    for (rows, n_blocks, cap_rows) in [(1usize, 1031usize, 4096usize), (5, 2048, 2048)] {
8568        let q_host: Vec<f32> = (0..rows * heads * head_dim).map(|_| next_f32()).collect();
8569        let pooled_host: Vec<f32> = (0..n_blocks * head_dim).map(|_| next_f32()).collect();
8570        let q = e.htod(&q_host)?;
8571        // The mirror as `indexer_select_rows` builds it: POOL_PLANES regions of cap_rows*head_dim,
8572        // the row-major rows H2D'd into the first, the plane filled by the transpose kernel.
8573        let mut mirror = e.zeros(cap_rows * head_dim * POOL_PLANES)?;
8574        {
8575            let mut view = mirror.slice_mut(0..n_blocks * head_dim);
8576            e.gpu.stream().memcpy_htod(&pooled_host, &mut view)?;
8577        }
8578        launch_qsa_pooled_transpose(e, &mut mirror, 0, n_blocks, head_dim, cap_rows)?;
8579        let was = pool_t_on();
8580        set_pool_t(true);
8581        let mut scores_dev = e.uninit(rows * n_blocks)?;
8582        let launched = launch_qsa_index_score(
8583            e,
8584            &q,
8585            &mirror,
8586            &mut scores_dev,
8587            heads,
8588            head_dim,
8589            n_blocks,
8590            rows,
8591            scale,
8592        );
8593        set_pool_t(was);
8594        launched?;
8595        let got = e.dtoh(&scores_dev)?;
8596        for row in 0..rows {
8597            let qr = &q_host[row * heads * head_dim..(row + 1) * heads * head_dim];
8598            let host = score_blocks(qr, &pooled_host, heads, head_dim, n_blocks, scale, 1);
8599            for (b, want) in host.iter().enumerate() {
8600                let g = got[row * n_blocks + b];
8601                if g.to_bits() != want.to_bits() {
8602                    return Err(format!(
8603                        "poolT qsa_index_score_f32_t: bit mismatch row {row} block {b}: \
8604                         {g} vs host {want} (n_blocks={n_blocks} cap_rows={cap_rows})"
8605                    )
8606                    .into());
8607                }
8608            }
8609            if top_blocks_ascending(&host, budget, 1)
8610                != top_blocks_ascending(&got[row * n_blocks..(row + 1) * n_blocks], budget, 1)
8611            {
8612                return Err(format!(
8613                    "poolT qsa_index_score_f32_t: top-{budget} set differs at row {row} \
8614                     (n_blocks={n_blocks} cap_rows={cap_rows})"
8615                )
8616                .into());
8617            }
8618            pool_t_rows += 1;
8619        }
8620    }
8621    Ok(format!(
8622        "qsa-index-score oracle: device scores BIT-IDENTICAL to the host twin over \
8623         {worst_rows} rows (4096 + 1031 blocks, real 4x128 geometry) and top-512 sets equal; \
8624         poolT dim-major plane (transpose + transposed kernel) BIT-IDENTICAL to the SAME host \
8625         twin over {pool_t_rows} rows, incl. the pitch-trap case cap_rows=4096 != n_blocks=1031"
8626    ))
8627}
8628
8629/// PLE n-gram id CACHE oracle (262k perf lane, `plecache`): `host_ngram_ids_cached` vs the
8630/// full `host_ngram_ids` twin, ids compared EXACTLY (they are table row indices — one wrong
8631/// id gathers a different embedding row and the output is fluent and wrong, so there is no
8632/// tolerance to have). Host-only, so it costs nothing and runs on every gate invocation.
8633///
8634/// The cases are the ones a cache gets wrong, not the ones it gets right:
8635/// - **one-token-at-a-time growth** (the decode shape) and **chunked growth** (the prefill
8636///   shape) over the same sequence, interleaved lengths, against a fresh full recompute at
8637///   every length.
8638/// - **EOS inside the sequence**: `shift_right_ignore_eos` resets its segment at an eos, and
8639///   the running `last_eos_inclusive` is the one piece of cross-token state the incremental
8640///   form has to carry. A cache that ignored it would be green on eos-free text.
8641/// - **rewind to a DIVERGING prefix** (the spec-reject shape): extend, then ask for a
8642///   sequence that shares only a prefix. The cache must truncate at the divergence, not at
8643///   the length — a length-only check keeps another sequence's hashes and produces fluent
8644///   output from the wrong rows, which is invisible.
8645/// - **a SHORTER unrelated sequence in the same cache** (state reuse).
8646/// - **eos as the very first token** and **an all-eos sequence** (segment_start edges).
8647pub fn gate_ple_ngram_cache() -> Res<String> {
8648    // Real artifact geometry: max_ngram 3, 16 heads (8 per ngram size), per-head vocab.
8649    let max_ngram = 3usize;
8650    let heads_per_ngram = 8usize;
8651    let total_heads = (max_ngram - 1) * heads_per_ngram;
8652    let multipliers: Vec<i64> = vec![
8653        0x2545_F491_4F6C_DD1D,
8654        0x9E37_79B9_7F4A_7C15u64 as i64,
8655        0x1234_5678_9ABC_DEF1,
8656    ];
8657    let sizes: Vec<i64> = (0..total_heads)
8658        .map(|i| 2_500_012_160 - (i as i64) * 7)
8659        .collect();
8660    let offsets: Vec<i64> = (0..total_heads)
8661        .map(|i| (i as i64) * 2_500_012_160)
8662        .collect();
8663    let eos = 248_046u32;
8664    let full = |ids: &[u32]| -> Vec<i64> {
8665        host_ngram_ids(
8666            ids,
8667            &multipliers,
8668            &sizes,
8669            &offsets,
8670            max_ngram,
8671            heads_per_ngram,
8672            eos,
8673        )
8674    };
8675    let mut lcg = 0x0be1_10ca_u64;
8676    let mut next_tok = move || -> u32 {
8677        lcg = lcg
8678            .wrapping_mul(6364136223846793005)
8679            .wrapping_add(1442695040888963407);
8680        ((lcg >> 33) as u32) % 250_000
8681    };
8682    let mut checks = 0usize;
8683    let run = |label: &str, steps: Vec<Vec<u32>>| -> Res<usize> {
8684        // `steps` are cumulative sequences fed to ONE cache, in order.
8685        let (mut ci, mut ch, mut ce) = (Vec::new(), Vec::new(), -1i64);
8686        let mut n = 0usize;
8687        for seq in &steps {
8688            host_ngram_ids_cached(
8689                &mut ci,
8690                &mut ch,
8691                &mut ce,
8692                seq,
8693                &multipliers,
8694                &sizes,
8695                &offsets,
8696                max_ngram,
8697                heads_per_ngram,
8698                eos,
8699            );
8700            let want = full(seq);
8701            if ci.len() != want.len() {
8702                return Err(format!(
8703                    "plecache oracle {label}: cache has {} ids, twin {} at len {}",
8704                    ci.len(),
8705                    want.len(),
8706                    seq.len()
8707                )
8708                .into());
8709            }
8710            if let Some(i) = ci.iter().zip(&want).position(|(a, b)| a != b) {
8711                return Err(format!(
8712                    "plecache oracle {label}: id {i} differs at len {} (token {}, head {}): \
8713                     cache {} vs twin {}",
8714                    seq.len(),
8715                    i / total_heads,
8716                    i % total_heads,
8717                    ci[i],
8718                    want[i]
8719                )
8720                .into());
8721            }
8722            n += seq.len();
8723        }
8724        Ok(n)
8725    };
8726    // 1. Decode shape: grow one token at a time, eos-free.
8727    {
8728        let base: Vec<u32> = (0..200).map(|_| next_tok()).collect();
8729        let steps: Vec<Vec<u32>> = (1..=base.len()).map(|n| base[..n].to_vec()).collect();
8730        checks += run("decode-growth", steps)?;
8731    }
8732    // 2. Prefill shape: chunked growth with ragged chunk sizes.
8733    {
8734        let base: Vec<u32> = (0..600).map(|_| next_tok()).collect();
8735        let mut steps = Vec::new();
8736        let mut n = 0usize;
8737        for step in [7usize, 1, 64, 3, 128, 2, 200, 195] {
8738            n = (n + step).min(base.len());
8739            steps.push(base[..n].to_vec());
8740        }
8741        checks += run("prefill-chunks", steps)?;
8742    }
8743    // 3. EOS inside the sequence (segment resets), incl. adjacent eos and a trailing eos.
8744    {
8745        let mut base: Vec<u32> = (0..300).map(|_| next_tok()).collect();
8746        for p in [0usize, 1, 2, 37, 38, 100, 101, 102, 299] {
8747            base[p] = eos;
8748        }
8749        let steps: Vec<Vec<u32>> = (1..=base.len()).map(|n| base[..n].to_vec()).collect();
8750        checks += run("eos-segments", steps)?;
8751    }
8752    // 4. All-eos: every position resets its own segment.
8753    {
8754        let base: Vec<u32> = vec![eos; 40];
8755        let steps: Vec<Vec<u32>> = (1..=base.len()).map(|n| base[..n].to_vec()).collect();
8756        checks += run("all-eos", steps)?;
8757    }
8758    // 5. Rewind to a DIVERGING prefix, repeatedly, then past the old length.
8759    {
8760        let a: Vec<u32> = (0..300).map(|_| next_tok()).collect();
8761        let mut b = a.clone();
8762        b[150] = a[150].wrapping_add(1) % 250_000;
8763        let mut c = b.clone();
8764        c[7] = b[7].wrapping_add(3) % 250_000;
8765        let mut d = c.clone();
8766        d.truncate(9);
8767        d.extend((0..100).map(|_| next_tok()));
8768        checks += run(
8769            "rewind-divergent",
8770            vec![
8771                a.clone(),
8772                a[..151].to_vec(),
8773                b.clone(),
8774                b[..8].to_vec(),
8775                c.clone(),
8776                d.clone(),
8777                a.clone(),
8778            ],
8779        )?;
8780    }
8781    // 6. A shorter unrelated sequence in the same cache (state reuse), and back up again.
8782    {
8783        let a: Vec<u32> = (0..250).map(|_| next_tok()).collect();
8784        let mut s: Vec<u32> = (0..11).map(|_| next_tok()).collect();
8785        s[0] = eos;
8786        checks += run("state-reuse", vec![a.clone(), s.clone(), a.clone(), s])?;
8787    }
8788    Ok(format!(
8789        "plecache oracle: incremental n-gram ids EXACT vs the full host_ngram_ids twin over \
8790         {checks} cumulative-sequence comparisons across 6 case families (decode one-at-a-time \
8791         growth, ragged prefill chunks, eos segment resets incl. adjacent + leading + trailing \
8792         eos, all-eos, repeated rewinds to DIVERGING prefixes, and shorter-unrelated-sequence \
8793         state reuse)"
8794    ))
8795}
8796
8797/// SEAM TABLE oracle (host-only, 262k host-lever lane): every `MEMRA_Q4E_SEAMS` name maps to its
8798/// OWN switch, `set_seam` and `seam_state` agree, and arming one seam changes NOTHING else.
8799///
8800/// This exists because the name table was refactored out of `apply_env_seams` into `set_seam` so
8801/// a measurement harness could flip a seam between timed rounds, and three agents add arms to it
8802/// concurrently. The failure mode of a mechanical refactor like that is not a crash: it is one
8803/// arm wired to a neighbour's switch, which arms the wrong seam and produces a fully fluent,
8804/// fully green run measuring something other than what the receipt claims. A copy-paste arm that
8805/// duplicates the line above it is exactly what a per-name distinctness check catches and what
8806/// reading the diff does not.
8807///
8808/// The strong assertion is the CROSS one: for each name, snapshot every other seam's state, flip
8809/// this one, and require that every other state is unchanged. That is what makes it a wiring
8810/// test rather than a smoke test — a table where two names share a switch passes "set then read
8811/// it back" and fails this.
8812pub fn gate_seam_table() -> Res<String> {
8813    // Derived from `seam_names()` — the engine's own list — so adding a seam extends this gate
8814    // automatically instead of silently escaping it. The three-valued names (`idxq`, `longatt`)
8815    // have no boolean `seam_state` and are filtered out here, but they are still required below
8816    // to be ACCEPTED by both entry points.
8817    let all: &[&str] = seam_names();
8818    let boolean: Vec<&str> = all
8819        .iter()
8820        .copied()
8821        .filter(|n| seam_state(n).is_some())
8822        .collect();
8823    // Non-vacuity, and it has to be able to FAIL: a collapsed list would make every assertion
8824    // below pass over nothing. Both bounds are real — the table carries 20+ boolean seams today,
8825    // and at least the two three-valued ones (`idxq`, `longatt`) must be present and filtered
8826    // out — so a list that lost either class trips here instead of reporting a green over a stub.
8827    if boolean.len() < 20 || all.len() < boolean.len() + 2 {
8828        return Err(format!(
8829            "seam-table oracle: refusing to report on {} boolean names out of {} total — the \
8830             seam list collapsed, so every assertion below would be vacuous",
8831            boolean.len(),
8832            all.len()
8833        )
8834        .into());
8835    }
8836    let names: &[&str] = &boolean;
8837    let snapshot = || -> Res<Vec<bool>> {
8838        names
8839            .iter()
8840            .map(|n| {
8841                seam_state(n).ok_or_else(|| {
8842                    Box::<dyn std::error::Error>::from(format!(
8843                        "seam-table oracle: seam_state({n:?}) is None — the name is in set_seam \
8844                         but not in seam_state, so save/restore around a measurement would \
8845                         silently not restore it"
8846                    ))
8847                })
8848            })
8849            .collect()
8850    };
8851    let restore = |v: &[bool]| {
8852        for (n, &b) in names.iter().zip(v) {
8853            set_seam(n, b, None);
8854        }
8855    };
8856    let entry = snapshot()?;
8857    let mut checks = 0usize;
8858    for (i, name) in names.iter().enumerate() {
8859        for &want in &[true, false, true] {
8860            let before = snapshot()?;
8861            if !set_seam(name, want, None) {
8862                restore(&entry);
8863                return Err(format!("seam-table oracle: set_seam({name:?}) refused").into());
8864            }
8865            let after = snapshot()?;
8866            if after[i] != want {
8867                restore(&entry);
8868                return Err(format!(
8869                    "seam-table oracle: set_seam({name:?}, {want}) then seam_state read {} — the \
8870                     two tables disagree on this name",
8871                    after[i]
8872                )
8873                .into());
8874            }
8875            // THE CROSS-CHECK, and the reason this is a wiring test rather than a smoke test: a
8876            // copy-paste arm wired to a neighbour's switch passes "set it then read it back" and
8877            // fails only here.
8878            for (j, other) in names.iter().enumerate() {
8879                if j != i && after[j] != before[j] {
8880                    restore(&entry);
8881                    return Err(format!(
8882                        "seam-table oracle: arming {name:?} also changed {other:?} ({} -> {}) — \
8883                         two names share one switch",
8884                        before[j], after[j]
8885                    )
8886                    .into());
8887                }
8888            }
8889            checks += 1;
8890        }
8891    }
8892    // Every name in the engine's own list — including the three-valued ones — must be accepted by
8893    // both entry points, or `apply_env_seams` would silently ignore a documented seam and the
8894    // run would measure the default while its receipt named the seam.
8895    for name in all {
8896        if !seam_exists(name) {
8897            restore(&entry);
8898            return Err(format!(
8899                "seam-table oracle: seam_names() lists {name:?} but seam_exists refuses it"
8900            )
8901            .into());
8902        }
8903        if !set_seam(name, seam_state(name).unwrap_or(false), None) {
8904            restore(&entry);
8905            return Err(format!(
8906                "seam-table oracle: seam_names() lists {name:?} but set_seam refuses it"
8907            )
8908            .into());
8909        }
8910    }
8911    // An unknown name must be refused by BOTH entry points, not silently accepted.
8912    if seam_exists("definitely-not-a-seam") || set_seam("definitely-not-a-seam", true, None) {
8913        restore(&entry);
8914        return Err("seam-table oracle: an unknown seam name was accepted".into());
8915    }
8916    // And `seam_exists` must apply NOTHING — the property the interleaved-A/B harness relies on
8917    // when it validates a seam name before a 25-80 minute prefill begins.
8918    let before = snapshot()?;
8919    for name in all {
8920        let _ = seam_exists(name);
8921    }
8922    if snapshot()? != before {
8923        restore(&entry);
8924        return Err("seam-table oracle: seam_exists mutated a seam (it must be name-only)".into());
8925    }
8926    restore(&entry);
8927    if snapshot()? != entry {
8928        return Err("seam-table oracle: the gate did not restore the entry state".into());
8929    }
8930    Ok(format!(
8931        "seam-table oracle: {} boolean seam names of {} total, {checks} set/read cycles, each \
8932         verified to change its OWN state and NO other (the cross-check that catches an arm \
8933         wired to a neighbour's switch), every listed name accepted by both entry points, \
8934         unknown names refused by both, seam_exists proven side-effect-free, entry state restored",
8935        names.len(),
8936        all.len()
8937    ))
8938}
8939
8940/// Device QSA indexer top-k SELECTION oracle (262k perf lane): `qsa_index_topk_u32` vs
8941/// `top_blocks_ascending` over the SAME score slab. Contract: the selected block ids AND
8942/// their emitted (ascending) order are EXACT — hard fail on any difference, no tolerance,
8943/// because a differing selection changes which KV rows the attention reads.
8944///
8945/// Geometry is REAL, not tiny: budget 512 (the shipped `budget_blocks`) at block counts up
8946/// to **65,536 — the 262,144-token target window's `fill/4`** — plus non-multiple counts
8947/// and RAGGED batches where each row reads its own prefix of a wider slab, which is the
8948/// exact shape the sub-batched caller produces. The tiny-green/real-broken trap has bitten
8949/// this lane twice; a budget-2 fixture would pass a kernel that cannot address 2^16 blocks.
8950///
8951/// Tie batteries a random draw cannot produce, and they are the point rather than an edge
8952/// case — the pinned rule is score desc then block index ASC:
8953/// - **all-zero**: every score +0.0. The whole selection is decided by the index tiebreak,
8954///   and this class is STRUCTURAL here (the scores are a relu-sum, so a deep row really
8955///   does carry long runs of exact +0.0). A tie-blind kernel is green everywhere else and
8956///   silently wrong here.
8957/// - **duplicate group straddling the budget boundary**: more equal scores than remaining
8958///   slots, so the boundary itself is resolved by index.
8959/// - **signed zeros / subnormals / negative / NaN**: outside the reachable score domain
8960///   (the caller's scores are >= +0.0), but the kernel's key is `f32::total_cmp` verbatim
8961///   over the whole domain, so the oracle proves that rather than assuming the domain.
8962pub fn gate_qsa_index_topk(e: &Engine) -> Res<String> {
8963    let budget = 512usize;
8964    let mut lcg = 0x1d5e_10ca_u64;
8965    let mut rows_checked = 0usize;
8966    let mut deepest = 0usize;
8967    // (label, per-row block counts, slab stride, score generator)
8968    let mut cases: Vec<(String, Vec<usize>, usize, Vec<f32>)> = Vec::new();
8969    let mut next_f32 = move || -> f32 {
8970        lcg = lcg
8971            .wrapping_mul(6364136223846793005)
8972            .wrapping_add(1442695040888963407);
8973        // Relu-sum scores are >= 0 with a heavy mass at exactly +0.0 — draw that shape.
8974        let r = ((lcg >> 33) as u32) % 1000;
8975        if r < 250 { 0.0 } else { (r as f32) / 250.0 }
8976    };
8977    for (label, counts) in [
8978        ("real-262k-depth", vec![65_536usize]),
8979        ("real-131k-depth", vec![32_768usize, 32_768]),
8980        ("shallow", vec![513usize, 1_031, 4_096]),
8981        ("ragged-batch", vec![2_049usize, 8_191, 65_536, 4_097]),
8982    ] {
8983        let stride = *counts.iter().max().unwrap();
8984        let slab: Vec<f32> = (0..counts.len() * stride).map(|_| next_f32()).collect();
8985        cases.push((label.to_string(), counts, stride, slab));
8986    }
8987    // all-zero: index tiebreak alone decides the whole selection.
8988    cases.push((
8989        "all-zero".into(),
8990        vec![65_536usize],
8991        65_536,
8992        vec![0.0f32; 65_536],
8993    ));
8994    // duplicate group straddling the boundary: 600 equal scores for the last 500 slots.
8995    {
8996        let n = 4_096usize;
8997        let mut v = vec![0.0f32; n];
8998        for (i, slot) in v.iter_mut().enumerate() {
8999            *slot = if i < 12 {
9000                100.0 - i as f32
9001            } else if i % 7 == 0 {
9002                2.5 // ~585 exact duplicates, straddling slot 512
9003            } else {
9004                (i % 3) as f32 * 0.25
9005            };
9006        }
9007        cases.push(("dup-straddle".into(), vec![n], n, v));
9008    }
9009    // Signed zeros, subnormals, negatives and NaN: the total_cmp domain, not the score
9010    // domain. total_cmp orders -0.0 below +0.0 and every NaN by its sign bit.
9011    {
9012        let n = 2_048usize;
9013        let mut v = vec![0.0f32; n];
9014        for (i, slot) in v.iter_mut().enumerate() {
9015            *slot = match i % 8 {
9016                0 => 0.0,
9017                1 => -0.0,
9018                2 => f32::from_bits(1),  // smallest positive subnormal
9019                3 => -f32::from_bits(1), // smallest negative subnormal
9020                4 => -(i as f32) * 0.5,
9021                5 => f32::NAN,
9022                6 => -f32::NAN,
9023                _ => (i % 5) as f32,
9024            };
9025        }
9026        cases.push(("total-cmp-domain".into(), vec![n], n, v));
9027    }
9028    for (label, counts, stride, slab) in &cases {
9029        let scores = e.htod(slab)?;
9030        let picked = launch_qsa_index_topk(e, &scores, counts, *stride, budget)?;
9031        if picked.len() != counts.len() {
9032            return Err(format!("idxsel oracle {label}: {} rows back", picked.len()).into());
9033        }
9034        for (r, &complete) in counts.iter().enumerate() {
9035            let row = &slab[r * *stride..r * *stride + complete];
9036            let twin = top_blocks_ascending(row, budget, 1);
9037            if twin != picked[r] {
9038                let first = twin
9039                    .iter()
9040                    .zip(picked[r].iter())
9041                    .position(|(a, b)| a != b)
9042                    .unwrap_or(twin.len().min(picked[r].len()));
9043                return Err(format!(
9044                    "idxsel oracle {label}: selection differs at row {r} (blocks {complete}), \
9045                     first differing slot {first}: host {:?} vs device {:?}",
9046                    twin.get(first),
9047                    picked[r].get(first)
9048                )
9049                .into());
9050            }
9051            rows_checked += 1;
9052            deepest = deepest.max(complete);
9053        }
9054    }
9055    Ok(format!(
9056        "qsa-index-topk oracle: device selection ids + ASCENDING order EXACT vs \
9057         top_blocks_ascending over {rows_checked} rows / {} cases at budget {budget}, \
9058         deepest {deepest} blocks (= the 262,144-token window), incl. the all-zero, \
9059         boundary-straddling-duplicate and total_cmp-domain (signed zero / subnormal / \
9060         negative / NaN) tie classes",
9061        cases.len()
9062    ))
9063}
9064
9065/// Device-router oracle at REAL geometry (devtwin lane): `qwen4exp_route_topk_f32` vs
9066/// `host_route_softmax_topk` on the SAME logits. Contract: the selection (ids AND their
9067/// emitted order — the combine reads slots sequentially) is EXACT, hard fail on any
9068/// mismatch; weights within a documented ULP bound (exp is the one op not bit-pinned to
9069/// host libm — kernel doc), worst observed printed in the receipt. Rows include the tie
9070/// batteries a random draw cannot produce: duplicate-logit groups STRADDLING the top-k
9071/// boundary (weight ties resolve by index — the rule a logits-ordered top-k would get
9072/// wrong), an all-equal row, and underflow rows (subnormal/zero weight ties). The renorm
9073/// denominator floor is unbindable on softmax geometry (top-k sum >= k/experts — see
9074/// ROUTE_DENOM_FLOOR) so it carries no arm; the twin computes the same fmaxf.
9075pub fn gate_route_kernel(e: &Engine) -> Res<String> {
9076    let mut lcg = 0x00de_7710_u64;
9077    let mut next_f32 = move || -> f32 {
9078        lcg = lcg
9079            .wrapping_mul(6364136223846793005)
9080            .wrapping_add(1442695040888963407);
9081        (((lcg >> 33) as u32) % 8000) as f32 / 200.0 - 20.0 // router-logit-scale [-20, 20)
9082    };
9083    const ULP_BOUND: u32 = 2;
9084    let mut worst_ulp: u32 = 0;
9085    let mut rows_checked = 0usize;
9086    let run = |e: &Engine,
9087               label: &str,
9088               logits_host: &[f32],
9089               experts: usize,
9090               selected: usize,
9091               rows: usize,
9092               worst_ulp: &mut u32|
9093     -> Res<()> {
9094        let logits = e.htod(logits_host)?;
9095        let mut sel = e.alloc_uninit::<i32>(rows * selected)?;
9096        let mut w = e.uninit(rows * selected)?;
9097        let mut tok = e.alloc_uninit::<i32>(rows * selected)?;
9098        launch_route_topk(
9099            e,
9100            &logits,
9101            &mut sel,
9102            &mut w,
9103            Some((&mut tok, 3)),
9104            experts,
9105            selected,
9106            rows,
9107        )?;
9108        let sel_h = e.gpu.stream().clone_dtoh(&sel.slice(0..rows * selected))?;
9109        let w_h = e.dtoh(&w)?;
9110        let tok_h = e.gpu.stream().clone_dtoh(&tok.slice(0..rows * selected))?;
9111        let k = selected.min(experts);
9112        for row in 0..rows {
9113            let twin =
9114                host_route_softmax_topk(&logits_host[row * experts..(row + 1) * experts], selected);
9115            if twin.len() != k {
9116                return Err(format!("route oracle {label}: host twin width {}", twin.len()).into());
9117            }
9118            for (j, &(idx, wt)) in twin.iter().enumerate() {
9119                let ds = sel_h[row * selected + j];
9120                let dw = w_h[row * selected + j];
9121                if ds != idx as i32 {
9122                    return Err(format!(
9123                        "route oracle {label}: selection mismatch row {row} slot {j}: \
9124                         device {ds} vs host {idx}"
9125                    )
9126                    .into());
9127                }
9128                let ulp = (dw.to_bits() as i64 - wt.to_bits() as i64).unsigned_abs();
9129                let ulp = u32::try_from(ulp).unwrap_or(u32::MAX);
9130                if ulp > ULP_BOUND {
9131                    return Err(format!(
9132                        "route oracle {label}: weight ULP {ulp} > {ULP_BOUND} at row {row} \
9133                         slot {j}: device {dw:e} vs host {wt:e}"
9134                    )
9135                    .into());
9136                }
9137                *worst_ulp = (*worst_ulp).max(ulp);
9138                if tok_h[row * selected + j] != (3 + row) as i32 {
9139                    return Err(format!(
9140                        "route oracle {label}: tok map wrong at row {row} slot {j}"
9141                    )
9142                    .into());
9143                }
9144            }
9145        }
9146        Ok(())
9147    };
9148    // Real geometry, random router-scale logits, batched rows (the verify shape).
9149    let (experts, selected) = (512usize, 10usize);
9150    for rows in [1usize, 6, 16] {
9151        let logits: Vec<f32> = (0..rows * experts).map(|_| next_f32()).collect();
9152        run(e, "real", &logits, experts, selected, rows, &mut worst_ulp)?;
9153        rows_checked += rows;
9154    }
9155    // Tie batteries (single rows).
9156    let mut tie_rows: Vec<(String, Vec<f32>)> = Vec::new();
9157    {
9158        // A 12-wide duplicate group straddling the top-10 boundary at positions 4..16:
9159        // host keeps the six lowest indices of the group after the four strict leaders.
9160        let mut v: Vec<f32> = (0..experts).map(|i| -30.0 - (i as f32) * 0.01).collect();
9161        for (rank, slot) in [40usize, 7, 300, 11].iter().enumerate() {
9162            v[*slot] = 10.0 - rank as f32;
9163        }
9164        for slot in [500usize, 3, 77, 210, 8, 401, 129, 64, 255, 380, 17, 450] {
9165            v[slot] = 2.5;
9166        }
9167        tie_rows.push(("dup-straddle".into(), v));
9168        // All-equal: the selection is indices 0..k by the tie rule alone.
9169        tie_rows.push(("all-equal".into(), vec![0.125f32; experts]));
9170        // Underflow: one dominant logit, the rest deep negative — weights tie at
9171        // 0.0/subnormal and the boundary resolves by index among bit-equal weights.
9172        let mut v = vec![-200.0f32; experts];
9173        v[100] = 5.0;
9174        for (i, slot) in [479usize, 2, 33].iter().enumerate() {
9175            v[*slot] = -80.0 - i as f32; // subnormal-weight class
9176        }
9177        tie_rows.push(("underflow".into(), v));
9178    }
9179    for (label, v) in &tie_rows {
9180        run(e, label, v, experts, selected, 1, &mut worst_ulp)?;
9181        rows_checked += 1;
9182    }
9183    // Off-real geometry (the envelope's edges): small expert counts, selected == experts.
9184    for (ex, se) in [(64usize, 4usize), (16, 16), (128, 32)] {
9185        let logits: Vec<f32> = (0..3 * ex).map(|_| next_f32()).collect();
9186        run(e, "geom", &logits, ex, se, 3, &mut worst_ulp)?;
9187        rows_checked += 3;
9188    }
9189    Ok(format!(
9190        "route oracle: device selection ids+order EXACT vs host twin over {rows_checked} rows \
9191         (real 512/10 + tie straddle/all-equal/underflow + geometry edges), worst weight \
9192         ULP {worst_ulp} (bound {ULP_BOUND}), tok map exact"
9193    ))
9194}
9195
9196pub fn gate_gdn_step_kernels(e: &Engine) -> Res<String> {
9197    let mut lcg = 0x0bad_cafe_u64;
9198    let mut next_f32 = move || -> f32 {
9199        lcg = lcg
9200            .wrapping_mul(6364136223846793005)
9201            .wrapping_add(1442695040888963407);
9202        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
9203    };
9204    let mut worst = 0.0f32;
9205    for (nk, nv, hk, hv) in [(16usize, 48usize, 128usize, 128usize), (2, 4, 32, 8)] {
9206        let conv_dim = 2 * nk * hk + nv * hv;
9207        let qkv_host: Vec<f32> = (0..conv_dim).map(|_| next_f32()).collect();
9208        let g_log_host: Vec<f32> = (0..nv).map(|_| next_f32().abs() * -2.0).collect();
9209        let beta_host: Vec<f32> = (0..nv).map(|_| next_f32()).collect();
9210        let state_host: Vec<f32> = (0..nv * hv * hk).map(|_| next_f32()).collect();
9211        let qkv = e.htod(&qkv_host)?;
9212        let g_log = e.htod(&g_log_host)?;
9213        let beta = e.htod(&beta_host)?;
9214        let scale = 1.0 / (hk as f32).sqrt();
9215        let eps = 1e-6f32;
9216        let mut state_a = e.htod(&state_host)?;
9217        let mut o_a = e.zeros(nv * hv)?;
9218        launch_gdn_scan(
9219            e,
9220            &qkv,
9221            &g_log,
9222            &beta,
9223            &mut state_a,
9224            &mut o_a,
9225            nk,
9226            nv,
9227            hk,
9228            hv,
9229            1,
9230            scale,
9231            eps,
9232        )?;
9233        let mut state_b = e.htod(&state_host)?;
9234        let mut o_b = e.zeros(nv * hv)?;
9235        launch_gdn_scan_step(
9236            e,
9237            &qkv,
9238            &g_log,
9239            &beta,
9240            &mut state_b,
9241            &mut o_b,
9242            nk,
9243            nv,
9244            hk,
9245            hv,
9246            scale,
9247            eps,
9248        )?;
9249        for (name, reference, candidate) in [
9250            ("o", e.dtoh(&o_a)?, e.dtoh(&o_b)?),
9251            ("state", e.dtoh(&state_a)?, e.dtoh(&state_b)?),
9252        ] {
9253            for (i, (&r, &c)) in reference.iter().zip(&candidate).enumerate() {
9254                let rel = (r - c).abs() / r.abs().max(1.0);
9255                if rel > worst {
9256                    worst = rel;
9257                }
9258                if rel > 1e-4 {
9259                    return Err(format!(
9260                        "gdn-step oracle: nk{nk}/nv{nv}/hk{hk}/hv{hv} {name} idx {i}: \
9261                         naive {r} step {c} (rel {rel:.3e})"
9262                    )
9263                    .into());
9264                }
9265            }
9266        }
9267    }
9268    // (b) fused norm+gate bit-identity at the artifact norm shape (48 rows of 128).
9269    let (rows, cols) = (48usize, 128usize);
9270    let x = e.htod(&(0..rows * cols).map(|_| next_f32()).collect::<Vec<_>>())?;
9271    let w = e.htod(&(0..cols).map(|_| next_f32()).collect::<Vec<_>>())?;
9272    let z = e.htod(&(0..rows * cols).map(|_| next_f32()).collect::<Vec<_>>())?;
9273    let eps = 1e-6f32;
9274    let mut normed = e.zeros(rows * cols)?;
9275    e.rms_norm(&x, &w, &mut normed, cols, rows, eps)?;
9276    let mut sg = e.zeros(rows * cols)?;
9277    e.sigmoid(&z, &mut sg, rows * cols)?;
9278    let mut chain = e.zeros(rows * cols)?;
9279    e.mul(&normed, &sg, &mut chain, rows * cols)?;
9280    let mut fused = e.zeros(rows * cols)?;
9281    launch_rms_sigmul(e, &x, &w, &z, &mut fused, cols, rows, eps)?;
9282    let (chain_h, fused_h) = (e.dtoh(&chain)?, e.dtoh(&fused)?);
9283    for (i, (&a, &b)) in chain_h.iter().zip(&fused_h).enumerate() {
9284        if a.to_bits() != b.to_bits() {
9285            return Err(format!(
9286                "rms_sigmul oracle: idx {i} not bit-identical: chain {a:?} fused {b:?}"
9287            )
9288            .into());
9289        }
9290    }
9291    Ok(format!(
9292        "gdn-step kernel oracle: scan step twin worst rel {worst:.3e} over artifact + \
9293         hk32 geometries; rms_sigmul bit-identical to the norm/sigmoid/mul chain ({rows}x{cols})"
9294    ))
9295}
9296
9297pub fn gate_qmatvec_bf16(e: &Engine) -> Res<String> {
9298    let mut lcg = 0x9e37_79b9_u64;
9299    let mut next_u32 = move || -> u32 {
9300        lcg = lcg
9301            .wrapping_mul(6364136223846793005)
9302            .wrapping_add(1442695040888963407);
9303        (lcg >> 33) as u32
9304    };
9305    let mut worst = (0.0f32, 0.0f32);
9306    for (mode, batch, t, out_f, in_f, x_bstride) in [
9307        ("per_batch_x", 3usize, 2usize, 5usize, 48usize, 2 * 48usize),
9308        ("shared_x", 4, 3, 7, 16, 0usize),
9309    ] {
9310        // bf16 weights minted as bf16 BYTES first (so the host twin widens the same
9311        // values the kernel reads), incl. sign and small-exponent coverage.
9312        let w_elems = batch * out_f * in_f;
9313        let mut w_bytes = Vec::with_capacity(w_elems * 2);
9314        let mut w_host = Vec::with_capacity(w_elems);
9315        for _ in 0..w_elems {
9316            // Magnitude bits below 0x4000 (= 2.0): denormals through ~2.0, signed —
9317            // keeps a 48-term dot far from overflow while covering the exponent range.
9318            let h = ((next_u32() % 0x4000) as u16) | (((next_u32() & 1) as u16) << 15);
9319            w_bytes.extend_from_slice(&h.to_le_bytes());
9320            w_host.push(f32::from_bits(u32::from(h) << 16));
9321        }
9322        let x_rows = if x_bstride == 0 { t } else { batch * t };
9323        let x_host: Vec<f32> = (0..x_rows * in_f)
9324            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
9325            .collect();
9326        let w_dev = e.htod_bytes(&w_bytes)?;
9327        let x_dev = e.htod(&x_host)?;
9328        let mut y_dev = e.uninit(batch * t * out_f)?;
9329        launch_qmatvec_bf16w(
9330            e,
9331            &w_dev,
9332            &x_dev,
9333            &mut y_dev,
9334            in_f,
9335            out_f,
9336            t,
9337            batch,
9338            out_f * in_f,
9339            x_bstride,
9340            in_f,
9341            t * out_f,
9342        )?;
9343        let y = e.dtoh(&y_dev)?;
9344        for b in 0..batch {
9345            for tok in 0..t {
9346                let xrow = &x_host[b * x_bstride + tok * in_f..][..in_f];
9347                for o in 0..out_f {
9348                    let wrow = &w_host[(b * out_f + o) * in_f..][..in_f];
9349                    let mut want = 0.0f32;
9350                    for i in 0..in_f {
9351                        want += wrow[i] * xrow[i];
9352                    }
9353                    let got = y[(b * t + tok) * out_f + o];
9354                    let abs = (want - got).abs();
9355                    let rel = abs / want.abs().max(1.0);
9356                    worst.0 = worst.0.max(abs);
9357                    worst.1 = worst.1.max(rel);
9358                    if rel > 1e-5 {
9359                        return Err(format!(
9360                            "bf16-matvec oracle: {mode} b {b} tok {tok} row {o}: want {want} \
9361                             got {got} (rel {rel:.3e})"
9362                        )
9363                        .into());
9364                    }
9365                }
9366            }
9367        }
9368    }
9369    // MT weight-shared mode (mtp-spec verify): the multi-token kernel must be
9370    // BIT-IDENTICAL per (row, token) to the per-token grid on the same operands —
9371    // artifact-class geometry (in_f % 8, wide rows) + odd t.
9372    {
9373        let (out_f, in_f, t) = (33usize, 64usize, 5usize);
9374        let w_elems = out_f * in_f;
9375        let mut w_bytes = Vec::with_capacity(w_elems * 2);
9376        for _ in 0..w_elems {
9377            let h = ((next_u32() % 0x4000) as u16) | (((next_u32() & 1) as u16) << 15);
9378            w_bytes.extend_from_slice(&h.to_le_bytes());
9379        }
9380        let x_host: Vec<f32> = (0..t * in_f)
9381            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
9382            .collect();
9383        let w_dev = e.htod_bytes(&w_bytes)?;
9384        let x_dev = e.htod(&x_host)?;
9385        let mut y_grid = e.uninit(t * out_f)?;
9386        launch_qmatvec_bf16w(
9387            e,
9388            &w_dev,
9389            &x_dev,
9390            &mut y_grid,
9391            in_f,
9392            out_f,
9393            t,
9394            1,
9395            0,
9396            0,
9397            in_f,
9398            0,
9399        )?;
9400        let mut y_mt = e.uninit(t * out_f)?;
9401        launch_qmatvec_bf16w_mt(e, &w_dev, 0, &x_dev, &mut y_mt, in_f, out_f, t)?;
9402        let (a, b) = (e.dtoh(&y_grid)?, e.dtoh(&y_mt)?);
9403        for (i, (&x1, &x2)) in a.iter().zip(&b).enumerate() {
9404            if x1.to_bits() != x2.to_bits() {
9405                return Err(format!(
9406                    "bf16-matvec mt oracle: idx {i}: grid {x1} vs mt {x2} NOT bit-identical"
9407                )
9408                .into());
9409            }
9410        }
9411    }
9412    // SEL mode (devtwin stage 2, the DeviceBf16 draft bank): the device-selected
9413    // grouped kernel must be BIT-IDENTICAL per slot to the per-slot off_into chain on
9414    // the same bank + sel (duplicate slots included), in BOTH stride shapes — shared x
9415    // (gate/up) and per-slot x rows (down).
9416    {
9417        let (experts, out_f, in_f, n_sel) = (16usize, 24usize, 32usize, 6usize);
9418        let w_elems = experts * out_f * in_f;
9419        let mut w_bytes = Vec::with_capacity(w_elems * 2);
9420        for _ in 0..w_elems {
9421            let h = ((next_u32() % 0x4000) as u16) | (((next_u32() & 1) as u16) << 15);
9422            w_bytes.extend_from_slice(&h.to_le_bytes());
9423        }
9424        let sel_host: Vec<i32> = vec![7, 0, 15, 7, 3, 9]; // duplicate expert on purpose
9425        let bank = e.htod_bytes(&w_bytes)?;
9426        let sel = e.htod_i32(&sel_host)?;
9427        for (label, x_rows, x_sstride) in [("shared-x", 1usize, 0usize), ("slot-x", n_sel, in_f)] {
9428            let x_host: Vec<f32> = (0..x_rows * in_f)
9429                .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
9430                .collect();
9431            let x_dev = e.htod(&x_host)?;
9432            let mut y_sel = e.uninit(n_sel * out_f)?;
9433            launch_qmatvec_bf16w_sel(
9434                e, &bank, &sel, 0, &x_dev, 0, x_sstride, &mut y_sel, n_sel, in_f, out_f,
9435            )?;
9436            let mut y_ref = e.uninit(n_sel * out_f)?;
9437            for (slot, &eid) in sel_host.iter().enumerate() {
9438                launch_qmatvec_bf16w_off_into(
9439                    e,
9440                    &bank,
9441                    eid as usize * out_f,
9442                    &x_dev,
9443                    slot * x_sstride,
9444                    &mut y_ref,
9445                    slot * out_f,
9446                    in_f,
9447                    out_f,
9448                )?;
9449            }
9450            let (a, b) = (e.dtoh(&y_sel)?, e.dtoh(&y_ref)?);
9451            for (i, (&x1, &x2)) in a.iter().zip(&b).enumerate() {
9452                if x1.to_bits() != x2.to_bits() {
9453                    return Err(format!(
9454                        "bf16-matvec sel oracle ({label}): idx {i}: sel {x1} vs off_into {x2} \
9455                         NOT bit-identical"
9456                    )
9457                    .into());
9458                }
9459            }
9460        }
9461    }
9462    Ok(format!(
9463        "bf16-matvec kernel oracle: worst abs {:.3e} rel {:.3e} over per-batch + shared-x \
9464         modes, batch>1, t>1, signed/denormal bf16; mt weight-shared twin BIT-IDENTICAL \
9465         at t 5; sel grouped twin BIT-IDENTICAL to the off_into chain (shared-x + slot-x, \
9466         duplicate slots)",
9467        worst.0, worst.1
9468    ))
9469}
9470
9471/// Dequantize ONE expert of a device-resident modelopt-NVFP4 stacked bank to f32.
9472///
9473/// The existing dsv4 kernel (`memra_dsv4_nvfp4_deq_bf16`) emits bf16, so the macro is
9474/// NOT passed into it: e2m1 × e4m3 products carry ≤ 6 significand bits and are EXACT in
9475/// bf16, and the macro multiplies AFTER the exact f32 upcast. That reproduces the host
9476/// decoder (`dsv4::dequant_nvfp4_expert`: `(code * scale) * scale_2`, one f32 rounding)
9477/// bit-for-bit for ANY finite macro — the real qwen4_exp mint ships modelopt's
9478/// amax-derived NON-pow2 `weight_scale_2` (measured 5.9945243e-5), which the dsv4-era
9479/// in-kernel-macro chain would round in bf16 (hence its pow2 law; not needed here).
9480fn dequant_nvfp4_expert_f32(
9481    e: &Engine,
9482    codes: &CudaSlice<u8>,
9483    scales: &CudaSlice<u8>,
9484    macro_scale: f32,
9485    expert: usize,
9486    rows: usize,
9487    cols: usize,
9488) -> Res<CudaSlice<f32>> {
9489    let wbytes = rows * cols / 2;
9490    let sbytes = rows * cols / 16;
9491    let bf = e.alloc_u8(rows * cols * 2)?;
9492    let stream = e.gpu.stream();
9493    let wp = (codes.device_ptr(&stream).0 as usize + expert * wbytes) as *const c_void;
9494    let scp = (scales.device_ptr(&stream).0 as usize + expert * sbytes) as *const c_void;
9495    let dst = bf.device_ptr(&stream).0 as usize as *mut c_void;
9496    let rc = unsafe {
9497        crate::dsv4_ffi::memra_dsv4_nvfp4_deq_bf16(
9498            wp,
9499            scp,
9500            1.0, // macro applied post-upcast in f32 (see the doc comment)
9501            rows as i32,
9502            cols as i32,
9503            dst,
9504            stream.cu_stream() as *mut c_void,
9505        )
9506    };
9507    if rc != 0 {
9508        return Err(format!("memra_dsv4_nvfp4_deq_bf16 rc={rc}").into());
9509    }
9510    let mut out = e.bf16_to_f32(&bf.slice(0..rows * cols * 2), rows * cols)?;
9511    if macro_scale != 1.0 {
9512        e.scale_inplace(&mut out, macro_scale, rows * cols)?;
9513    }
9514    Ok(out)
9515}
9516
9517// ---------------------------------------------------------------- loading
9518
9519fn expect(weights: &ReferenceWeights, id: &TensorId) -> Res<ReferenceTensor> {
9520    weights
9521        .get(id)
9522        .cloned()
9523        .ok_or_else(|| format!("qwen4exp_gpu: missing weight {id:?}").into())
9524}
9525
9526fn family_id(key: String) -> TensorId {
9527    TensorId::Family {
9528        family: "qwen4_exp",
9529        key,
9530    }
9531}
9532
9533fn layer_id(index: u32, tensor: LayerTensor) -> TensorId {
9534    TensorId::Layer { index, tensor }
9535}
9536
9537fn upload(e: &Engine, tensor: &ReferenceTensor) -> Res<CudaSlice<f32>> {
9538    e.htod(&tensor.data)
9539}
9540
9541/// Slice a [rows, wide] row-major tensor into per-stream [rows, hidden] column blocks.
9542fn split_columns(data: &[f32], rows: usize, streams: usize, hidden: usize) -> Vec<Vec<f32>> {
9543    let wide = streams * hidden;
9544    (0..streams)
9545        .map(|s| {
9546            let mut out = Vec::with_capacity(rows * hidden);
9547            for row in 0..rows {
9548                out.extend_from_slice(
9549                    &data[row * wide + s * hidden..row * wide + (s + 1) * hidden],
9550                );
9551            }
9552            out
9553        })
9554        .collect()
9555}
9556
9557/// Slice a [wide, cols] row-major tensor into per-stream [hidden, cols] row blocks.
9558fn split_rows(data: &[f32], streams: usize, hidden: usize, cols: usize) -> Vec<Vec<f32>> {
9559    (0..streams)
9560        .map(|s| data[s * hidden * cols..(s + 1) * hidden * cols].to_vec())
9561        .collect()
9562}
9563
9564fn load_gate(
9565    e: &Engine,
9566    weights: &ReferenceWeights,
9567    prefix: &str,
9568    sublayer: &str,
9569    streams: usize,
9570    hidden: usize,
9571    rank: usize,
9572    with_inject: bool,
9573) -> Res<GateW> {
9574    let wide = streams * hidden;
9575    let norm = expect(
9576        weights,
9577        &family_id(format!("{prefix}{sublayer}hc_norm.weight")),
9578    )?;
9579    let down = expect(
9580        weights,
9581        &family_id(format!("{prefix}{sublayer}input_mix_weight_down.weight")),
9582    )?;
9583    let up = expect(
9584        weights,
9585        &family_id(format!("{prefix}{sublayer}input_mix_weight_up.weight")),
9586    )?;
9587    if norm.data.len() != wide || down.data.len() != rank * wide || up.data.len() != wide * rank {
9588        return Err(format!("qwen4exp_gpu: gate {prefix}{sublayer} shape mismatch").into());
9589    }
9590    let norm_slices = split_rows(&norm.data, streams, hidden, 1);
9591    let down_slices = split_columns(&down.data, rank, streams, hidden);
9592    let up_slices = split_rows(&up.data, streams, hidden, rank);
9593    // bf16 trunk twins, STACKED across streams so the fused gate runs one batched
9594    // launch per projection (guards in `bf16_twin`).
9595    let stack = |slices: &[Vec<f32>]| -> Vec<f32> {
9596        let mut out = Vec::with_capacity(slices.len() * slices[0].len());
9597        for s in slices {
9598            out.extend_from_slice(s);
9599        }
9600        out
9601    };
9602    let down_b16 = bf16_twin(e, &stack(&down_slices), hidden)?;
9603    let up_b16 = bf16_twin(e, &stack(&up_slices), rank)?;
9604    let (inject, inject_b16) = if with_inject {
9605        let inject = expect(
9606            weights,
9607            &family_id(format!("{prefix}{sublayer}block_inject_weight.weight")),
9608        )?;
9609        if inject.data.len() != streams * wide {
9610            return Err(format!("qwen4exp_gpu: inject {prefix}{sublayer} shape mismatch").into());
9611        }
9612        // Kept whole: the fused inject kernel walks [s][s2*hidden + d] directly, which is
9613        // exactly this tensor's row-major layout against the stream-major normed planes.
9614        (
9615            Some(e.htod(&inject.data)?),
9616            bf16_twin(e, &inject.data, hidden)?,
9617        )
9618    } else {
9619        (None, None)
9620    };
9621    Ok(GateW {
9622        norm_stack: e.htod(&stack(&norm_slices))?,
9623        norm: norm_slices
9624            .into_iter()
9625            .map(|v| e.htod(&v))
9626            .collect::<Result<_, _>>()?,
9627        down: down_slices
9628            .into_iter()
9629            .map(|v| e.htod(&v))
9630            .collect::<Result<_, _>>()?,
9631        up: up_slices
9632            .into_iter()
9633            .map(|v| e.htod(&v))
9634            .collect::<Result<_, _>>()?,
9635        inject,
9636        down_b16,
9637        up_b16,
9638        inject_b16,
9639    })
9640}
9641
9642/// Loader-side carriers that bypass `ReferenceWeights` (the real artifact cannot
9643/// materialize them host-f32): device-bound expert banks and host n-gram tables,
9644/// keyed by trunk layer index.
9645#[derive(Default)]
9646pub struct ExternalParts {
9647    expert_banks: std::collections::BTreeMap<u32, ExpertBank>,
9648    ngram_tables: std::collections::BTreeMap<u32, NgramTable>,
9649}
9650
9651/// Build one decoder layer's engine-resident weights from TensorId-keyed reference
9652/// weights — shared by the trunk loop and the MTP draft block (mtp-spec lane), which is
9653/// the same layer schema at global index n_trunk under the `mtp.layers.{depth}.` prefix.
9654#[allow(clippy::too_many_arguments)]
9655fn build_layer_w(
9656    e: &Engine,
9657    weights: &ReferenceWeights,
9658    layer: &memra_gguf::model_plan::LayerPlan,
9659    prefix: &str,
9660    streams: usize,
9661    hidden: usize,
9662    rank: usize,
9663    bank_override: Option<ExpertBank>,
9664    table_override: Option<NgramTable>,
9665) -> Res<LayerW> {
9666    let ResidualTopology::GatedResidual { .. } = layer.residual else {
9667        return Err(format!("qwen4exp_gpu: layer {} is not gated-residual", layer.index).into());
9668    };
9669    let attn_gate = load_gate(
9670        e,
9671        weights,
9672        prefix,
9673        "attn_hyper_connection.",
9674        streams,
9675        hidden,
9676        rank,
9677        true,
9678    )?;
9679    let mlp_gate = load_gate(
9680        e,
9681        weights,
9682        prefix,
9683        "mlp_hyper_connection.",
9684        streams,
9685        hidden,
9686        rank,
9687        true,
9688    )?;
9689    let mixer = match &layer.attention {
9690        AttentionPlan::Full(attn) => {
9691            let overlay = layer.sparse_overlay.ok_or_else(|| {
9692                format!(
9693                    "qwen4exp_gpu: QSA layer {} has no indexer overlay",
9694                    layer.index
9695                )
9696            })?;
9697            // Plain partial rope or YaRN (long-context lane); anything else refuses in
9698            // `build_yarn`.
9699            let yarn = build_yarn(e, &attn.rope, Some(&overlay), layer.index)?;
9700            // The eager attention path lays q/k/v/attended out with ONE head_dim
9701            // and gates full-width; unequal key/value dims would be silently
9702            // wrong, so refuse (family: 256/256).
9703            if attn.key_head_dim != attn.value_head_dim {
9704                return Err(format!(
9705                    "qwen4exp_gpu: layer {} key_head_dim {} != value_head_dim {}",
9706                    layer.index, attn.key_head_dim, attn.value_head_dim
9707                )
9708                .into());
9709            }
9710            let load_opt_norm = |tensor: LayerTensor| -> Res<Option<CudaSlice<f32>>> {
9711                match weights.get(&layer_id(layer.index, tensor)) {
9712                    Some(t) => Ok(Some(e.htod(&t.data)?)),
9713                    None if attn.qk_norm == TensorPresence::Required => {
9714                        Err(format!("qwen4exp_gpu: layer {} missing qk norm", layer.index).into())
9715                    }
9716                    None => Ok(None),
9717                }
9718            };
9719            let wq_t = expect(weights, &layer_id(layer.index, LayerTensor::Query))?;
9720            let wk_t = expect(weights, &layer_id(layer.index, LayerTensor::Key))?;
9721            let wv_t = expect(weights, &layer_id(layer.index, LayerTensor::Value))?;
9722            let wo_t = expect(
9723                weights,
9724                &layer_id(layer.index, LayerTensor::AttentionOutput),
9725            )?;
9726            let o_in = (attn.query_heads * attn.key_head_dim) as usize;
9727            MixerW::Qsa(QsaW {
9728                attn: attn.clone(),
9729                overlay,
9730                yarn,
9731                proj_b16: bf16_stack_twin(e, &[&wq_t.data, &wk_t.data, &wv_t.data], hidden)?,
9732                wo_b16: bf16_twin(e, &wo_t.data, o_in)?,
9733                wq: upload(e, &wq_t)?,
9734                wk: upload(e, &wk_t)?,
9735                wv: upload(e, &wv_t)?,
9736                wo: upload(e, &wo_t)?,
9737                q_norm: load_opt_norm(LayerTensor::QueryNorm)?,
9738                k_norm: load_opt_norm(LayerTensor::KeyNorm)?,
9739                idx_proj: upload(
9740                    e,
9741                    &expect(
9742                        weights,
9743                        &family_id(format!("{prefix}self_attn.indexer.index_qk_proj.weight")),
9744                    )?,
9745                )?,
9746                idx_q_norm: expect(
9747                    weights,
9748                    &family_id(format!("{prefix}self_attn.indexer.q_layernorm.weight")),
9749                )?
9750                .data,
9751                idx_k_norm: expect(
9752                    weights,
9753                    &family_id(format!("{prefix}self_attn.indexer.k_layernorm.weight")),
9754                )?
9755                .data,
9756            })
9757        }
9758        AttentionPlan::GatedDeltaNet(gdn) => {
9759            let qkv_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnQkv))?;
9760            let z_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnGate))?;
9761            let beta_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnBeta))?;
9762            let alpha_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnAlpha))?;
9763            let out_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnOutput))?;
9764            let o_in = (gdn.value_heads * gdn.value_head_dim) as usize;
9765            MixerW::Gdn(GdnW {
9766                plan: *gdn,
9767                proj_b16: bf16_stack_twin(
9768                    e,
9769                    &[&qkv_t.data, &z_t.data, &beta_t.data, &alpha_t.data],
9770                    hidden,
9771                )?,
9772                out_b16: bf16_twin(e, &out_t.data, o_in)?,
9773                qkv: upload(e, &qkv_t)?,
9774                z: upload(e, &z_t)?,
9775                beta: upload(e, &beta_t)?,
9776                alpha: upload(e, &alpha_t)?,
9777                conv_w: upload(
9778                    e,
9779                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnConv1d))?,
9780                )?,
9781                a: upload(
9782                    e,
9783                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnA))?,
9784                )?,
9785                dt: upload(
9786                    e,
9787                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnDtBias))?,
9788                )?,
9789                norm: upload(
9790                    e,
9791                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnNorm))?,
9792                )?,
9793                out: upload(e, &out_t)?,
9794            })
9795        }
9796        other => {
9797            return Err(format!(
9798                "qwen4exp_gpu: unsupported mixer {other:?} at layer {}",
9799                layer.index
9800            )
9801            .into());
9802        }
9803    };
9804    let MlpPlan::Moe(moe_plan) = &layer.mlp else {
9805        return Err(format!("qwen4exp_gpu: layer {} is not MoE", layer.index).into());
9806    };
9807    if !matches!(moe_plan.router, RouterPlan::Softmax) {
9808        return Err("qwen4exp_gpu: only the softmax router arm is implemented".into());
9809    }
9810    let shared = moe_plan
9811        .shared
9812        .as_ref()
9813        .ok_or("qwen4exp_gpu: missing shared expert plan")?;
9814    let bank = match bank_override {
9815        Some(bank) => bank,
9816        None => {
9817            let gate = expect(
9818                weights,
9819                &layer_id(layer.index, LayerTensor::MoeExpertGateBank),
9820            )?;
9821            let up = expect(
9822                weights,
9823                &layer_id(layer.index, LayerTensor::MoeExpertUpBank),
9824            )?;
9825            let down = expect(
9826                weights,
9827                &layer_id(layer.index, LayerTensor::MoeExpertDownBank),
9828            )?;
9829            let experts = moe_plan.expert_count as usize;
9830            let ff = moe_plan.expert_intermediate_size as usize;
9831            if gate.data.len() != experts * ff * hidden
9832                || up.data.len() != experts * ff * hidden
9833                || down.data.len() != experts * hidden * ff
9834            {
9835                return Err(format!(
9836                    "qwen4exp_gpu: layer {} expert bank shape mismatch",
9837                    layer.index
9838                )
9839                .into());
9840            }
9841            ExpertBank {
9842                gate: BankHalf::F32(e.htod(&gate.data)?),
9843                up: BankHalf::F32(e.htod(&up.data)?),
9844                down: BankHalf::F32(e.htod(&down.data)?),
9845            }
9846        }
9847    };
9848    let sh_gate_t = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpGate))?;
9849    let sh_up_t = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpUp))?;
9850    let sh_down_t = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpDown))?;
9851    let sff = shared.intermediate_size as usize;
9852    let router_t = expect(weights, &layer_id(layer.index, LayerTensor::MoeRouter))?;
9853    let moe = MoeW {
9854        plan: moe_plan.clone(),
9855        router_b16: bf16_twin(e, &router_t.data, hidden)?,
9856        router: upload(e, &router_t)?,
9857        bank,
9858        shared_gu_b16: bf16_stack_twin(e, &[&sh_gate_t.data, &sh_up_t.data], hidden)?,
9859        shared_down_b16: bf16_twin(e, &sh_down_t.data, sff)?,
9860        shared_gate: upload(e, &sh_gate_t)?,
9861        shared_up: upload(e, &sh_up_t)?,
9862        shared_down: upload(e, &sh_down_t)?,
9863        shared_input_gate: if shared.gated {
9864            Some(upload(
9865                e,
9866                &expect(
9867                    weights,
9868                    &layer_id(layer.index, LayerTensor::SharedMlpInputGate),
9869                )?,
9870            )?)
9871        } else {
9872            None
9873        },
9874    };
9875    let ple = match layer.ple.as_ref() {
9876        None => None,
9877        Some(ple_plan) => {
9878            let embed_dim = ple_plan.embed_dim as usize;
9879            let head_dim = ple_plan.head_embed_dim as usize;
9880            let wide = streams * hidden;
9881            let key_proj = expect(weights, &family_id(format!("{prefix}ple.key_proj.weight")))?;
9882            let conv_w = expect(weights, &family_id(format!("{prefix}ple.conv1d.weight")))?;
9883            if key_proj.data.len() != wide * embed_dim {
9884                return Err("qwen4exp_gpu: ple key_proj shape mismatch".into());
9885            }
9886            let norm_slices = |name: &str| -> Res<Vec<CudaSlice<f32>>> {
9887                let t = expect(weights, &family_id(format!("{prefix}ple.{name}.weight")))?;
9888                split_rows(&t.data, streams, hidden, 1)
9889                    .into_iter()
9890                    .map(|v| e.htod(&v))
9891                    .collect::<Result<_, _>>()
9892            };
9893            let ints = |name: &str| -> Res<Vec<i64>> {
9894                let t = expect(
9895                    weights,
9896                    &family_id(format!("{prefix}ple.ple_embedding.{name}")),
9897                )?;
9898                t.ints
9899                    .clone()
9900                    .ok_or_else(|| "qwen4exp_gpu: n-gram buffer must be I64".into())
9901            };
9902            let table = match table_override {
9903                Some(table) => table,
9904                None => {
9905                    let t = expect(
9906                        weights,
9907                        &family_id(format!("{prefix}ple.ple_embedding.ngram_embedding")),
9908                    )?;
9909                    if t.shape.len() != 2 || t.shape[1] != head_dim {
9910                        return Err("qwen4exp_gpu: n-gram table shape mismatch".into());
9911                    }
9912                    NgramTable::F32(t.data)
9913                }
9914            };
9915            Some(PleW {
9916                plan: *ple_plan,
9917                key_proj: split_rows(&key_proj.data, streams, hidden, embed_dim)
9918                    .into_iter()
9919                    .map(|v| e.htod(&v))
9920                    .collect::<Result<_, _>>()?,
9921                value_proj: upload(
9922                    e,
9923                    &expect(
9924                        weights,
9925                        &family_id(format!("{prefix}ple.value_proj.weight")),
9926                    )?,
9927                )?,
9928                norm_key: norm_slices("norm_key")?,
9929                norm_query: norm_slices("norm_query")?,
9930                norm_conv: norm_slices("norm_conv")?,
9931                conv_w: split_rows(&conv_w.data, streams, hidden, ple_plan.conv_kernel as usize)
9932                    .into_iter()
9933                    .map(|v| e.htod(&v))
9934                    .collect::<Result<_, _>>()?,
9935                multipliers: ints("layer_multipliers")?,
9936                sizes: ints("ngram_heads_vocab_sizes")?,
9937                offsets: ints("ngram_heads_offsets")?,
9938                table,
9939            })
9940        }
9941    };
9942    Ok(LayerW {
9943        index: layer.index,
9944        eps_attn: layer.pre_attention_norm.epsilon,
9945        eps_mlp: layer.pre_mlp_norm.epsilon,
9946        attn_gate,
9947        mlp_gate,
9948        mixer,
9949        moe,
9950        ple,
9951    })
9952}
9953
9954/// Build the MTP draft block (SEMANTICS.md §MTP): fusion glue + the one decoder layer +
9955/// the draft's own exit mixer. The lm_head is SHARED with the trunk (`self.output`).
9956#[allow(clippy::too_many_arguments)]
9957fn build_mtp_w(
9958    e: &Engine,
9959    weights: &ReferenceWeights,
9960    block: &memra_gguf::model_plan::MtpBlockPlan,
9961    streams: usize,
9962    hidden: usize,
9963    rank: usize,
9964    bank_override: Option<ExpertBank>,
9965) -> Res<MtpW> {
9966    use memra_gguf::tensor_contract::MtpTensor;
9967    if block.input.fusion != memra_gguf::model_plan::MtpFusionPlan::SeparateProjections {
9968        return Err("qwen4exp_gpu: MTP block is not the separate-projections family".into());
9969    }
9970    let wide = streams * hidden;
9971    let depth = block.depth;
9972    let mtp_id = |tensor: MtpTensor| TensorId::Mtp { depth, tensor };
9973    let pre_e = expect(weights, &mtp_id(MtpTensor::EmbeddingNorm))?;
9974    let pre_h = expect(weights, &mtp_id(MtpTensor::HiddenNorm))?;
9975    let fc_e = expect(weights, &mtp_id(MtpTensor::EmbeddingProjection))?;
9976    let fc_h = expect(weights, &mtp_id(MtpTensor::HiddenProjection))?;
9977    if pre_e.data.len() != hidden
9978        || pre_h.data.len() != wide
9979        || fc_e.data.len() != hidden * hidden
9980        || fc_h.data.len() != hidden * hidden
9981    {
9982        return Err("qwen4exp_gpu: MTP fusion tensor shape mismatch".into());
9983    }
9984    let prefix = format!("mtp.layers.{depth}.");
9985    let layer = build_layer_w(
9986        e,
9987        weights,
9988        &block.layer,
9989        &prefix,
9990        streams,
9991        hidden,
9992        rank,
9993        bank_override,
9994        None,
9995    )?;
9996    let mixer = load_gate(
9997        e,
9998        weights,
9999        "mtp.hyper_connection_mixer.",
10000        "",
10001        streams,
10002        hidden,
10003        rank,
10004        false,
10005    )?;
10006    Ok(MtpW {
10007        eps_embed: block.input.embedding_norm.epsilon,
10008        eps_hidden: block.input.hidden_norm.epsilon,
10009        fc_embed_b16: bf16_twin(e, &fc_e.data, hidden)?,
10010        fc_hidden_b16: bf16_twin(e, &fc_h.data, hidden)?,
10011        pre_norm_embed: upload(e, &pre_e)?,
10012        pre_norm_hidden: upload(e, &pre_h)?,
10013        fc_embed: upload(e, &fc_e)?,
10014        fc_hidden: upload(e, &fc_h)?,
10015        layer,
10016        mixer,
10017    })
10018}
10019
10020impl Qwen4ExpGpu {
10021    /// Build the eager model from TensorId-keyed reference weights (the deterministic tiny
10022    /// fixture, or a checkpoint materialized through `read_checkpoint`'s binding walk).
10023    /// Effective (already-folded) norm weights; reference layout throughout.
10024    pub fn from_reference_weights(
10025        e: &Engine,
10026        plan: &ModelPlan,
10027        weights: &ReferenceWeights,
10028    ) -> Res<Self> {
10029        Self::from_reference_weights_with(e, None, plan, weights, ExternalParts::default())
10030    }
10031
10032    fn from_reference_weights_with(
10033        e: &Engine,
10034        // Card-1 draft placement (mtp10): when given, the MTP block's device tensors and
10035        // a private lm-head copy build on THIS engine instead of `e`.
10036        draft_e: Option<&Engine>,
10037        plan: &ModelPlan,
10038        weights: &ReferenceWeights,
10039        mut parts: ExternalParts,
10040    ) -> Res<Self> {
10041        let hidden = plan.hidden_size as usize;
10042        let vocab = plan.vocab_size as usize;
10043        let Some(mixer_plan) = plan.exit_mixer else {
10044            return Err("qwen4exp_gpu requires the gated-residual exit mixer".into());
10045        };
10046        let streams = mixer_plan.streams as usize;
10047        if streams > PLANE_SLOTS.len() {
10048            return Err("qwen4exp_gpu: hc_count exceeds the step-workspace slot table".into());
10049        }
10050        let rank = mixer_plan.bottleneck_rank as usize;
10051        if !plan.logits.is_empty() {
10052            return Err("qwen4exp_gpu: logits transforms are not part of this family".into());
10053        }
10054
10055        let embed = expect(weights, &TensorId::TokenEmbedding)?;
10056        if embed.data.len() != vocab * hidden {
10057            return Err("qwen4exp_gpu: embedding shape mismatch".into());
10058        }
10059        let (output, output_b16) = match weights.get(&TensorId::OutputProjection) {
10060            Some(tensor) => (e.htod(&tensor.data)?, bf16_twin(e, &tensor.data, hidden)?),
10061            None => (e.htod(&embed.data)?, bf16_twin(e, &embed.data, hidden)?),
10062        };
10063
10064        let mut layers = Vec::with_capacity(plan.layers.len());
10065        for layer in &plan.layers {
10066            let prefix = format!("trunk.layers.{}.", layer.index);
10067            layers.push(build_layer_w(
10068                e,
10069                weights,
10070                layer,
10071                &prefix,
10072                streams,
10073                hidden,
10074                rank,
10075                parts.expert_banks.remove(&layer.index),
10076                parts.ngram_tables.remove(&layer.index),
10077            )?);
10078        }
10079        // The MTP draft block (mtp-spec lane): built when its rows are present in the
10080        // materialized weights — presence-driven, so the deterministic fixture carries
10081        // it and a checkpoint loaded without `LoadOptions::load_mtp` skips it.
10082        let mtp = match plan.mtp_blocks.first() {
10083            Some(block)
10084                if weights
10085                    .get(&TensorId::Mtp {
10086                        depth: block.depth,
10087                        tensor: memra_gguf::tensor_contract::MtpTensor::EmbeddingProjection,
10088                    })
10089                    .is_some() =>
10090            {
10091                Some(build_mtp_w(
10092                    draft_e.unwrap_or(e),
10093                    weights,
10094                    block,
10095                    streams,
10096                    hidden,
10097                    rank,
10098                    parts.expert_banks.remove(&block.layer.index),
10099                )?)
10100            }
10101            _ => None,
10102        };
10103        // Card-1 lm-head copy for the dev1 draft: the SAME f32 rows and the SAME bf16
10104        // twin bytes as card 0's head, so the draft head program is verbatim.
10105        let mtp_dev1 = match (draft_e, mtp.as_ref()) {
10106            (Some(de), Some(_)) => {
10107                let head_data: &[f32] = match weights.get(&TensorId::OutputProjection) {
10108                    Some(tensor) => &tensor.data,
10109                    None => &embed.data,
10110                };
10111                Some(MtpDev1 {
10112                    dev: de.ctx().ordinal(),
10113                    output: de.htod(head_data)?,
10114                    output_b16: bf16_twin(de, head_data, hidden)?,
10115                })
10116            }
10117            (Some(_), None) => {
10118                return Err(
10119                    "qwen4exp_gpu: a draft engine was given but no mtp.* rows were \
10120                     materialized (LoadOptions::load_mtp)"
10121                        .into(),
10122                );
10123            }
10124            _ => None,
10125        };
10126        let exit_mixer = load_gate(
10127            e,
10128            weights,
10129            "trunk.hyper_connection_mixer.",
10130            "",
10131            streams,
10132            hidden,
10133            rank,
10134            false,
10135        )?;
10136        Ok(Self {
10137            plan: plan.clone(),
10138            hidden,
10139            streams,
10140            vocab,
10141            embed_host: embed.data,
10142            output,
10143            output_b16,
10144            layers,
10145            exit_mixer,
10146            exit_eps: plan.output_norm.epsilon,
10147            mtp,
10148            mtp_dev1,
10149            draft_trim: None,
10150            draft_trim_parked: None,
10151            chain_embed: None,
10152        })
10153    }
10154
10155    /// Arm the FR-Spec draft-head trim (mtp9): gather the `ids` rows of the SHARED lm head
10156    /// into a [n, hidden] trimmed head, D2D — same bytes, so every trimmed logit is
10157    /// bit-identical to its full-vocab twin. `ids` is the own-gen rank list in rank order
10158    /// (most frequent first); duplicates and out-of-range ids are rejected.
10159    ///
10160    /// Arming changes what the DRAFT can propose (acceptance), never what the model
10161    /// commits: the verify chunk is full-vocab and the accept walk compares against it.
10162    pub fn build_draft_trim(&mut self, e: &Engine, ids: &[u32]) -> Res<()> {
10163        // Card-1 placement: the trim gathers from the DEV1 head copy (same bytes as
10164        // card 0's) and its rows live beside the draft — `e` must be the draft engine.
10165        self.check_draft_engine(e)?;
10166        let n = ids.len();
10167        if n == 0 || n > self.vocab {
10168            return Err(format!("qwen4exp_gpu: draft trim wants 1..={} ids", self.vocab).into());
10169        }
10170        let mut seen = vec![false; self.vocab];
10171        for &id in ids {
10172            let id = id as usize;
10173            if id >= self.vocab {
10174                return Err(format!("qwen4exp_gpu: draft trim id {id} out of vocab").into());
10175            }
10176            if std::mem::replace(&mut seen[id], true) {
10177                return Err(format!("qwen4exp_gpu: draft trim id {id} repeats").into());
10178            }
10179        }
10180        let hidden = self.hidden;
10181        let (src_f32, src_b16) = match self.mtp_dev1.as_ref() {
10182            Some(d) => (&d.output, d.output_b16.as_ref()),
10183            None => (&self.output, self.output_b16.as_ref()),
10184        };
10185        // Gather the bf16 twin when it exists (the arm the trunk seam runs) and SKIP the
10186        // f32 gather entirely — at N=32768 that is 168 MB instead of 503 MB, and the f32
10187        // arm would be dead residency. No twin => gather f32, the only arm available.
10188        let (head_b16, head) = match src_b16 {
10189            Some(full) => {
10190                let mut trim = e.alloc_u8_uninit(n * hidden * 2)?;
10191                for (row, &id) in ids.iter().enumerate() {
10192                    e.copy_u8_range_into(
10193                        &mut trim,
10194                        row * hidden * 2,
10195                        full,
10196                        id as usize * hidden * 2,
10197                        hidden * 2,
10198                    )?;
10199                }
10200                (Some(trim), None)
10201            }
10202            None => {
10203                let mut head = e.uninit(n * hidden)?;
10204                for (row, &id) in ids.iter().enumerate() {
10205                    e.copy_range_into(
10206                        &mut head,
10207                        row * hidden,
10208                        src_f32,
10209                        id as usize * hidden,
10210                        hidden,
10211                    )?;
10212                }
10213                (None, Some(head))
10214            }
10215        };
10216        self.draft_trim = Some(DraftTrim {
10217            n,
10218            d2t: ids.to_vec(),
10219            head,
10220            head_b16,
10221        });
10222        self.draft_trim_parked = None;
10223        Ok(())
10224    }
10225
10226    /// Flip a BUILT trim between live and parked (the interleaved A/B's two arms) without
10227    /// reallocating the gathered head. No-op when no trim was ever built.
10228    pub fn set_draft_trim(&mut self, on: bool) {
10229        if on {
10230            if let Some(t) = self.draft_trim_parked.take() {
10231                self.draft_trim = Some(t);
10232            }
10233        } else if let Some(t) = self.draft_trim.take() {
10234            self.draft_trim_parked = Some(t);
10235        }
10236    }
10237
10238    /// Drop the draft trim entirely (both live and parked).
10239    pub fn clear_draft_trim(&mut self) {
10240        self.draft_trim = None;
10241        self.draft_trim_parked = None;
10242    }
10243
10244    /// Arm the deferred-chain embed table (mtp11, `SpecOpts::defer`): the chain's
10245    /// next-step embed rows, resident on the DRAFT engine, so the device argmax feeds
10246    /// the next chain step without a host round trip (see [`ChainEmbed`] for the
10247    /// bf16-clean bit-identity contract and the trim-rank row order). Re-arm after any
10248    /// trim change — `spec_generate_ext` refuses a table whose trim state or width
10249    /// disagrees with the live draft head.
10250    pub fn arm_spec_devchain(&mut self, de: &Engine) -> Res<()> {
10251        self.check_draft_engine(de)?;
10252        let hidden = self.hidden;
10253        let (rows, for_trim) = match self.draft_trim.as_ref() {
10254            Some(tr) => (tr.n, true),
10255            None => (self.vocab, false),
10256        };
10257        let src_row = |r: usize| -> &[f32] {
10258            let id = match self.draft_trim.as_ref() {
10259                Some(tr) => tr.d2t[r] as usize,
10260                None => r,
10261            };
10262            &self.embed_host[id * hidden..(id + 1) * hidden]
10263        };
10264        // bf16-clean scan over the SELECTED rows: every value must round-trip
10265        // f32 -> bits>>16 -> bits<<16 exactly, or the table falls back to raw f32.
10266        let clean = (0..rows).all(|r| src_row(r).iter().all(|x| x.to_bits() & 0xFFFF == 0));
10267        let (bytes, qt, row_bytes) = if clean {
10268            let mut b = vec![0u8; rows * hidden * 2];
10269            for r in 0..rows {
10270                for (j, &x) in src_row(r).iter().enumerate() {
10271                    let h = (x.to_bits() >> 16) as u16;
10272                    b[(r * hidden + j) * 2..(r * hidden + j) * 2 + 2]
10273                        .copy_from_slice(&h.to_le_bytes());
10274                }
10275            }
10276            (b, crate::QT_BF16, hidden * 2)
10277        } else {
10278            let mut b = vec![0u8; rows * hidden * 4];
10279            for r in 0..rows {
10280                for (j, &x) in src_row(r).iter().enumerate() {
10281                    b[(r * hidden + j) * 4..(r * hidden + j) * 4 + 4]
10282                        .copy_from_slice(&x.to_le_bytes());
10283                }
10284            }
10285            (b, crate::QT_F32, hidden * 4)
10286        };
10287        let table = de.upload_u8(&bytes)?;
10288        println!(
10289            "[qwen4exp-spec] deferred-chain embed table armed: {} rows x {hidden} ({}, {:.1} MiB, dev {}{})",
10290            rows,
10291            if clean {
10292                "bf16 bit-clean"
10293            } else {
10294                "f32 fallback"
10295            },
10296            (rows * row_bytes) as f64 / (1024.0 * 1024.0),
10297            de.ctx().ordinal(),
10298            if for_trim { ", trim-rank order" } else { "" },
10299        );
10300        self.chain_embed = Some(ChainEmbed {
10301            table,
10302            qt,
10303            row_bytes,
10304            rows,
10305            for_trim,
10306            dev: de.ctx().ordinal(),
10307        });
10308        Ok(())
10309    }
10310
10311    /// Drop the deferred-chain embed table (frees the card-1 residency).
10312    pub fn clear_spec_devchain(&mut self) {
10313        self.chain_embed = None;
10314    }
10315
10316    /// Rows the draft's lm_head produces: the trim width when armed, else full vocab.
10317    /// Draft logits live in TRIMMED space when armed; `draft_token` maps a row back.
10318    pub fn draft_logits_width(&self) -> usize {
10319        match self.draft_trim.as_ref() {
10320            Some(t) => t.n,
10321            None => self.vocab,
10322        }
10323    }
10324
10325    /// Map a draft-logits row index back to its TARGET vocab id (identity when the trim
10326    /// is off).
10327    fn draft_token(&self, row: u32) -> Res<u32> {
10328        match self.draft_trim.as_ref() {
10329            Some(t) => t
10330                .d2t
10331                .get(row as usize)
10332                .copied()
10333                .ok_or_else(|| format!("qwen4exp_gpu: draft row {row} outside the trim").into()),
10334            None => Ok(row),
10335        }
10336    }
10337
10338    /// Trunk f32 diet (yarn-cell follow-up 3): FREE the f32 originals whose bf16 twins
10339    /// are resident — under the ship seams (trunk-bf16 + fused-gate, both default ON)
10340    /// every consumer of these tensors runs the bf16 kernels at every t, so the f32
10341    /// copies are pure dead residency (~6 GiB on card 0 at the real geometry). Each
10342    /// dropped tensor becomes a 1-element stub; every f32 fallback path guards on the
10343    /// stub and errs loudly instead of reading it (flipping the trunk seams OFF after
10344    /// the diet refuses rather than corrupting). Returns bytes freed. NOT applied to
10345    /// the MTP draft weights (card-1 slack; the reference-parity gates read them).
10346    pub fn trunk_f32_diet(&mut self, e: &Engine) -> Res<usize> {
10347        if !trunk_bf16_on() || !hc_fused_gate_on() {
10348            return Err(
10349                "qwen4exp_gpu: trunk_f32_diet requires the trunk-bf16 + fused-gate seams ON \
10350                 (the bf16 paths must be the ones serving)"
10351                    .into(),
10352            );
10353        }
10354        let mut freed = 0usize;
10355        fn stub(e: &Engine, s: &mut CudaSlice<f32>, freed: &mut usize) -> Res<()> {
10356            if s.len() > 1 {
10357                *freed += s.len() * 4;
10358                *s = e.zeros(1)?;
10359            }
10360            Ok(())
10361        }
10362        fn diet_gate(e: &Engine, g: &mut GateW, freed: &mut usize) -> Res<()> {
10363            if g.down_b16.is_none()
10364                || g.up_b16.is_none()
10365                || (g.inject.is_some() && g.inject_b16.is_none())
10366            {
10367                return Ok(()); // partial twins: keep the f32 arm whole
10368            }
10369            for s in g.down.iter_mut() {
10370                stub(e, s, freed)?;
10371            }
10372            for s in g.up.iter_mut() {
10373                stub(e, s, freed)?;
10374            }
10375            if let Some(inj) = g.inject.as_mut() {
10376                stub(e, inj, freed)?;
10377            }
10378            Ok(())
10379        }
10380        for layer in self.layers.iter_mut() {
10381            diet_gate(e, &mut layer.attn_gate, &mut freed)?;
10382            diet_gate(e, &mut layer.mlp_gate, &mut freed)?;
10383            match &mut layer.mixer {
10384                MixerW::Qsa(q) => {
10385                    if q.proj_b16.is_some() {
10386                        stub(e, &mut q.wq, &mut freed)?;
10387                        stub(e, &mut q.wk, &mut freed)?;
10388                        stub(e, &mut q.wv, &mut freed)?;
10389                    }
10390                    if q.wo_b16.is_some() {
10391                        stub(e, &mut q.wo, &mut freed)?;
10392                    }
10393                }
10394                MixerW::Gdn(g) => {
10395                    if g.proj_b16.is_some() {
10396                        stub(e, &mut g.qkv, &mut freed)?;
10397                        stub(e, &mut g.z, &mut freed)?;
10398                        stub(e, &mut g.beta, &mut freed)?;
10399                        stub(e, &mut g.alpha, &mut freed)?;
10400                    }
10401                    if g.out_b16.is_some() {
10402                        stub(e, &mut g.out, &mut freed)?;
10403                    }
10404                }
10405            }
10406            let moe = &mut layer.moe;
10407            if moe.router_b16.is_some() {
10408                stub(e, &mut moe.router, &mut freed)?;
10409            }
10410            if moe.shared_gu_b16.is_some() {
10411                stub(e, &mut moe.shared_gate, &mut freed)?;
10412                stub(e, &mut moe.shared_up, &mut freed)?;
10413            }
10414            if moe.shared_down_b16.is_some() {
10415                stub(e, &mut moe.shared_down, &mut freed)?;
10416            }
10417        }
10418        diet_gate(e, &mut self.exit_mixer, &mut freed)?;
10419        if self.output_b16.is_some() {
10420            stub(e, &mut self.output, &mut freed)?;
10421        }
10422        Ok(freed)
10423    }
10424
10425    pub fn alloc_state(&self, e: &Engine, capacity: usize) -> Res<Qwen4ExpState> {
10426        self.alloc_state_reserve(e, capacity, capacity, None)
10427    }
10428
10429    /// Long-context state: `reserve` caps the workspace-slot unit at the chunk bound
10430    /// (see `Qwen4ExpState::reserve`), and `kv_engine` optionally places the QSA KV
10431    /// caches on ANOTHER card (the kv-dev1 ladder arm: card 0 holds the trunk at
10432    /// ~90 GiB; the attention kernels read K/V over UVA P2P). `None` = same card.
10433    pub fn alloc_state_reserve(
10434        &self,
10435        e: &Engine,
10436        capacity: usize,
10437        reserve: usize,
10438        kv_engine: Option<&Engine>,
10439    ) -> Res<Qwen4ExpState> {
10440        let kv_e = kv_engine.unwrap_or(e);
10441        // Peer-resident KV is admissible only at smoke depth (see `peer_kv_max_cap`):
10442        // past the ceiling the block-list attention's scatter reads leave the reading
10443        // card's L2 behind and every selected position becomes a PCIe round trip.
10444        // Refused HERE rather than discovered as a 100%-sm / 0%-mem non-finish, which is
10445        // how memra#53 burned two cells (45 min and 113 min, no rung row either time).
10446        if kv_e.ctx().ordinal() != e.ctx().ordinal() {
10447            let limit = peer_kv_max_cap();
10448            if capacity > limit {
10449                return Err(format!(
10450                    "qwen4exp_gpu: peer-resident QSA KV refused — capacity {capacity} rows on \
10451                     device {} while the attention runs on device {} (ceiling {limit} rows, \
10452                     MEMRA_Q4E_PEER_KV_MAX_CAP). The block-list form is the only read path for a \
10453                     quantized cache and it is a scatter reader (q4e_sdpa_blocklist_q8q5 phase 1 \
10454                     is thread-per-position: 32 lanes on 32 rows, 32 sectors per load \
10455                     instruction). Peer memory is not cached in the reading card's L2, so at this \
10456                     depth ONE 2,048-token prefill chunk asks ~523 GB across the link and the run \
10457                     never finishes — it does not deadlock, it just never arrives. Keep the QSA KV \
10458                     on the compute card: it is 10,368 B/row across the 12 QSA layers (2.7 GiB at \
10459                     262,144), while the allocation that forces a second card is the MTP draft \
10460                     state (~17.6 GiB), which --mtp-dev1 / load_from_dir_dev1 already places \
10461                     there.",
10462                    kv_e.ctx().ordinal(),
10463                    e.ctx().ordinal(),
10464                )
10465                .into());
10466            }
10467        }
10468        let mut layers = Vec::with_capacity(self.layers.len());
10469        for layer in &self.layers {
10470            let mixer = match &layer.mixer {
10471                MixerW::Qsa(qsa) => {
10472                    let kv_width = qsa.attn.kv_heads as usize * qsa.attn.key_head_dim as usize;
10473                    let v_width = qsa.attn.kv_heads as usize * qsa.attn.value_head_dim as usize;
10474                    // kvq/idxq lanes: the storage format latches PER STATE here (a byte
10475                    // cache cannot flip mid-run; the A/B harness allocates per arm).
10476                    let kv = if kv_quant_on() {
10477                        QsaKvStore::Q8Q5 {
10478                            k: kv_e.alloc_u8(capacity * q8_row_bytes(kv_width))?,
10479                            v: kv_e.alloc_u8(capacity * q5_row_bytes(v_width))?,
10480                        }
10481                    } else {
10482                        QsaKvStore::F32 {
10483                            k: kv_e.zeros(capacity * kv_width)?,
10484                            v: kv_e.zeros(capacity * v_width)?,
10485                        }
10486                    };
10487                    MixerState::Qsa {
10488                        kv,
10489                        raw_keys: IdxRawCache::new(idxq_mode()),
10490                        pooled_keys: Vec::new(),
10491                        pooled_dev: None,
10492                        pooled_dev_rows: 0,
10493                        raw_dev: None,
10494                        raw_dev_rows: 0,
10495                        idx_audit: (idxq_mode() != IdxQMode::F32 && idxq_audit_on()).then(|| {
10496                            Box::new(IdxAudit {
10497                                raw_f32: IdxRawCache::F32(Vec::new()),
10498                                pooled_f32: Vec::new(),
10499                            })
10500                        }),
10501                    }
10502                }
10503                MixerW::Gdn(gdn) => {
10504                    let p = &gdn.plan;
10505                    let conv_dim = 2 * (p.key_heads * p.key_head_dim) as usize
10506                        + (p.value_heads * p.value_head_dim) as usize;
10507                    let pad = p.conv_kernel as usize - 1;
10508                    MixerState::Gdn {
10509                        conv: e.zeros(pad * conv_dim)?,
10510                        state: e
10511                            .zeros((p.value_heads * p.value_head_dim * p.key_head_dim) as usize)?,
10512                    }
10513                }
10514            };
10515            let ple = match layer.ple.as_ref() {
10516                None => None,
10517                Some(ple) => {
10518                    let pad = (ple.plan.conv_kernel as usize - 1) * ple.plan.max_ngram as usize;
10519                    let mut conv_hist = Vec::with_capacity(self.streams);
10520                    for _ in 0..self.streams {
10521                        conv_hist.push(e.zeros(pad * self.hidden)?);
10522                    }
10523                    Some(PleState {
10524                        conv_hist,
10525                        ngram_ids: Vec::new(),
10526                        ngram_history: Vec::new(),
10527                        ngram_last_eos: -1,
10528                    })
10529                }
10530            };
10531            layers.push(LayerState { mixer, ple });
10532        }
10533        Ok(Qwen4ExpState {
10534            pos: 0,
10535            capacity,
10536            reserve,
10537            tokens: Vec::new(),
10538            layers,
10539            ws: StepPool::default(),
10540            graphs: StepGraphs::default(),
10541            tp2: None,
10542            verify: None,
10543        })
10544    }
10545
10546    /// Prefill `ids` from the state's current position. Returns [t, vocab] logits (host).
10547    pub fn prefill(&self, e: &Engine, ids: &[u32], state: &mut Qwen4ExpState) -> Res<Vec<f32>> {
10548        self.forward(e, ids, state, None)
10549    }
10550
10551    /// LONG-context chunked prefill: forward `ids` in `chunk`-sized pieces from the
10552    /// state's current position, skipping the exit mixer + lm_head on every chunk but
10553    /// materializing ONLY the final row's logits at the end. State-identical to one big
10554    /// `prefill` (the head reads no state and writes none); the [t, vocab] logits block
10555    /// a big chunk would otherwise materialize is the thing being skipped (16 GB at
10556    /// chunk 16384 on this vocab). Returns the LAST row's logits [vocab].
10557    pub fn prefill_extend(
10558        &self,
10559        e: &Engine,
10560        ids: &[u32],
10561        state: &mut Qwen4ExpState,
10562        chunk: usize,
10563    ) -> Res<Vec<f32>> {
10564        if ids.is_empty() || chunk == 0 {
10565            return Err("qwen4exp_gpu: prefill_extend needs ids and a chunk size".into());
10566        }
10567        let mut last = Vec::new();
10568        for piece in ids.chunks(chunk) {
10569            let is_last =
10570                piece.as_ptr() as usize + piece.len() * 4 == ids.as_ptr() as usize + ids.len() * 4;
10571            let head = if is_last {
10572                HeadMode::LastRow
10573            } else {
10574                HeadMode::Skip
10575            };
10576            last = self.forward_with(e, piece, state, None, head)?;
10577        }
10578        Ok(last)
10579    }
10580
10581    /// One incremental decode step (no prompt recompute). Returns [vocab] logits (host).
10582    pub fn decode_step(&self, e: &Engine, token: u32, state: &mut Qwen4ExpState) -> Res<Vec<f32>> {
10583        self.forward(e, &[token], state, None)
10584    }
10585
10586    /// Prefill with per-layer parity capture (the transformers hidden-goldens hook
10587    /// points): post-layer WIDE rows per trunk layer + the exit mixer output.
10588    pub fn prefill_captured(
10589        &self,
10590        e: &Engine,
10591        ids: &[u32],
10592        state: &mut Qwen4ExpState,
10593    ) -> Res<(Vec<f32>, PrefillCapture)> {
10594        let mut capture = PrefillCapture {
10595            layer_wide: Vec::with_capacity(self.layers.len()),
10596            exit_mixed: Vec::new(),
10597        };
10598        let logits = self.forward(e, ids, state, Some(&mut capture))?;
10599        Ok((logits, capture))
10600    }
10601
10602    /// Interleave stream-major planes into token-major wide rows [t, streams*hidden]
10603    /// (the HF wide-stream layout: token row = concat over streams).
10604    fn planes_to_wide(&self, e: &Engine, planes: &[CudaSlice<f32>], t: usize) -> Res<Vec<f32>> {
10605        let hidden = self.hidden;
10606        let wide = self.streams * hidden;
10607        let mut out = vec![0.0f32; t * wide];
10608        for (s, plane) in planes.iter().enumerate() {
10609            // Slice: workspace planes are reserve-sized (>= t*hidden).
10610            let host = e.dtoh_view(&plane.slice(0..t * hidden))?;
10611            for row in 0..t {
10612                out[row * wide + s * hidden..row * wide + (s + 1) * hidden]
10613                    .copy_from_slice(&host[row * hidden..(row + 1) * hidden]);
10614            }
10615        }
10616        Ok(out)
10617    }
10618
10619    fn forward(
10620        &self,
10621        e: &Engine,
10622        ids: &[u32],
10623        state: &mut Qwen4ExpState,
10624        capture: Option<&mut PrefillCapture>,
10625    ) -> Res<Vec<f32>> {
10626        self.forward_with(e, ids, state, capture, HeadMode::All)
10627    }
10628
10629    fn forward_with(
10630        &self,
10631        e: &Engine,
10632        ids: &[u32],
10633        state: &mut Qwen4ExpState,
10634        mut capture: Option<&mut PrefillCapture>,
10635        head: HeadMode,
10636    ) -> Res<Vec<f32>> {
10637        let t = ids.len();
10638        let hidden = self.hidden;
10639        if t == 0 {
10640            return Err("qwen4exp_gpu: empty input".into());
10641        }
10642        if head != HeadMode::All {
10643            // Head-skipping forwards are a chunked-prefill shape: goldens capture wants
10644            // every row, and a verify-EXACT chunk (t <= k_cap) or a t == 1 step feeds
10645            // the argmax sink from the full logits block. Big verify-armed chunks are
10646            // fine — the wide capture happens before the head, and the spec co-prefill
10647            // is exactly this shape.
10648            if capture.is_some() {
10649                return Err("qwen4exp_gpu: prefill capture wants every logits row".into());
10650            }
10651            if let Some(v) = state.verify.as_ref()
10652                && (t == 1 || t <= v.k_cap)
10653            {
10654                return Err(
10655                    "qwen4exp_gpu: head-skipping forward on a verify-exact chunk shape".into(),
10656                );
10657            }
10658        }
10659        if state.pos + t > state.capacity {
10660            return Err("qwen4exp_gpu: state capacity exceeded".into());
10661        }
10662        if state.tp2.is_some() {
10663            return Err(
10664                "qwen4exp_gpu: state already decoded in TP2 mode; single-card forward \
10665                 requires a fresh state (the half-state migration is one-way)"
10666                    .into(),
10667            );
10668        }
10669        let base_pos = state.pos;
10670        state.tokens.extend_from_slice(ids);
10671        // A multi-token chunk can GROW workspace slots (reallocation) — any captured
10672        // graph would keep the stale baked addresses, so invalidate them first.
10673        if t > 1 {
10674            state.graphs = StepGraphs::default();
10675        }
10676        // Decode graphs never engage on an ARMED-verify state (mtp11): the graphs tail
10677        // (`forward_graphs_tail`) carries neither the wide capture nor the argmax sink,
10678        // so two consecutive t == 1 forwards with verify armed (= consecutive zero-draft
10679        // rounds under the p-min guard) would route the second through the tail and skip
10680        // the wide row the next replay seeds from — an acceptance-only degradation the
10681        // byte-identity gates cannot see (the mtp11 audit's found-while-auditing item).
10682        let graphs_mode = t == 1
10683            && decode_graphs_on()
10684            && step_ws_on()
10685            && hc_fused_gate_on()
10686            && !prof::on()
10687            && capture.is_none()
10688            && state.verify.is_none();
10689        let tokens = &state.tokens;
10690        let ws = &mut state.ws;
10691        // Verify instrument (mtp-spec lane): while armed, capture the final wide rows
10692        // every forward; 1 < t <= k_cap chunks additionally run the EXACT row programs
10693        // (each row bit-identical to t == 1 decode) and stash per-column GDN/PLE state.
10694        let verify = state.verify.as_mut();
10695        let (exact, vfused, stash_gdn, stash_ple, stash_wide, argmax_sink, last_row_only) =
10696            match verify {
10697                Some(v) => {
10698                    // Verify chunks NEVER include the prefill (base_pos == 0): a
10699                    // prompt shorter than k_cap would otherwise prefill through the
10700                    // per-row DECODE programs while the plain baseline prefills FUSED —
10701                    // bit-different state from token 0 that drifts until the first
10702                    // thin-margin argmax flips. Found by the mtp11 256-token battery
10703                    // (raw prompt 2, len 6, K=5: k_cap 6 >= 6 -> exact prefill ->
10704                    // divergence at gen 157; K<=4 fused the same prefill and passed);
10705                    // latent since mtp-spec (every green spec-gate ran 64 tokens, and
10706                    // the tiny fixture's 18-token prompt never fit inside k_cap).
10707                    // The `vfuse` cost instrument moves the SAME chunk shape onto the
10708                    // fused program; it does not widen the shape, so this gen-157 rule
10709                    // holds unchanged on both arms.
10710                    let vchunk = base_pos > 0 && t > 1 && t <= v.k_cap;
10711                    let vfused = vchunk && verify_fused_on();
10712                    let exact = vchunk && !vfused;
10713                    // mtp11 deferred round: the t == 1 steps (zero-draft verify, dynk
10714                    // plain tail) take the argmax fast path too — same sink, same
10715                    // bit-identical device argmax, a 4-byte dtoh instead of ~1 MB.
10716                    let amx_t1 = t == 1 && v.want_argmax_t1;
10717                    if exact {
10718                        v.chunk = Some((base_pos, t));
10719                        v.argmax.clear();
10720                    } else if (vfused || amx_t1) && v.want_argmax {
10721                        v.argmax.clear();
10722                    }
10723                    if vfused {
10724                        // Rewind has no per-column stash to restore from on this arm —
10725                        // record the shape so `verify_rewind` can refuse by NAME instead
10726                        // of reporting "no live verify chunk" and reading like a bug.
10727                        v.fused_chunk = Some((base_pos, t));
10728                    }
10729                    (
10730                        exact,
10731                        vfused,
10732                        Some(&mut v.gdn),
10733                        Some(&mut v.ple),
10734                        Some((&mut v.wide, v.ring_rows)),
10735                        // The fused arm feeds the SAME argmax sink, so the A/B compares
10736                        // programs and not readback sizes (a full [t, vocab] dtoh on one
10737                        // arm only would be ~6 MB of measured noise at t=6).
10738                        if (exact || vfused || amx_t1) && v.want_argmax {
10739                            Some((&mut v.argmax, &mut v.toks))
10740                        } else {
10741                            None
10742                        },
10743                        v.last_row_only && t > 1 && !exact && !vfused,
10744                    )
10745                }
10746                None => (false, false, None, None, None, None, false),
10747            };
10748        let mut stash_gdn = stash_gdn;
10749        let mut stash_ple = stash_ple;
10750        // Slot RESERVE unit: reserve-derived so a growing decode never reallocates a
10751        // slot mid-run (address stability, item 2b's prerequisite). Transients scale
10752        // with the CHUNK length t; `reserve` = capacity by default, but a LONG-context
10753        // state (alloc_state_reserve) caps it at the chunk bound — a 1M-capacity state
10754        // must not reserve 1M-token transients (plane slots alone would be ~41 GB).
10755        let cap = state.reserve.max(t);
10756
10757        // Entry: wide stream = `streams` copies of the embedding (modular L1012), held as
10758        // stream-major planes so every per-stream op is a contiguous existing kernel.
10759        let mut planes = prof_section(e, "entry.embed", || {
10760            let mut embedded = vec![0.0f32; t * hidden];
10761            for (row, &token) in ids.iter().enumerate() {
10762                let token = token as usize;
10763                if token >= self.vocab {
10764                    return Err(format!("qwen4exp_gpu: token {token} out of range").into());
10765                }
10766                embedded[row * hidden..(row + 1) * hidden]
10767                    .copy_from_slice(&self.embed_host[token * hidden..(token + 1) * hidden]);
10768            }
10769            let embedded_dev = ws.take_f32_h2d(e, "entry.embed", &embedded, cap * hidden)?;
10770            let mut planes: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
10771            for s in 0..self.streams {
10772                let mut plane = ws.take_f32(e, PLANE_SLOTS[s], t * hidden, cap * hidden)?;
10773                e.copy_into(&mut plane, 0, &embedded_dev, t * hidden)?;
10774                planes.push(plane);
10775            }
10776            ws.put_f32("entry.embed", embedded_dev);
10777            Ok(planes)
10778        })?;
10779
10780        // Plane pointer table for the stream-batched kernels (hcmicro): refreshed every
10781        // step (eagerly, outside any graph) into a stable slot the captured launches
10782        // read at run time.
10783        let ptr_vals: Vec<u64> = {
10784            let stream = e.gpu.stream();
10785            planes.iter().map(|p| p.device_ptr(&stream).0).collect()
10786        };
10787        let ptrs = ws.take_u64_h2d(e, "hc.ptrs", &ptr_vals, 0)?;
10788
10789        if graphs_mode {
10790            if state.graphs.warm {
10791                return self.forward_graphs_tail(e, state, planes, ptrs, base_pos);
10792            }
10793            // First graph-eligible step: run EAGER to warm/park every slot (allocations
10794            // inside a capture region become graph mem nodes); capture starts next step.
10795            state.graphs.warm = true;
10796        }
10797
10798        for (li, (layer, lstate)) in self.layers.iter().zip(state.layers.iter_mut()).enumerate() {
10799            if let (Some(ple), Some(ple_state)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
10800                let ps = if exact {
10801                    stash_ple
10802                        .as_mut()
10803                        .and_then(|v| v.get_mut(li))
10804                        .and_then(|s| s.as_mut())
10805                } else {
10806                    None
10807                };
10808                self.ple_block(
10809                    e,
10810                    layer,
10811                    ple,
10812                    &ple.table,
10813                    ple_state,
10814                    &mut planes,
10815                    tokens,
10816                    t,
10817                    exact,
10818                    ps,
10819                )?;
10820            }
10821            let (mixed, inject) = prof_section(e, "hyper.read", || {
10822                self.gate_read(
10823                    e,
10824                    ws,
10825                    &ptrs,
10826                    &layer.attn_gate,
10827                    &planes,
10828                    t,
10829                    layer.eps_attn,
10830                    exact,
10831                )
10832            })?;
10833            let block_out = match &layer.mixer {
10834                MixerW::Qsa(qsa) => self.qsa_forward(
10835                    e,
10836                    ws,
10837                    layer,
10838                    qsa,
10839                    &mixed,
10840                    &mut lstate.mixer,
10841                    base_pos,
10842                    t,
10843                    0,
10844                    exact,
10845                )?,
10846                MixerW::Gdn(gdn) => {
10847                    let gs = if exact {
10848                        stash_gdn
10849                            .as_mut()
10850                            .and_then(|v| v.get_mut(li))
10851                            .and_then(|s| s.as_mut())
10852                    } else {
10853                        None
10854                    };
10855                    self.gdn_forward(e, ws, layer, gdn, &mixed, &mut lstate.mixer, t, gs)?
10856                }
10857            };
10858            ws.put_f32("hc.mixed", mixed);
10859            prof_section(e, "hyper.write", || {
10860                self.gate_write(e, &mut planes, &ptrs, &block_out, &inject, t)
10861            })?;
10862            ws.put_f32("mixer.out", block_out);
10863            put_inject(ws, inject);
10864            let (mixed, inject) = prof_section(e, "hyper.read", || {
10865                self.gate_read(
10866                    e,
10867                    ws,
10868                    &ptrs,
10869                    &layer.mlp_gate,
10870                    &planes,
10871                    t,
10872                    layer.eps_mlp,
10873                    exact,
10874                )
10875            })?;
10876            // Chunked long-context prefill (head-skipping forwards) rides the GROUPED
10877            // MoE program like verify chunks do: the per-expert prefill executor pays
10878            // 3 dequants + several small syncing H2Ds + GEMMs PER ROUTED EXPERT per
10879            // chunk (~512 x 48 per chunk = minutes/chunk measured on the smoke ladder);
10880            // the grouped path is 2 launches + t combines per layer on NVFP4 banks.
10881            // Decode-class rows (per-slot programs bit-identical to t == 1) — the
10882            // chunked-prefill gates are tolerance-class by design.
10883            // `prefill_grouped_all_on()` is the TP2 class gate's PRIME instrument (default
10884            // OFF = today's behavior exactly): it lets an all-rows single-card forward run
10885            // the GROUPED executor so a TP2 comparison isolates the expert-half split
10886            // instead of straddling it and the executor difference. See the flag's doc.
10887            // `vfused` forces grouped too: the MoE routed union is ALREADY one grouped
10888            // gufuse launch over every verify column on the exact arm, so letting a fused
10889            // verify chunk fall into the per-expert prefill executor would measure that
10890            // executor (minutes/chunk, above) instead of the fusion. Identical MoE program
10891            // on both arms is also the honest cost model — this section cannot be a vfuse
10892            // win, and the A/B must not pretend otherwise in either direction.
10893            let grouped = exact || vfused || head != HeadMode::All || prefill_grouped_all_on();
10894            let mlp = self.moe_forward(e, ws, &layer.moe, &mixed, t, grouped, layer.index)?;
10895            ws.put_f32("hc.mixed", mixed);
10896            prof_section(e, "hyper.write", || {
10897                self.gate_write(e, &mut planes, &ptrs, &mlp, &inject, t)
10898            })?;
10899            ws.put_f32("moe.out", mlp);
10900            put_inject(ws, inject);
10901            if let Some(capture) = capture.as_deref_mut() {
10902                capture.layer_wide.push(self.planes_to_wide(e, &planes, t)?);
10903            }
10904        }
10905
10906        // Verify wide capture: the trunk's FINAL wide rows at their absolute positions,
10907        // ring-slotted (row % ring_rows; ring == capacity is the historical identity
10908        // layout) — the draft's hidden seeds (SEMANTICS.md §MTP).
10909        if let Some((wide_buf, ring_rows)) = stash_wide {
10910            let wide = self.streams * hidden;
10911            for (s, plane) in planes.iter().enumerate() {
10912                for tok in 0..t {
10913                    e.copy_range_into(
10914                        wide_buf,
10915                        ((base_pos + tok) % ring_rows) * wide + s * hidden,
10916                        plane,
10917                        tok * hidden,
10918                        hidden,
10919                    )?;
10920                }
10921            }
10922        }
10923
10924        // Head skip (chunked long-context prefill): the exit mixer + lm_head read no
10925        // state and write none — a mid-prefill chunk stops here, state-identical.
10926        if head == HeadMode::Skip {
10927            ws.put_u64("hc.ptrs", ptrs);
10928            state.pos += t;
10929            for (s, plane) in planes.into_iter().enumerate() {
10930                ws.put_f32(PLANE_SLOTS[s], plane);
10931            }
10932            return Ok(Vec::new());
10933        }
10934
10935        // Exit downmix replaces the final norm (SEMANTICS.md §Layer stack).
10936        let x = prof_section(e, "exit.mixer", || {
10937            Ok(self
10938                .gate_read_inner(
10939                    e,
10940                    ws,
10941                    &ptrs,
10942                    &self.exit_mixer,
10943                    &planes,
10944                    t,
10945                    self.exit_eps,
10946                    false,
10947                    exact,
10948                )?
10949                .0)
10950        })?;
10951        ws.put_u64("hc.ptrs", ptrs);
10952        if let Some(capture) = capture.as_deref_mut() {
10953            capture.exit_mixed = e.dtoh(&x)?;
10954        }
10955        // LastRow (chunked prefill's final chunk): lm_head on ONE row — a [t, vocab]
10956        // logits block at long-context chunk sizes is gigabytes.
10957        let head_rows = if head == HeadMode::LastRow { 1 } else { t };
10958        let logits = prof_section(e, "lm_head", || {
10959            let mut logits =
10960                ws.take_f32(e, "logits", head_rows * self.vocab, head_rows * self.vocab)?;
10961            let x_head = if head == HeadMode::LastRow {
10962                let mut last = ws.take_f32(e, "exit.last", hidden, hidden)?;
10963                e.copy_range_into(&mut last, 0, &x, (t - 1) * hidden, hidden)?;
10964                last
10965            } else {
10966                x
10967            };
10968            linear_trunk_into(
10969                e,
10970                &self.output,
10971                &self.output_b16,
10972                &x_head,
10973                &mut logits,
10974                head_rows,
10975                hidden,
10976                self.vocab,
10977            )?;
10978            ws.put_f32(
10979                if head == HeadMode::LastRow {
10980                    "exit.last"
10981                } else {
10982                    "hc.mixed"
10983                },
10984                x_head,
10985            );
10986            Ok(logits)
10987        })?;
10988        state.pos += t;
10989        if head == HeadMode::LastRow {
10990            let out = prof_section(e, "logits.dtoh", || {
10991                Ok(e.dtoh_view(&logits.slice(0..self.vocab))?)
10992            })?;
10993            ws.put_f32("logits", logits);
10994            for (s, plane) in planes.into_iter().enumerate() {
10995                ws.put_f32(PLANE_SLOTS[s], plane);
10996            }
10997            return Ok(out);
10998        }
10999        // Verify fast path: per-row device argmax + a 4t-byte dtoh instead of the
11000        // [t, vocab] block (the spec loop reads target rows only).
11001        let out = if let Some((argmax_rows, toks)) = argmax_sink {
11002            prof_section(e, "logits.argmax", || {
11003                for row in 0..t {
11004                    e.argmax_token_device_col(&logits, row, self.vocab, toks, row)?;
11005                }
11006                let host = e.gpu.stream().clone_dtoh(&toks.slice(0..t))?;
11007                argmax_rows.extend_from_slice(&host);
11008                Ok(Vec::new())
11009            })?
11010        } else if last_row_only {
11011            // mtp11: big-t (prefill) forwards under the deferred seam dtoh ONE row —
11012            // the spec loop reads exactly one (x0). Same bytes for that row.
11013            prof_section(e, "logits.dtoh", || {
11014                Ok(e.dtoh_view(&logits.slice((t - 1) * self.vocab..t * self.vocab))?)
11015            })?
11016        } else {
11017            prof_section(e, "logits.dtoh", || {
11018                Ok(e.dtoh_view(&logits.slice(0..t * self.vocab))?)
11019            })?
11020        };
11021        ws.put_f32("logits", logits);
11022        for (s, plane) in planes.into_iter().enumerate() {
11023            ws.put_f32(PLANE_SLOTS[s], plane);
11024        }
11025        Ok(out)
11026    }
11027
11028    /// Gated-residual read gate (`gated_residual_read` twin): grouped (effective-weight)
11029    /// RMSNorm per stream, `w = sigmoid(up(silu(down(normed)/S)))`, `mixed = mean_s(w ⊙
11030    /// normed_s)`, inject scalars `2*sigmoid(block_inject(normed)/S)` per stream.
11031    #[allow(clippy::too_many_arguments)]
11032    fn gate_read(
11033        &self,
11034        e: &Engine,
11035        ws: &mut StepPool,
11036        ptrs: &CudaSlice<u64>,
11037        gate: &GateW,
11038        planes: &[CudaSlice<f32>],
11039        t: usize,
11040        eps: f32,
11041        exact: bool,
11042    ) -> Res<(CudaSlice<f32>, InjectOut)> {
11043        self.gate_read_inner(e, ws, ptrs, gate, planes, t, eps, true, exact)
11044    }
11045
11046    #[allow(clippy::too_many_arguments)]
11047    fn gate_read_inner(
11048        &self,
11049        e: &Engine,
11050        ws: &mut StepPool,
11051        ptrs: &CudaSlice<u64>,
11052        gate: &GateW,
11053        planes: &[CudaSlice<f32>],
11054        t: usize,
11055        eps: f32,
11056        with_inject: bool,
11057        // Verify-chunk exactness (mtp-spec lane): engage the DIET kernels at t > 1 so
11058        // every verify row runs the DECODE gate program verbatim per token (the diet
11059        // kernels' token dim is the t == 1 program at a plane offset — bit-identical
11060        // rows). Plain prefill keeps the fused chain (banked-goldens numerics stay).
11061        exact: bool,
11062    ) -> Res<(CudaSlice<f32>, InjectOut)> {
11063        if !hc_fused_gate_on() {
11064            return self.gate_read_legacy(e, ws, gate, planes, t, eps, with_inject);
11065        }
11066        let hidden = self.hidden;
11067        let streams = self.streams;
11068        let rank = gate_rank(gate, hidden, streams)?;
11069        let micro_norm = micro_norm_on();
11070        let micro_inj = micro_inj_on();
11071        // Hyper-gate diet (round 4): the whole read gate in THREE launches. Requires the
11072        // bf16 twins + the Slab inject posture (micro_inj — take_inject's form contract)
11073        // + real geometry; anything else falls back to the fused chain below.
11074        if hc_diet_on()
11075            && (t == 1 || exact)
11076            && trunk_bf16_on()
11077            && micro_inj
11078            && hidden % 8 == 0
11079            && rank % 8 == 0
11080            && gate.down_b16.is_some()
11081            && gate.up_b16.is_some()
11082            && (!with_inject || gate.inject_b16.is_some())
11083        {
11084            let mut parts = ws.take_f32(e, "hc.parts", t * streams * rank, 0)?;
11085            let mut injp = ws.take_f32(e, "hc.injp", t * streams * streams, 0)?;
11086            let mut inv = ws.take_f32(e, "hc.inv", t * streams, 0)?;
11087            let winj = if with_inject {
11088                gate.inject_b16.as_ref()
11089            } else {
11090                None
11091            };
11092            // Weight-shared MT stages (set_verify_mt) at verify chunks: bit-identical
11093            // per token to the token-grid stages (kernel docs + gate oracle), weight
11094            // reads 1x instead of t x.
11095            let mt = t > 1 && verify_mt_on() && (2..=12).contains(&t);
11096            if mt {
11097                launch_hc_diet_stage0_mt(e, ptrs, &mut inv, hidden, streams, t, eps)?;
11098                launch_hc_diet_stage1_mt(
11099                    e,
11100                    ptrs,
11101                    &gate.norm_stack,
11102                    &inv,
11103                    gate.down_b16.as_ref().expect("guarded above"),
11104                    winj,
11105                    &mut parts,
11106                    &mut injp,
11107                    hidden,
11108                    rank,
11109                    streams,
11110                    t,
11111                )?;
11112            } else {
11113                launch_hc_diet_stage1(
11114                    e,
11115                    ptrs,
11116                    &gate.norm_stack,
11117                    gate.down_b16.as_ref().expect("guarded above"),
11118                    winj,
11119                    &mut parts,
11120                    &mut injp,
11121                    &mut inv,
11122                    hidden,
11123                    rank,
11124                    streams,
11125                    t,
11126                    eps,
11127                )?;
11128            }
11129            let mut low_act = ws.take_f32(e, "hc.low_act", t * rank, 0)?;
11130            let mut all = ws.take_f32(e, "hc.inj_all", streams * t, 0)?;
11131            launch_hc_diet_stage2(
11132                e,
11133                &parts,
11134                &injp,
11135                &mut low_act,
11136                &mut all,
11137                rank,
11138                streams,
11139                t,
11140                with_inject,
11141            )?;
11142            let mut mixed = ws.take_f32(e, "hc.mixed", t * hidden, 0)?;
11143            if mt && (t * rank + 8 * streams * t) * 4 <= 96 * 1024 {
11144                launch_hc_diet_stage3_mt(
11145                    e,
11146                    ptrs,
11147                    &gate.norm_stack,
11148                    &inv,
11149                    gate.up_b16.as_ref().expect("guarded above"),
11150                    &low_act,
11151                    &mut mixed,
11152                    hidden,
11153                    rank,
11154                    streams,
11155                    t,
11156                )?;
11157            } else {
11158                launch_hc_diet_stage3(
11159                    e,
11160                    ptrs,
11161                    &gate.norm_stack,
11162                    &inv,
11163                    gate.up_b16.as_ref().expect("guarded above"),
11164                    &low_act,
11165                    &mut mixed,
11166                    hidden,
11167                    rank,
11168                    streams,
11169                    t,
11170                )?;
11171            }
11172            ws.put_f32("hc.parts", parts);
11173            ws.put_f32("hc.injp", injp);
11174            ws.put_f32("hc.inv", inv);
11175            ws.put_f32("hc.low_act", low_act);
11176            let inject_out = if with_inject {
11177                InjectOut::Slab(all)
11178            } else {
11179                ws.put_f32("hc.inj_all", all);
11180                InjectOut::Rows(Vec::new())
11181            };
11182            return Ok((mixed, inject_out));
11183        }
11184
11185        // Buffers are STREAM-MAJOR and CONTIGUOUS ([streams, t, width]) so the three fused
11186        // gate kernels (perf lane attack (c)) each read every stream in one launch; the
11187        // 12 GEMVs stay cuBLASLt. Launches per read gate: 4 norms + 4 down + 1 reduce +
11188        // 4 up + 1 epilogue + 1 inject = 15, vs ~71 before (PROFILE-0: 27.7% of the token
11189        // across 96 calls, nearly all issue latency).
11190        let mut normed = ws.take_f32(e, "hc.normed", streams * t * hidden, 0)?;
11191        if micro_norm {
11192            // One launch for all streams over the plane pointer table (hcmicro).
11193            launch_hc_norm_planes(
11194                e,
11195                ptrs,
11196                &gate.norm_stack,
11197                &mut normed,
11198                hidden,
11199                t,
11200                streams,
11201                eps,
11202            )?;
11203        } else {
11204            for s in 0..streams {
11205                let mut dst = normed.slice_mut(s * t * hidden..(s + 1) * t * hidden);
11206                launch_rms_norm_into_view(e, &planes[s], &gate.norm[s], &mut dst, hidden, t, eps)?;
11207            }
11208        }
11209        // low_act = silu(mean_s down_s @ normed_s). bf16 trunk residency runs the
11210        // projection as ONE batched launch over the stream-major slab (stacked twin,
11211        // same output layout as the per-stream cuBLASLt chain — the A/B/fallback arm).
11212        let trunk_b16 = trunk_bf16_on();
11213        let mut parts = ws.take_f32(e, "hc.parts", streams * t * rank, 0)?;
11214        if let (true, Some(w)) = (trunk_b16, gate.down_b16.as_ref()) {
11215            launch_qmatvec_bf16w(
11216                e,
11217                w,
11218                &normed,
11219                &mut parts,
11220                hidden,
11221                rank,
11222                t,
11223                streams,
11224                rank * hidden,
11225                t * hidden,
11226                hidden,
11227                t * rank,
11228            )?;
11229        } else {
11230            if gate.down[0].len() < rank * hidden {
11231                return Err(
11232                    "qwen4exp_gpu: gate down f32 dropped (trunk_f32_diet) — keep the \
11233                            trunk-bf16 seam ON"
11234                        .into(),
11235                );
11236            }
11237            for s in 0..streams {
11238                let x = normed.slice(s * t * hidden..(s + 1) * t * hidden);
11239                let w = gate.down[s].slice(0..rank * hidden);
11240                let mut out = parts.slice_mut(s * t * rank..(s + 1) * t * rank);
11241                e.linear_device_into(&x, &w, &mut out, t, hidden, rank)?;
11242            }
11243        }
11244        let mut low_act = ws.take_f32(e, "hc.low_act", t * rank, 0)?;
11245        launch_hc_lowrank_reduce(e, &parts, &mut low_act, streams, t, rank)?;
11246        ws.put_f32("hc.parts", parts);
11247
11248        // mixed = mean_s sigmoid(up_s @ low_act) ⊙ normed_s (batched twin: x_bstride 0
11249        // shares the one low_act plane across streams).
11250        let mut gates = ws.take_f32(e, "hc.gates", streams * t * hidden, 0)?;
11251        if let (true, Some(w)) = (trunk_b16, gate.up_b16.as_ref()) {
11252            launch_qmatvec_bf16w(
11253                e,
11254                w,
11255                &low_act,
11256                &mut gates,
11257                rank,
11258                hidden,
11259                t,
11260                streams,
11261                hidden * rank,
11262                0,
11263                rank,
11264                t * hidden,
11265            )?;
11266        } else {
11267            if gate.up[0].len() < hidden * rank {
11268                return Err(
11269                    "qwen4exp_gpu: gate up f32 dropped (trunk_f32_diet) — keep the \
11270                            trunk-bf16 seam ON"
11271                        .into(),
11272                );
11273            }
11274            for s in 0..streams {
11275                let x = low_act.slice(0..t * rank);
11276                let w = gate.up[s].slice(0..hidden * rank);
11277                let mut out = gates.slice_mut(s * t * hidden..(s + 1) * t * hidden);
11278                e.linear_device_into(&x, &w, &mut out, t, rank, hidden)?;
11279            }
11280        }
11281        let mut mixed = ws.take_f32(e, "hc.mixed", t * hidden, 0)?;
11282        launch_hc_mix_epilogue(e, &gates, &normed, &mut mixed, streams, t, hidden)?;
11283        ws.put_f32("hc.gates", gates);
11284        ws.put_f32("hc.low_act", low_act);
11285
11286        let mut inject_out = InjectOut::Rows(Vec::new());
11287        if with_inject {
11288            let inject = gate
11289                .inject
11290                .as_ref()
11291                .ok_or("qwen4exp_gpu: read gate missing inject weights")?;
11292            // trunk_f32_diet: the f32 inject may be a dropped stub — every non-b16
11293            // consumer below must refuse it rather than read garbage.
11294            let inject_dropped = inject.len() < streams * streams * hidden;
11295            let inject_guard = || -> Res<()> {
11296                if inject_dropped {
11297                    return Err("qwen4exp_gpu: inject f32 dropped (trunk_f32_diet) — keep \
11298                                the trunk-bf16 seam ON"
11299                        .into());
11300                }
11301                Ok(())
11302            };
11303            let mut all = ws.take_f32(e, "hc.inj_all", streams * t, 0)?;
11304            if micro_inj {
11305                // Two-stage inject (hcmicro): chunked partials fill the card, the reduce
11306                // applies the sigmoid; the slab goes straight to `gate_write`.
11307                const CHUNKS: usize = 16;
11308                let mut partials = ws.take_f32(e, "hc.inj_part", streams * t * CHUNKS, 0)?;
11309                let w_b16 = if trunk_b16 {
11310                    gate.inject_b16.as_ref()
11311                } else {
11312                    None
11313                };
11314                if w_b16.is_none() {
11315                    inject_guard()?;
11316                }
11317                launch_hc_inject_two_stage(
11318                    e,
11319                    &normed,
11320                    inject,
11321                    w_b16,
11322                    &mut partials,
11323                    &mut all,
11324                    streams,
11325                    t,
11326                    hidden,
11327                    CHUNKS,
11328                )?;
11329                ws.put_f32("hc.inj_part", partials);
11330                inject_out = InjectOut::Slab(all);
11331            } else {
11332                // [streams, t] scalars in one launch; `gate_write` consumes one row per
11333                // stream.
11334                if let (true, Some(w)) = (trunk_b16, gate.inject_b16.as_ref()) {
11335                    launch_hc_inject_gates_b16(e, &normed, w, &mut all, streams, t, hidden)?;
11336                } else {
11337                    inject_guard()?;
11338                    launch_hc_inject_gates(e, &normed, inject, &mut all, streams, t, hidden)?;
11339                }
11340                let mut rows = Vec::with_capacity(streams);
11341                for s in 0..streams {
11342                    let mut row = ws.take_f32(e, INJECT_SLOTS[s], t, 0)?;
11343                    e.copy_range_into(&mut row, 0, &all, s * t, t)?;
11344                    rows.push(row);
11345                }
11346                ws.put_f32("hc.inj_all", all);
11347                inject_out = InjectOut::Rows(rows);
11348            }
11349        }
11350        ws.put_f32("hc.normed", normed);
11351        Ok((mixed, inject_out))
11352    }
11353
11354    /// Unfused read gate — the literal `gated_residual_read` composition from existing
11355    /// engine ops, kept as the A/B twin of the fused arm (`set_hc_fused_gate(false)`) and
11356    /// as the readable statement of the program. ~71 launches per call at hc_count 4.
11357    /// Deliberately NOT workspace-pooled: it is the hc-off measurement twin.
11358    #[allow(clippy::too_many_arguments)]
11359    fn gate_read_legacy(
11360        &self,
11361        e: &Engine,
11362        _ws: &mut StepPool,
11363        gate: &GateW,
11364        planes: &[CudaSlice<f32>],
11365        t: usize,
11366        eps: f32,
11367        with_inject: bool,
11368    ) -> Res<(CudaSlice<f32>, InjectOut)> {
11369        let hidden = self.hidden;
11370        let streams = self.streams;
11371        let rank = gate_rank(gate, hidden, streams)?;
11372        if gate.down[0].len() < rank * hidden {
11373            return Err(
11374                "qwen4exp_gpu: gate f32 originals dropped (trunk_f32_diet) — the \
11375                        legacy gate path needs them (keep hc seams ON)"
11376                    .into(),
11377            );
11378        }
11379        let inv_streams = 1.0 / streams as f32; // pow2 (hc_count 4 / tiny 2) — exact
11380
11381        let mut normed = Vec::with_capacity(streams);
11382        for s in 0..streams {
11383            let mut dst = e.uninit(t * hidden)?;
11384            e.rms_norm(&planes[s], &gate.norm[s], &mut dst, hidden, t, eps)?;
11385            normed.push(dst);
11386        }
11387        // low = silu(sum_s down_s @ normed_s / S)
11388        let mut low = e.linear(&normed[0], &gate.down[0], t, hidden, rank)?;
11389        for s in 1..streams {
11390            let part = e.linear(&normed[s], &gate.down[s], t, hidden, rank)?;
11391            let mut view = low.slice_mut(0..t * rank);
11392            e.axpy_into(&part, 1.0, &mut view, t * rank)?;
11393        }
11394        e.scale_inplace(&mut low, inv_streams, t * rank)?;
11395        let ones = e.htod(&vec![1.0f32; t * rank.max(1)])?;
11396        let mut low_act = e.uninit(t * rank)?;
11397        e.silu_mul(&low, &ones, &mut low_act, t * rank)?;
11398
11399        // mixed = mean_s sigmoid(up_s @ low) ⊙ normed_s
11400        let mut mixed = e.zeros(t * hidden)?;
11401        let mut gate_buf = e.uninit(t * hidden)?;
11402        let mut prod = e.uninit(t * hidden)?;
11403        for s in 0..streams {
11404            let g = e.linear(&low_act, &gate.up[s], t, rank, hidden)?;
11405            e.sigmoid(&g, &mut gate_buf, t * hidden)?;
11406            e.mul(&gate_buf, &normed[s], &mut prod, t * hidden)?;
11407            let mut view = mixed.slice_mut(0..t * hidden);
11408            e.axpy_into(&prod, 1.0, &mut view, t * hidden)?;
11409        }
11410        e.scale_inplace(&mut mixed, inv_streams, t * hidden)?;
11411
11412        let mut inject_out = Vec::new();
11413        if with_inject {
11414            let inject = gate
11415                .inject
11416                .as_ref()
11417                .ok_or("qwen4exp_gpu: read gate missing inject weights")?;
11418            let wide = streams * hidden;
11419            for s in 0..streams {
11420                // Per-(s, s2) [hidden] weight windows of block_inject_weight row s.
11421                let mut acc = {
11422                    let w = inject.slice(s * wide..s * wide + hidden);
11423                    let x = normed[0].slice(0..t * hidden);
11424                    let mut out = e.uninit(t)?;
11425                    e.linear_device_into(&x, &w, &mut out, t, hidden, 1)?;
11426                    out
11427                };
11428                for s2 in 1..streams {
11429                    let w = inject.slice(s * wide + s2 * hidden..s * wide + (s2 + 1) * hidden);
11430                    let x = normed[s2].slice(0..t * hidden);
11431                    let mut part = e.uninit(t)?;
11432                    e.linear_device_into(&x, &w, &mut part, t, hidden, 1)?;
11433                    let mut view = acc.slice_mut(0..t);
11434                    e.axpy_into(&part, 1.0, &mut view, t)?;
11435                }
11436                e.scale_inplace(&mut acc, inv_streams, t)?;
11437                let mut sg = e.uninit(t)?;
11438                e.sigmoid(&acc, &mut sg, t)?;
11439                e.scale_inplace(&mut sg, 2.0, t)?;
11440                inject_out.push(sg);
11441            }
11442        }
11443        Ok((mixed, InjectOut::Rows(inject_out)))
11444    }
11445
11446    /// Write half (`gated_residual_write` twin): plane_s += block_out ⊗ inject_s.
11447    /// Rows = per-stream add_scaled_rows (item-1-era plumbing); Slab = one launch over
11448    /// the plane pointer table (hcmicro).
11449    fn gate_write(
11450        &self,
11451        e: &Engine,
11452        planes: &mut [CudaSlice<f32>],
11453        ptrs: &CudaSlice<u64>,
11454        block_out: &CudaSlice<f32>,
11455        inject: &InjectOut,
11456        t: usize,
11457    ) -> Res<()> {
11458        match inject {
11459            InjectOut::Rows(rows) => {
11460                for (plane, inj) in planes.iter_mut().zip(rows) {
11461                    e.add_scaled_rows(block_out, inj, plane, self.hidden, t)?;
11462                }
11463                Ok(())
11464            }
11465            InjectOut::Slab(slab) => {
11466                launch_hc_write_planes(e, ptrs, block_out, slab, self.hidden, t, self.streams)
11467            }
11468        }
11469    }
11470
11471    /// One decode layer's INTERIOR at t == 1 (graph driver, item 2b): PLE (when
11472    /// present) → attn read gate → mixer → write → mlp read gate, ending with the mlp
11473    /// `mixed`/inject scalars PARKED in their slots for the MoE tail. The exact
11474    /// semantics of the eager `forward` loop body up to `moe_forward`; device-only for
11475    /// GDN layers without PLE, which is what makes those capturable.
11476    #[allow(clippy::too_many_arguments)]
11477    fn layer_interior(
11478        &self,
11479        e: &Engine,
11480        ws: &mut StepPool,
11481        ptrs: &CudaSlice<u64>,
11482        layer: &LayerW,
11483        lstate: &mut LayerState,
11484        planes: &mut [CudaSlice<f32>],
11485        tokens: &[u32],
11486        base_pos: usize,
11487    ) -> Res<()> {
11488        if let (Some(ple), Some(ple_state)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
11489            self.ple_block(
11490                e, layer, ple, &ple.table, ple_state, planes, tokens, 1, false, None,
11491            )?;
11492        }
11493        let (mixed, inject) = self.gate_read(
11494            e,
11495            ws,
11496            ptrs,
11497            &layer.attn_gate,
11498            planes,
11499            1,
11500            layer.eps_attn,
11501            false,
11502        )?;
11503        let block_out = match &layer.mixer {
11504            MixerW::Qsa(qsa) => self.qsa_forward(
11505                e,
11506                ws,
11507                layer,
11508                qsa,
11509                &mixed,
11510                &mut lstate.mixer,
11511                base_pos,
11512                1,
11513                0,
11514                false,
11515            )?,
11516            MixerW::Gdn(gdn) => {
11517                self.gdn_forward(e, ws, layer, gdn, &mixed, &mut lstate.mixer, 1, None)?
11518            }
11519        };
11520        ws.put_f32("hc.mixed", mixed);
11521        self.gate_write(e, planes, ptrs, &block_out, &inject, 1)?;
11522        ws.put_f32("mixer.out", block_out);
11523        put_inject(ws, inject);
11524        let (mixed, inject) = self.gate_read(
11525            e,
11526            ws,
11527            ptrs,
11528            &layer.mlp_gate,
11529            planes,
11530            1,
11531            layer.eps_mlp,
11532            false,
11533        )?;
11534        ws.put_f32("hc.mixed", mixed);
11535        put_inject(ws, inject);
11536        Ok(())
11537    }
11538
11539    /// Per-step MoE routing (graph driver): router GEMV over the parked mlp `mixed`,
11540    /// dtoh (the per-layer host boundary — routing is a HOST twin by lane doctrine, so
11541    /// a whole-step graph is structurally impossible; this is the sync the segment
11542    /// graphs meet at), reference top-k, then H2D of the selection into the slot
11543    /// addresses the captured MoE-tail graph baked.
11544    fn moe_route_slots(&self, e: &Engine, ws: &mut StepPool, moe: &MoeW, layer: u32) -> Res<()> {
11545        let hidden = self.hidden;
11546        let experts = moe.plan.expert_count as usize;
11547        let selected = moe.plan.experts_per_token as usize;
11548        let mixed = ws.take_f32(e, "hc.mixed", hidden, 0)?;
11549        let mut router_out = ws.take_f32(e, "moe.router", experts, 0)?;
11550        let none: Option<CudaSlice<u8>> = None;
11551        let rb = if router_bf16_on() {
11552            &moe.router_b16
11553        } else {
11554            &none
11555        };
11556        linear_trunk_into(
11557            e,
11558            &moe.router,
11559            rb,
11560            &mixed,
11561            &mut router_out,
11562            1,
11563            hidden,
11564            experts,
11565        )?;
11566        // Device router (devtwin lane): the route stays on device — no dtoh, no host
11567        // top-k, no selection h2d. Writes land in the SAME parked slots the captured
11568        // MoE-tail graph baked (take-without-upload + put preserves the address).
11569        if router_dev_on() && route_dev_geometry(experts, selected) {
11570            let mut sel = ws.take_i32_slot(e, "moe.sel", selected, 0)?;
11571            let mut w = ws.take_f32(e, "moe.w", selected, 0)?;
11572            route_topk_device(
11573                e,
11574                &router_out,
11575                &mut sel,
11576                &mut w,
11577                None,
11578                experts,
11579                selected,
11580                1,
11581                layer,
11582            )?;
11583            // DIAGNOSTIC ONLY (`MEMRA_Q4E_ROUTE_SYNC=1`, never a serving arm): restore the
11584            // host arm's per-layer SYNC structure while keeping the device route, to
11585            // separate "the kernel costs" from "the missing sync costs" in the
11586            // graphs-ON regression (devtwin: graphs OFF the seam wins 1.083x, graphs ON
11587            // it loses — PROFILE-9 §3).
11588            if route_sync_diag() {
11589                e.gpu.stream().synchronize()?;
11590            }
11591            ws.put_i32("moe.sel", sel);
11592            ws.put_f32("moe.w", w);
11593            ws.put_f32("moe.router", router_out);
11594            ws.put_f32("hc.mixed", mixed);
11595            return Ok(());
11596        }
11597        let logits = e.dtoh_view(&router_out.slice(0..experts))?;
11598        ws.put_f32("moe.router", router_out);
11599        ws.put_f32("hc.mixed", mixed);
11600        let route = host_route_softmax_topk(&logits, selected);
11601        let sel_host: Vec<i32> = route.iter().map(|&(x, _)| x as i32).collect();
11602        let w_host: Vec<f32> = route.iter().map(|&(_, w)| w).collect();
11603        ws.write_i32(e, "moe.sel", &sel_host)?;
11604        ws.write_f32(e, "moe.w", &w_host)?;
11605        Ok(())
11606    }
11607
11608    /// The grouped-MoE tail at t == 1 over PARKED slots (graph driver): sel matvecs →
11609    /// shared expert → mlp gate_write. Same kernels/order as the `moe_forward` grouped
11610    /// block; the selection indices/weights arrive via `moe_route_slots` into the baked
11611    /// slot addresses.
11612    fn moe_grouped_tail_slots(
11613        &self,
11614        e: &Engine,
11615        ws: &mut StepPool,
11616        ptrs: &CudaSlice<u64>,
11617        moe: &MoeW,
11618        planes: &mut [CudaSlice<f32>],
11619    ) -> Res<()> {
11620        let hidden = self.hidden;
11621        let ff = moe.plan.expert_intermediate_size as usize;
11622        let n_sel = moe.plan.experts_per_token as usize;
11623        let (
11624            BankHalf::Nvfp4 {
11625                codes: gc,
11626                scales: gs,
11627                macros_dev: gm,
11628                ..
11629            },
11630            BankHalf::Nvfp4 {
11631                codes: uc,
11632                scales: us,
11633                macros_dev: um,
11634                ..
11635            },
11636            BankHalf::Nvfp4 {
11637                codes: dc,
11638                scales: ds,
11639                macros_dev: dm,
11640                ..
11641            },
11642        ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
11643        else {
11644            return Err("qwen4exp_gpu: grouped tail on a non-NVFP4 bank".into());
11645        };
11646        let mixed = ws.take_f32(e, "hc.mixed", hidden, 0)?;
11647        let sel = ws
11648            .i32s
11649            .remove("moe.sel")
11650            .ok_or("step workspace: moe.sel is not parked")?;
11651        let w_dev = ws.take_f32(e, "moe.w", n_sel, 0)?;
11652        let mut act = ws.take_f32(e, "moe.act", n_sel * ff, 0)?;
11653        // Fused gate+up+silu (round 4): the graph bakes whichever arm is live at
11654        // capture (fresh state per A/B arm); bit-identical to the chain.
11655        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
11656            launch_nvfp4_sel_gu_silu(
11657                e,
11658                (gc, gs, gm),
11659                (uc, us, um),
11660                Some(&sel),
11661                0,
11662                n_sel,
11663                &mixed,
11664                &mut act,
11665                hidden,
11666                ff,
11667                None,
11668            )?;
11669        } else {
11670            let mut yg = ws.take_f32(e, "moe.yg", n_sel * ff, 0)?;
11671            let mut yu = ws.take_f32(e, "moe.yu", n_sel * ff, 0)?;
11672            launch_nvfp4_sel_matvec(e, gc, gs, gm, &sel, &mixed, &mut yg, n_sel, hidden, ff, 0)?;
11673            launch_nvfp4_sel_matvec(e, uc, us, um, &sel, &mixed, &mut yu, n_sel, hidden, ff, 0)?;
11674            e.silu_mul(&yg, &yu, &mut act, n_sel * ff)?;
11675            ws.put_f32("moe.yg", yg);
11676            ws.put_f32("moe.yu", yu);
11677        }
11678        let mut partial = ws.take_f32(e, "moe.partial", n_sel * hidden, 0)?;
11679        launch_nvfp4_sel_matvec(
11680            e,
11681            dc,
11682            ds,
11683            dm,
11684            &sel,
11685            &act,
11686            &mut partial,
11687            n_sel,
11688            ff,
11689            hidden,
11690            ff,
11691        )?;
11692        let mut out = ws.take_f32(e, "moe.out", hidden, 0)?;
11693        e.axpy_rows_seq_into(&partial, &w_dev, &mut out, hidden, n_sel)?;
11694        ws.put_i32("moe.sel", sel);
11695        ws.put_f32("moe.w", w_dev);
11696        ws.put_f32("moe.act", act);
11697        ws.put_f32("moe.partial", partial);
11698        let out = self.moe_shared_tail(e, ws, moe, &mixed, out, 1)?;
11699        ws.put_f32("hc.mixed", mixed);
11700        let inject = take_inject(e, ws, self.streams, 1)?;
11701        self.gate_write(e, planes, ptrs, &out, &inject, 1)?;
11702        ws.put_f32("moe.out", out);
11703        put_inject(ws, inject);
11704        Ok(())
11705    }
11706
11707    /// Graph-mode decode tail (item 2b): per layer, replay (or lazily capture) the
11708    /// interior graph, run the host routing boundary, replay the MoE-tail graph; then
11709    /// the exit graph and one logits dtoh. Falls back to the eager helpers per layer
11710    /// where a graph is structurally unavailable (QSA/PLE interiors — the indexer host
11711    /// twin and PLE host hashing live there; non-NVFP4 banks for the tail).
11712    fn forward_graphs_tail(
11713        &self,
11714        e: &Engine,
11715        state: &mut Qwen4ExpState,
11716        mut planes: Vec<CudaSlice<f32>>,
11717        ptrs: CudaSlice<u64>,
11718        base_pos: usize,
11719    ) -> Res<Vec<f32>> {
11720        let mut graphs = std::mem::take(&mut state.graphs);
11721        if graphs.a.len() != self.layers.len() {
11722            graphs.a = (0..self.layers.len()).map(|_| None).collect();
11723            graphs.b = (0..self.layers.len()).map(|_| None).collect();
11724        }
11725        let ws = &mut state.ws;
11726        let tokens = &state.tokens;
11727        for (li, (layer, lstate)) in self.layers.iter().zip(state.layers.iter_mut()).enumerate() {
11728            let a_ok = matches!(layer.mixer, MixerW::Gdn(_)) && layer.ple.is_none();
11729            if a_ok {
11730                if graphs.a[li].is_none() {
11731                    graphs.a[li] = Some(e.capture_graph_retained_nowarm(|eng| {
11732                        self.layer_interior(
11733                            eng,
11734                            ws,
11735                            &ptrs,
11736                            layer,
11737                            lstate,
11738                            &mut planes,
11739                            tokens,
11740                            base_pos,
11741                        )
11742                    })?);
11743                }
11744                graphs.a[li].as_ref().unwrap().0.launch()?;
11745            } else {
11746                self.layer_interior(e, ws, &ptrs, layer, lstate, &mut planes, tokens, base_pos)?;
11747            }
11748            let b_ok = moe_sel_path_on()
11749                && matches!(
11750                    (
11751                        &layer.moe.bank.gate,
11752                        &layer.moe.bank.up,
11753                        &layer.moe.bank.down
11754                    ),
11755                    (
11756                        BankHalf::Nvfp4 { .. },
11757                        BankHalf::Nvfp4 { .. },
11758                        BankHalf::Nvfp4 { .. }
11759                    )
11760                );
11761            if b_ok {
11762                self.moe_route_slots(e, ws, &layer.moe, layer.index)?;
11763                if graphs.b[li].is_none() {
11764                    graphs.b[li] = Some(e.capture_graph_retained_nowarm(|eng| {
11765                        self.moe_grouped_tail_slots(eng, ws, &ptrs, &layer.moe, &mut planes)
11766                    })?);
11767                }
11768                graphs.b[li].as_ref().unwrap().0.launch()?;
11769            } else {
11770                // Eager MoE (per-expert path routes internally) + mlp write.
11771                let mixed = ws.take_f32(e, "hc.mixed", self.hidden, 0)?;
11772                let mlp = self.moe_forward(e, ws, &layer.moe, &mixed, 1, false, layer.index)?;
11773                ws.put_f32("hc.mixed", mixed);
11774                let inject = take_inject(e, ws, self.streams, 1)?;
11775                self.gate_write(e, &mut planes, &ptrs, &mlp, &inject, 1)?;
11776                ws.put_f32("moe.out", mlp);
11777                put_inject(ws, inject);
11778            }
11779        }
11780        if graphs.exit.is_none() {
11781            graphs.exit = Some(e.capture_graph_retained_nowarm(|eng| {
11782                let x = self
11783                    .gate_read_inner(
11784                        eng,
11785                        ws,
11786                        &ptrs,
11787                        &self.exit_mixer,
11788                        &planes,
11789                        1,
11790                        self.exit_eps,
11791                        false,
11792                        false,
11793                    )?
11794                    .0;
11795                let mut logits = ws.take_f32(eng, "logits", self.vocab, 0)?;
11796                linear_trunk_into(
11797                    eng,
11798                    &self.output,
11799                    &self.output_b16,
11800                    &x,
11801                    &mut logits,
11802                    1,
11803                    self.hidden,
11804                    self.vocab,
11805                )?;
11806                ws.put_f32("hc.mixed", x);
11807                ws.put_f32("logits", logits);
11808                Ok(())
11809            })?);
11810        }
11811        graphs.exit.as_ref().unwrap().0.launch()?;
11812        let out = {
11813            let logits = ws.peek_f32("logits")?;
11814            e.dtoh_view(&logits.slice(0..self.vocab))?
11815        };
11816        for (s, plane) in planes.into_iter().enumerate() {
11817            ws.put_f32(PLANE_SLOTS[s], plane);
11818        }
11819        ws.put_u64("hc.ptrs", ptrs);
11820        state.pos += 1;
11821        state.graphs = graphs;
11822        Ok(out)
11823    }
11824
11825    /// QSA layer: fused [q|gate] projection, q/k RMSNorm, partial rope, KV append, the
11826    /// host indexer-selection twin, dense masked attention, sigmoid fused output gate.
11827    ///
11828    /// Indexer update + selection for one chunk (factored from `qsa_forward` so the
11829    /// TP2 route shares it verbatim): idx projection, the idxcache device raw-key
11830    /// cache maintenance, host/pooled cache updates, the device-scorer selection, and
11831    /// the idxq audit twin. Returns per-row selections (`RowSel`).
11832    #[allow(clippy::too_many_arguments)]
11833    fn qsa_update_select(
11834        &self,
11835        e: &Engine,
11836        ws: &mut StepPool,
11837        qsa: &QsaW,
11838        eps: f32,
11839        mixed: &CudaSlice<f32>,
11840        raw_keys: &mut IdxRawCache,
11841        pooled_keys: &mut Vec<f32>,
11842        pooled_dev: &mut Option<CudaSlice<f32>>,
11843        pooled_dev_rows: &mut usize,
11844        raw_dev: &mut Option<IdxRawDev>,
11845        raw_dev_rows: &mut usize,
11846        mut idx_audit: Option<&mut Box<IdxAudit>>,
11847        base_pos: usize,
11848        t: usize,
11849        pos_off: usize,
11850        exact: bool,
11851    ) -> Res<Vec<RowSel>> {
11852        let hidden = self.hidden;
11853        let base = qsa.attn.rope.base;
11854        let t_kv = base_pos + t;
11855        // Indexer selection: host twin of micro_block_selection_mask over the raw-key cache.
11856        let overlay = &qsa.overlay;
11857        let idx_dim = overlay.head_dim as usize;
11858        let qk_width = (overlay.query_heads as usize + overlay.kv_heads as usize) * idx_dim;
11859        if overlay.kv_heads != 1 {
11860            return Err("qwen4exp_gpu: indexer with more than one key head".into());
11861        }
11862        let idx_proj = prof_section(e, "qsa.idx_proj", || {
11863            let mut idx_proj = ws.take_f32(e, "qsa.idxp", t * qk_width, 0)?;
11864            if exact && t > 1 {
11865                let wv = qsa.idx_proj.slice(0..qsa.idx_proj.len());
11866                for tok in 0..t {
11867                    let xv = mixed.slice(tok * hidden..(tok + 1) * hidden);
11868                    let mut yv = idx_proj.slice_mut(tok * qk_width..(tok + 1) * qk_width);
11869                    e.linear_device_into(&xv, &wv, &mut yv, 1, hidden, qk_width)?;
11870                }
11871            } else {
11872                e.linear_device_into(mixed, &qsa.idx_proj, &mut idx_proj, t, hidden, qk_width)?;
11873            }
11874            Ok(idx_proj)
11875        })?;
11876        // Device raw-key cache (devtwin stage 3, `idxcache`): row r of `raw_dev` is
11877        // absolute cache row r. Below the selection horizon ((base_pos + t)/block <=
11878        // budget — the indexer_select_rows fast path, decided from positions alone)
11879        // the selection needs NO device data, so the k-part rows append d2d and the
11880        // idx_proj dtoh dies; the host cache lags and materializes LAZILY at the first
11881        // scored chunk — the same bytes dtoh'd later, bit-identical by construction.
11882        // Mid-run seam flips on a live state pay their debt loudly here: OFF->ON
11883        // backfills the device from the host (h2d, exact bytes); any host lag is paid
11884        // BEFORE this chunk lands whenever the fast path does not take it.
11885        let dev_cache = idx_cache_on();
11886        let block_size = overlay.block_size as usize;
11887        let all_full = (base_pos + t) / block_size <= overlay.budget_blocks as usize;
11888        let host_rows = raw_keys.rows(idx_dim);
11889        if *raw_dev_rows > host_rows && !(dev_cache && all_full) {
11890            // Lazy host materialization (or an ON->OFF flip's debt): dtoh the delta
11891            // VERBATIM — quantized formats materialize their own bytes, no re-quant,
11892            // so the seam's bit-identity contract is preserved per format.
11893            idx_materialize_host(e, raw_keys, raw_dev, *raw_dev_rows, idx_dim)?;
11894        }
11895        if dev_cache {
11896            let host_rows = raw_keys.rows(idx_dim);
11897            let base_rows = (*raw_dev_rows).max(host_rows);
11898            let cap_rows = (base_rows + t).next_power_of_two().max(64);
11899            let q_off = overlay.query_heads as usize * idx_dim;
11900            match &mut *raw_keys {
11901                IdxRawCache::F32(h) => {
11902                    let want = (base_rows + t) * idx_dim;
11903                    let grow = match raw_dev.as_ref() {
11904                        Some(IdxRawDev::F32(m)) => m.len() < want,
11905                        Some(_) => return Err("idxcache: device format lag on f32".into()),
11906                        None => true,
11907                    };
11908                    if grow {
11909                        let mut fresh = e.uninit(cap_rows * idx_dim)?;
11910                        if let (Some(IdxRawDev::F32(old)), rows) = (raw_dev.as_ref(), *raw_dev_rows)
11911                        {
11912                            if rows > 0 {
11913                                e.copy_range_into(&mut fresh, 0, old, 0, rows * idx_dim)?;
11914                            }
11915                        }
11916                        *raw_dev = Some(IdxRawDev::F32(fresh));
11917                    }
11918                    let Some(IdxRawDev::F32(m)) = raw_dev.as_mut() else {
11919                        unreachable!("allocated above");
11920                    };
11921                    if host_rows > *raw_dev_rows {
11922                        // OFF->ON flip on a live state: backfill the device from host.
11923                        let mut view = m.slice_mut(*raw_dev_rows * idx_dim..host_rows * idx_dim);
11924                        e.gpu
11925                            .stream()
11926                            .memcpy_htod(&h[*raw_dev_rows * idx_dim..], &mut view)?;
11927                        *raw_dev_rows = host_rows;
11928                    }
11929                    launch_copy_rows_col(
11930                        e,
11931                        &idx_proj,
11932                        m,
11933                        t,
11934                        idx_dim,
11935                        qk_width,
11936                        q_off,
11937                        *raw_dev_rows,
11938                    )?;
11939                }
11940                IdxRawCache::Q8(h) => {
11941                    let rb = q8_row_bytes(idx_dim);
11942                    let want = (base_rows + t) * rb;
11943                    let grow = match raw_dev.as_ref() {
11944                        Some(IdxRawDev::Q8(m)) => m.len() < want,
11945                        Some(_) => return Err("idxcache: device format lag on q8".into()),
11946                        None => true,
11947                    };
11948                    if grow {
11949                        let mut fresh = e.alloc_u8_uninit(cap_rows * rb)?;
11950                        if let (Some(IdxRawDev::Q8(old)), rows) = (raw_dev.as_ref(), *raw_dev_rows)
11951                        {
11952                            if rows > 0 {
11953                                let mut dst = fresh.slice_mut(0..rows * rb);
11954                                e.gpu
11955                                    .stream()
11956                                    .memcpy_dtod(&old.slice(0..rows * rb), &mut dst)?;
11957                            }
11958                        }
11959                        *raw_dev = Some(IdxRawDev::Q8(fresh));
11960                    }
11961                    let Some(IdxRawDev::Q8(m)) = raw_dev.as_mut() else {
11962                        unreachable!("allocated above");
11963                    };
11964                    if host_rows > *raw_dev_rows {
11965                        let mut view = m.slice_mut(*raw_dev_rows * rb..host_rows * rb);
11966                        e.gpu
11967                            .stream()
11968                            .memcpy_htod(&h[*raw_dev_rows * rb..host_rows * rb], &mut view)?;
11969                        *raw_dev_rows = host_rows;
11970                    }
11971                    launch_q4e_idx_append_q8(
11972                        e,
11973                        &idx_proj,
11974                        m,
11975                        t,
11976                        idx_dim,
11977                        qk_width,
11978                        q_off,
11979                        *raw_dev_rows,
11980                    )?;
11981                }
11982                IdxRawCache::Bf16(h) => {
11983                    let want = (base_rows + t) * idx_dim;
11984                    let grow = match raw_dev.as_ref() {
11985                        Some(IdxRawDev::Bf16(m)) => m.len() < want,
11986                        Some(_) => return Err("idxcache: device format lag on bf16".into()),
11987                        None => true,
11988                    };
11989                    if grow {
11990                        let mut fresh = unsafe { e.gpu.stream().alloc::<u16>(cap_rows * idx_dim)? };
11991                        if let (Some(IdxRawDev::Bf16(old)), rows) =
11992                            (raw_dev.as_ref(), *raw_dev_rows)
11993                        {
11994                            if rows > 0 {
11995                                let mut dst = fresh.slice_mut(0..rows * idx_dim);
11996                                e.gpu
11997                                    .stream()
11998                                    .memcpy_dtod(&old.slice(0..rows * idx_dim), &mut dst)?;
11999                            }
12000                        }
12001                        *raw_dev = Some(IdxRawDev::Bf16(fresh));
12002                    }
12003                    let Some(IdxRawDev::Bf16(m)) = raw_dev.as_mut() else {
12004                        unreachable!("allocated above");
12005                    };
12006                    if host_rows > *raw_dev_rows {
12007                        let mut view = m.slice_mut(*raw_dev_rows * idx_dim..host_rows * idx_dim);
12008                        e.gpu.stream().memcpy_htod(
12009                            &h[*raw_dev_rows * idx_dim..host_rows * idx_dim],
12010                            &mut view,
12011                        )?;
12012                        *raw_dev_rows = host_rows;
12013                    }
12014                    launch_q4e_idx_append_bf16(
12015                        e,
12016                        &idx_proj,
12017                        m,
12018                        t,
12019                        idx_dim,
12020                        qk_width,
12021                        q_off,
12022                        *raw_dev_rows,
12023                    )?;
12024                }
12025            }
12026            *raw_dev_rows += t;
12027        }
12028        // idxq selection-identity audit (instrument): the f32 twin cache is fed on
12029        // EVERY chunk — this re-adds the idx_proj dtoh the idxcache seam removed, and
12030        // is never a perf arm. Fed BEFORE selection so the twin includes this chunk.
12031        if let Some(audit) = idx_audit.as_deref_mut() {
12032            let q_off = overlay.query_heads as usize * idx_dim;
12033            let rows_f = e.dtoh_view(&idx_proj.slice(0..t * qk_width))?;
12034            let IdxRawCache::F32(twin) = &mut audit.raw_f32 else {
12035                return Err("idxq audit: twin cache is not f32".into());
12036            };
12037            for row in 0..t {
12038                twin.extend_from_slice(&rows_f[row * qk_width + q_off..(row + 1) * qk_width]);
12039            }
12040        }
12041        let sels: Vec<RowSel> = if dev_cache && all_full {
12042            ws.put_f32("qsa.idxp", idx_proj);
12043            (0..t)
12044                .map(|qt| RowSel {
12045                    full: true,
12046                    blocks: Vec::new(),
12047                    visible: base_pos + qt + 1,
12048                })
12049                .collect()
12050        } else {
12051            let idx_rows = e.dtoh_view(&idx_proj.slice(0..t * qk_width))?;
12052            ws.put_f32("qsa.idxp", idx_proj);
12053            let q_off = overlay.query_heads as usize * idx_dim;
12054            for row in 0..t {
12055                raw_keys.append_rows_f32(
12056                    &idx_rows[row * qk_width + q_off..(row + 1) * qk_width],
12057                    1,
12058                    idx_dim,
12059                );
12060            }
12061            // Device block scorer (long-context lane): the host twin is O(context) per
12062            // token per layer — 52% of the decode token at a 32k fill (smoke ladder),
12063            // and quadratic across a long prefill. Scores are bit-identical (same
12064            // arithmetic order), so the selection is the same set. `idx_dev` (default
12065            // ON) is the rollback seam; the host twin remains the reference and the
12066            // TP2 path.
12067            let dev_scorer = idx_dev_on();
12068            let sels = prof_section(e, "qsa.idx_host", || {
12069                indexer_select_rows(
12070                    overlay,
12071                    base,
12072                    qsa.yarn.as_ref().map(|y| (y.ff_host.as_slice(), y.mscale)),
12073                    eps,
12074                    &qsa.idx_q_norm,
12075                    &qsa.idx_k_norm,
12076                    &idx_rows,
12077                    raw_keys,
12078                    pooled_keys,
12079                    if dev_scorer {
12080                        Some((e, pooled_dev, pooled_dev_rows))
12081                    } else {
12082                        None
12083                    },
12084                    base_pos,
12085                    t,
12086                    t_kv,
12087                    pos_off,
12088                )
12089            })?;
12090            // Audit compare: recompute every scored row's selection from the f32 twin
12091            // caches (host scorer) and count flipped sets. Full rows cannot flip (the
12092            // structural fast path reads no scores) and are skipped. BOUNDED to
12093            // decode/draft/verify shapes (t <= 8): a prefill chunk would pay the
12094            // O(context) host selection PER ROW x 2048 rows x every chunk — quadratic
12095            // across a long prefill, the exact cost the device scorer retired. Prefill
12096            // chunks still FEED the twin (above); the twin's pooled cache catches up
12097            // lazily inside its next compare. Stated in the receipt: the flip rate is
12098            // measured on decode/verify rows at depth.
12099            if let Some(audit) = idx_audit.as_deref_mut() {
12100                if t <= 8 && sels.iter().any(|s| !s.full) {
12101                    let twin_sels = indexer_select_rows(
12102                        overlay,
12103                        base,
12104                        qsa.yarn.as_ref().map(|y| (y.ff_host.as_slice(), y.mscale)),
12105                        eps,
12106                        &qsa.idx_q_norm,
12107                        &qsa.idx_k_norm,
12108                        &idx_rows,
12109                        &audit.raw_f32,
12110                        &mut audit.pooled_f32,
12111                        None,
12112                        base_pos,
12113                        t,
12114                        t_kv,
12115                        pos_off,
12116                    )?;
12117                    use std::sync::atomic::Ordering::Relaxed;
12118                    for (a, b) in sels.iter().zip(&twin_sels) {
12119                        if a.full && b.full {
12120                            continue;
12121                        }
12122                        IDXQ_AUDIT_ROWS.fetch_add(1, Relaxed);
12123                        if a.full != b.full || a.blocks != b.blocks {
12124                            IDXQ_AUDIT_FLIPPED.fetch_add(1, Relaxed);
12125                            let mut diff = 0u64;
12126                            let (sa, sb) = (&a.blocks, &b.blocks);
12127                            let seta: std::collections::BTreeSet<_> = sa.iter().collect();
12128                            let setb: std::collections::BTreeSet<_> = sb.iter().collect();
12129                            diff += seta.symmetric_difference(&setb).count() as u64;
12130                            IDXQ_AUDIT_BLOCKS.fetch_add(diff, Relaxed);
12131                        }
12132                    }
12133                }
12134            }
12135            sels
12136        };
12137        Ok(sels)
12138    }
12139
12140    fn qsa_forward(
12141        &self,
12142        e: &Engine,
12143        ws: &mut StepPool,
12144        layer: &LayerW,
12145        qsa: &QsaW,
12146        mixed: &CudaSlice<f32>,
12147        mstate: &mut MixerState,
12148        base_pos: usize,
12149        t: usize,
12150        // Rope/indexer position offset (0 = trunk; 1 = the MTP draft, see
12151        // `indexer_mask_rows`). Causality stays cache-row based either way.
12152        pos_off: usize,
12153        // Verify-exact rows (mtp-spec): per-token indexer-projection launches — the
12154        // one cuBLASLt op in this path whose m > 1 algorithm may differ from the
12155        // decode-shape GEMV; m == 1 per token keeps rows bit-identical to decode.
12156        exact: bool,
12157    ) -> Res<CudaSlice<f32>> {
12158        let MixerState::Qsa {
12159            kv,
12160            raw_keys,
12161            pooled_keys,
12162            pooled_dev,
12163            pooled_dev_rows,
12164            raw_dev,
12165            raw_dev_rows,
12166            idx_audit,
12167        } = mstate
12168        else {
12169            return Err(format!(
12170                "qwen4exp_gpu: QSA layer {} bound to non-QSA state",
12171                layer.index
12172            )
12173            .into());
12174        };
12175        let hidden = self.hidden;
12176        let nh = qsa.attn.query_heads as usize;
12177        let nkv = qsa.attn.kv_heads as usize;
12178        let hd = qsa.attn.key_head_dim as usize;
12179        let eps = layer.eps_attn;
12180        // Mask-slot reserve: [t, capacity] never grows mid-run (t_kv does, every step).
12181        let cap = kv.capacity_rows(nkv * hd);
12182
12183        let n_rot = qsa.attn.rope.dimensions as usize;
12184        let base = qsa.attn.rope.base;
12185        let (q, gate) = prof_section(e, "qsa.proj", || {
12186            let mut q_fused = ws.take_f32(e, "qsa.qf", t * 2 * nh * hd, 0)?;
12187            let mut k_new = ws.take_f32(e, "qsa.k", t * nkv * hd, 0)?;
12188            let mut v_new = ws.take_f32(e, "qsa.v", t * nkv * hd, 0)?;
12189            // Proj stack (round 4): wq/wk/wv in ONE launch over the row-stacked twin;
12190            // per-row bit-identical to the per-mat launches (OFF arm = row-offset views
12191            // of the same stack).
12192            if let (true, Some(stack)) = (
12193                t == 1 && proj_stack_on() && trunk_bf16_on(),
12194                qsa.proj_b16.as_ref(),
12195            ) {
12196                launch_qmatvec_bf16w_multi4(
12197                    e,
12198                    stack,
12199                    mixed,
12200                    &[
12201                        (&q_fused, 2 * nh * hd),
12202                        (&k_new, nkv * hd),
12203                        (&v_new, nkv * hd),
12204                    ],
12205                    hidden,
12206                )?;
12207            } else {
12208                linear_trunk_stacked_into(
12209                    e,
12210                    &qsa.wq,
12211                    &qsa.proj_b16,
12212                    0,
12213                    mixed,
12214                    &mut q_fused,
12215                    t,
12216                    hidden,
12217                    2 * nh * hd,
12218                )?;
12219                linear_trunk_stacked_into(
12220                    e,
12221                    &qsa.wk,
12222                    &qsa.proj_b16,
12223                    2 * nh * hd,
12224                    mixed,
12225                    &mut k_new,
12226                    t,
12227                    hidden,
12228                    nkv * hd,
12229                )?;
12230                linear_trunk_stacked_into(
12231                    e,
12232                    &qsa.wv,
12233                    &qsa.proj_b16,
12234                    2 * nh * hd + nkv * hd,
12235                    mixed,
12236                    &mut v_new,
12237                    t,
12238                    hidden,
12239                    nkv * hd,
12240                )?;
12241            }
12242            let mut q = ws.take_f32(e, "qsa.q", t * nh * hd, 0)?;
12243            let mut gate = ws.take_f32(e, "qsa.gate", t * nh * hd, 0)?;
12244            e.q_gate_split(&q_fused, &mut q, &mut gate, hd, nh, t)?;
12245            ws.put_f32("qsa.qf", q_fused);
12246            let mut q = if let Some(norm) = qsa.q_norm.as_ref() {
12247                let mut dst = ws.take_f32(e, "qsa.qn", t * nh * hd, 0)?;
12248                e.rms_norm(&q, norm, &mut dst, hd, t * nh, eps)?;
12249                ws.put_f32("qsa.q", q);
12250                dst
12251            } else {
12252                q
12253            };
12254            let mut k_new = if let Some(norm) = qsa.k_norm.as_ref() {
12255                let mut dst = ws.take_f32(e, "qsa.kn", t * nkv * hd, 0)?;
12256                e.rms_norm(&k_new, norm, &mut dst, hd, t * nkv, eps)?;
12257                ws.put_f32("qsa.k", k_new);
12258                dst
12259            } else {
12260                k_new
12261            };
12262            let positions: Vec<i32> = (0..t).map(|i| (base_pos + i + pos_off) as i32).collect();
12263            let pos_dev = ws.take_i32(e, "qsa.pos", &positions, 0)?;
12264            if let Some(yarn) = qsa.yarn.as_ref() {
12265                e.rope_neox_ffm(
12266                    &mut q,
12267                    &pos_dev,
12268                    hd,
12269                    n_rot,
12270                    nh,
12271                    t,
12272                    base,
12273                    1.0,
12274                    &yarn.ff,
12275                    yarn.mscale,
12276                )?;
12277                e.rope_neox_ffm(
12278                    &mut k_new,
12279                    &pos_dev,
12280                    hd,
12281                    n_rot,
12282                    nkv,
12283                    t,
12284                    base,
12285                    1.0,
12286                    &yarn.ff,
12287                    yarn.mscale,
12288                )?;
12289            } else {
12290                e.rope_neox(&mut q, &pos_dev, hd, n_rot, nh, t, base, 1.0)?;
12291                e.rope_neox(&mut k_new, &pos_dev, hd, n_rot, nkv, t, base, 1.0)?;
12292            }
12293            ws.put_i32("qsa.pos", pos_dev);
12294            // Explicit lengths: workspace slots may be larger than this chunk.
12295            match kv {
12296                QsaKvStore::F32 { k, v } => {
12297                    e.copy_range_into(k, base_pos * nkv * hd, &k_new, 0, t * nkv * hd)?;
12298                    e.copy_range_into(v, base_pos * nkv * hd, &v_new, 0, t * nkv * hd)?;
12299                }
12300                // kvq lane: append-quantize the post-RoPE rows in place (K=q8_0,
12301                // V=q5_1) — same slot addressing, no host round trip.
12302                QsaKvStore::Q8Q5 { k, v } => {
12303                    launch_q4e_kv_append(e, &k_new, &v_new, k, v, base_pos, t, nkv * hd)?;
12304                }
12305            }
12306            ws.put_f32(
12307                if qsa.k_norm.is_some() {
12308                    "qsa.kn"
12309                } else {
12310                    "qsa.k"
12311                },
12312                k_new,
12313            );
12314            ws.put_f32("qsa.v", v_new);
12315            Ok((q, gate))
12316        })?;
12317        let t_kv = base_pos + t;
12318        let sels = self.qsa_update_select(
12319            e,
12320            ws,
12321            qsa,
12322            eps,
12323            mixed,
12324            raw_keys,
12325            pooled_keys,
12326            pooled_dev,
12327            pooled_dev_rows,
12328            raw_dev,
12329            raw_dev_rows,
12330            idx_audit.as_mut(),
12331            base_pos,
12332            t,
12333            pos_off,
12334            exact,
12335        )?;
12336        let overlay = &qsa.overlay;
12337
12338        let scale = match qsa.attn.scale {
12339            memra_gguf::model_plan::AttentionScale::InverseSqrtKeyDim => 1.0 / (hd as f32).sqrt(),
12340            memra_gguf::model_plan::AttentionScale::Fixed(scale) => scale,
12341        };
12342        // Long-context attention form: past the masked kernel's smem bound the dense
12343        // [t, t_kv] mask is impossible (bytes scale with context), so the block-list
12344        // kernel consumes the selection directly — BIT-IDENTICAL math (the masked
12345        // kernel's -1e30 rows contribute exact 0.0 terms in the same ascending order;
12346        // gate arm `fixture-longatt` + the blocklist kernel oracle).
12347        //
12348        // AUTO engages when the block-list form reads STRICTLY FEWER KV rows than the
12349        // dense form — i.e. as soon as the indexer actually drops blocks (any non-full
12350        // row, which on real geometry means position >= 2051) — and always past the
12351        // masked kernel's smem bound. This is where QSA's bounded-attention claim
12352        // becomes real: the dense mask still READS every t_kv row (the mask only zeroes
12353        // scores), so masked decode is O(context) bytes, while the block-list form reads
12354        // the <= 2052 selected rows at ANY depth. Measured motivation (smoke ladder,
12355        // yarn-1M, KV on card 1): masked decode at a 4k fill spent 97% of the token in
12356        // `qsa.sdpa` at 673 ms/token. Below the drop point every row IS the full prefix,
12357        // so the two forms read the same rows and AUTO keeps the historical masked path
12358        // (byte-stable receipts). `MEMRA_Q4E_SEAMS=longatt` forces it for the gate A/B;
12359        // `longatt=0` restores the masked-only behavior (and its long-context refusal).
12360        // kvq lane: the quantized cache has no masked-kernel form — the block-list
12361        // program (with in-place dequant) is the ONLY read path, at every depth. Below
12362        // the drop point every row is the full prefix, so the block-list form reads the
12363        // same rows the masked kernel would; there is no byte-stability question because
12364        // a quantized state has no historical masked receipts.
12365        let long_att = if kv.is_quant() {
12366            if longatt_mode() == LongAttMode::Off {
12367                return Err(
12368                    "qwen4exp_gpu: kvq requires the block-list attention form (longatt=off)".into(),
12369                );
12370            }
12371            true
12372        } else {
12373            match longatt_mode() {
12374                LongAttMode::Force => true,
12375                LongAttMode::Auto => t_kv > SDPA_MASK_TKV_BOUND || sels.iter().any(|s| !s.full),
12376                LongAttMode::Off => false,
12377            }
12378        };
12379        let block_size = overlay.block_size as usize;
12380        let attended = if long_att {
12381            let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
12382            let pos_dev = prof_section(e, "qsa.mask_h2d", || {
12383                ws.take_i32(e, "qsa.selpos", &pos_flat, 0)
12384            })?;
12385            let meta_dev = ws.take_i32(e, "qsa.selmeta", &meta, 0)?;
12386            let attended = prof_section(e, "qsa.sdpa", || {
12387                let mut attended = ws.take_f32(e, "qsa.att", t * nh * hd, 0)?;
12388                match kv {
12389                    QsaKvStore::F32 { k, v } => {
12390                        let k_view = k.slice(0..t_kv * nkv * hd);
12391                        let v_view = v.slice(0..t_kv * nkv * hd);
12392                        launch_sdpa_blocklist(
12393                            e,
12394                            &q,
12395                            &k_view,
12396                            &v_view,
12397                            &mut attended,
12398                            &pos_dev,
12399                            &meta_dev,
12400                            hd,
12401                            nh,
12402                            nkv,
12403                            t,
12404                            max_count,
12405                            scale,
12406                        )?;
12407                    }
12408                    QsaKvStore::Q8Q5 { k, v } => {
12409                        launch_q4e_sdpa_blocklist_q8q5(
12410                            e,
12411                            &q,
12412                            k,
12413                            v,
12414                            &mut attended,
12415                            &pos_dev,
12416                            &meta_dev,
12417                            hd,
12418                            nh,
12419                            nkv,
12420                            t,
12421                            max_count,
12422                            scale,
12423                        )?;
12424                    }
12425                }
12426                Ok(attended)
12427            })?;
12428            ws.put_i32("qsa.selpos", pos_dev);
12429            ws.put_i32("qsa.selmeta", meta_dev);
12430            attended
12431        } else {
12432            let QsaKvStore::F32 { k, v } = &*kv else {
12433                return Err("qwen4exp_gpu: masked SDPA reached with a quantized cache".into());
12434            };
12435            let mask = rowsel_to_mask(&sels, block_size, t_kv);
12436            let mask_dev = prof_section(e, "qsa.mask_h2d", || {
12437                // Masked-kernel rows never exceed the smem bound, so the slot reserve is
12438                // bounded even on a long-context-capacity state.
12439                ws.take_u8_h2d(e, "qsa.mask", &mask, t * cap.min(SDPA_MASK_TKV_BOUND))
12440            })?;
12441            let attended = prof_section(e, "qsa.sdpa", || {
12442                let mut attended = ws.take_f32(e, "qsa.att", t * nh * hd, 0)?;
12443                let k_view = k.slice(0..t_kv * nkv * hd);
12444                let v_view = v.slice(0..t_kv * nkv * hd);
12445                launch_sdpa_mask(
12446                    e,
12447                    &q,
12448                    &k_view,
12449                    &v_view,
12450                    &mut attended,
12451                    &mask_dev,
12452                    hd,
12453                    nh,
12454                    nkv,
12455                    t,
12456                    t_kv,
12457                    scale,
12458                )?;
12459                Ok(attended)
12460            })?;
12461            ws.put_u8("qsa.mask", mask_dev);
12462            attended
12463        };
12464        ws.put_f32(
12465            if qsa.q_norm.is_some() {
12466                "qsa.qn"
12467            } else {
12468                "qsa.q"
12469            },
12470            q,
12471        );
12472        let out = prof_section(e, "qsa.gate_wo", || {
12473            // fused per-(head, dim) sigmoid output gate (family convention).
12474            let mut sg = ws.take_f32(e, "qsa.sg", t * nh * hd, 0)?;
12475            e.sigmoid(&gate, &mut sg, t * nh * hd)?;
12476            let mut gated = ws.take_f32(e, "qsa.gated", t * nh * hd, 0)?;
12477            e.mul(&attended, &sg, &mut gated, t * nh * hd)?;
12478            let mut out = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
12479            linear_trunk_into(
12480                e,
12481                &qsa.wo,
12482                &qsa.wo_b16,
12483                &gated,
12484                &mut out,
12485                t,
12486                nh * hd,
12487                hidden,
12488            )?;
12489            ws.put_f32("qsa.sg", sg);
12490            ws.put_f32("qsa.gated", gated);
12491            Ok(out)
12492        })?;
12493        ws.put_f32("qsa.att", attended);
12494        ws.put_f32("qsa.gate", gate);
12495        Ok(out)
12496    }
12497
12498    /// GDN layer (`gated_delta_net` twin): fused qkv/z/beta/alpha projections, causal
12499    /// conv (dilation 1, silu) over cached raw rows, the geometry-generic sequential scan,
12500    /// gated RMSNorm with the family's SIGMOID z-gate (SEMANTICS.md §GDN).
12501    #[allow(clippy::too_many_arguments)]
12502    fn gdn_forward(
12503        &self,
12504        e: &Engine,
12505        ws: &mut StepPool,
12506        layer: &LayerW,
12507        gdn: &GdnW,
12508        mixed: &CudaSlice<f32>,
12509        mstate: &mut MixerState,
12510        t: usize,
12511        // Verify-exact stash (mtp-spec): Some => per-token scan (each column the t == 1
12512        // decode kernel dispatch, bit-identical) + per-column state snapshots + the
12513        // chunk's conv-rewind inputs.
12514        mut stash: Option<&mut GdnStash>,
12515    ) -> Res<CudaSlice<f32>> {
12516        let MixerState::Gdn { conv, state } = mstate else {
12517            return Err(format!(
12518                "qwen4exp_gpu: GDN layer {} bound to non-GDN state",
12519                layer.index
12520            )
12521            .into());
12522        };
12523        let hidden = self.hidden;
12524        let p = &gdn.plan;
12525        let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
12526        let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
12527        let kernel = p.conv_kernel as usize;
12528        let pad = kernel - 1;
12529        let conv_dim = 2 * nk * hk + nv * hv;
12530        let eps = layer.eps_attn;
12531
12532        let (qkv, z, beta_raw, g_log) = prof_section(e, "gdn.proj", || {
12533            let mut qkv = ws.take_f32(e, "gdn.qkv", t * conv_dim, 0)?;
12534            let mut z = ws.take_f32(e, "gdn.z", t * nv * hv, 0)?;
12535            let mut beta_raw = ws.take_f32(e, "gdn.beta", t * nv, 0)?;
12536            let mut alpha = ws.take_f32(e, "gdn.alpha", t * nv, 0)?;
12537            // Proj stack (round 4): the 4 same-activation projections in ONE launch over
12538            // the row-stacked twin; per-row bit-identical to the per-mat launches (the
12539            // OFF arm reads row-offset views of the SAME stack — same bytes, same
12540            // kernel, VRAM-neutral residency).
12541            if let (true, Some(stack)) = (
12542                t == 1 && proj_stack_on() && trunk_bf16_on(),
12543                gdn.proj_b16.as_ref(),
12544            ) {
12545                launch_qmatvec_bf16w_multi4(
12546                    e,
12547                    stack,
12548                    mixed,
12549                    &[
12550                        (&qkv, conv_dim),
12551                        (&z, nv * hv),
12552                        (&beta_raw, nv),
12553                        (&alpha, nv),
12554                    ],
12555                    hidden,
12556                )?;
12557            } else {
12558                linear_trunk_stacked_into(
12559                    e,
12560                    &gdn.qkv,
12561                    &gdn.proj_b16,
12562                    0,
12563                    mixed,
12564                    &mut qkv,
12565                    t,
12566                    hidden,
12567                    conv_dim,
12568                )?;
12569                linear_trunk_stacked_into(
12570                    e,
12571                    &gdn.z,
12572                    &gdn.proj_b16,
12573                    conv_dim,
12574                    mixed,
12575                    &mut z,
12576                    t,
12577                    hidden,
12578                    nv * hv,
12579                )?;
12580                linear_trunk_stacked_into(
12581                    e,
12582                    &gdn.beta,
12583                    &gdn.proj_b16,
12584                    conv_dim + nv * hv,
12585                    mixed,
12586                    &mut beta_raw,
12587                    t,
12588                    hidden,
12589                    nv,
12590                )?;
12591                linear_trunk_stacked_into(
12592                    e,
12593                    &gdn.alpha,
12594                    &gdn.proj_b16,
12595                    conv_dim + nv * hv + nv,
12596                    mixed,
12597                    &mut alpha,
12598                    t,
12599                    hidden,
12600                    nv,
12601                )?;
12602            }
12603            let mut g_log = ws.take_f32(e, "gdn.glog", t * nv, 0)?;
12604            e.gdn_glog_v(&alpha.slice(0..t * nv), &gdn.dt, &gdn.a, &mut g_log, nv, t)?;
12605            ws.put_f32("gdn.alpha", alpha);
12606            Ok((qkv, z, beta_raw, g_log))
12607        })?;
12608
12609        let o = prof_section(e, "gdn.conv_scan", || {
12610            // Verify stash: the pre-chunk conv history + the chunk's raw rows are the
12611            // rewind rebuild inputs (pure retains — no kernel sees them). Kept OUTSIDE the
12612            // segment graph: they are the only part whose destination is the stash itself.
12613            if let Some(st) = stash.as_deref_mut() {
12614                e.copy_range_into(&mut st.conv_pre, 0, conv, 0, pad * conv_dim)?;
12615                e.copy_range_into(&mut st.qkv_rows, 0, &qkv, 0, t * conv_dim)?;
12616            }
12617            // Slots are taken (and so ALLOCATED, if this is their first use) before any
12618            // capture region opens; addresses are stable from here on.
12619            let mut conv_out = ws.take_f32(e, "gdn.conv_out", t * conv_dim, 0)?;
12620            let mut o = ws.take_f32(e, "gdn.o", t * nv * hv, 0)?;
12621            let mut tmp = if t >= pad {
12622                None
12623            } else {
12624                Some(ws.take_f32(e, "gdn.tmp", (pad - t) * conv_dim, 0)?)
12625            };
12626            let scale = 1.0 / (hk as f32).sqrt();
12627            let step_ok = gdn_step_on() && hk % 32 == 0 && hk <= 1024;
12628            // The dwconv -> per-column scan -> conv-history roll chain, as ONE callable
12629            // unit so the eager arm and the captured arm run the IDENTICAL launch
12630            // sequence (the graph A/B's bit-identity is by construction, not by review).
12631            //
12632            // Decode-step twin (perf round 3): one state element per thread instead of
12633            // one state row — geometry guard keeps the tiny plan (hk 4) on the naive
12634            // kernel; prefill (t > 1) always takes the naive sequential scan. VERIFY
12635            // chunks (stash Some) run per-token launches of the SAME dispatch decode
12636            // takes (step when the guard admits, else naive-at-1) with a per-column
12637            // state snapshot after each token — the rewind checkpoints.
12638            let chain = |eng: &Engine,
12639                         conv: &mut CudaSlice<f32>,
12640                         state: &mut CudaSlice<f32>,
12641                         states_snap: Option<&mut CudaSlice<f32>>,
12642                         conv_out: &mut CudaSlice<f32>,
12643                         o: &mut CudaSlice<f32>,
12644                         tmp: Option<&mut CudaSlice<f32>>|
12645             -> Res<()> {
12646                launch_dwconv(
12647                    eng,
12648                    &qkv,
12649                    conv,
12650                    &gdn.conv_w,
12651                    conv_out,
12652                    t,
12653                    pad,
12654                    conv_dim,
12655                    kernel,
12656                    1,
12657                    1,
12658                )?;
12659                match states_snap {
12660                    Some(states) => {
12661                        let state_len = nv * hv * hk;
12662                        for tok in 0..t {
12663                            if step_ok {
12664                                launch_gdn_scan_step_at(
12665                                    eng, conv_out, &g_log, &beta_raw, state, o, tok, nk, nv, hk,
12666                                    hv, scale, eps,
12667                                )?;
12668                            } else {
12669                                launch_gdn_scan_at(
12670                                    eng, conv_out, &g_log, &beta_raw, state, o, tok, nk, nv, hk,
12671                                    hv, scale, eps,
12672                                )?;
12673                            }
12674                            eng.copy_range_into(states, tok * state_len, state, 0, state_len)?;
12675                        }
12676                    }
12677                    None if t == 1 && step_ok => {
12678                        launch_gdn_scan_step(
12679                            eng, conv_out, &g_log, &beta_raw, state, o, nk, nv, hk, hv, scale, eps,
12680                        )?;
12681                    }
12682                    None => {
12683                        launch_gdn_scan(
12684                            eng, conv_out, &g_log, &beta_raw, state, o, nk, nv, hk, hv, t, scale,
12685                            eps,
12686                        )?;
12687                    }
12688                }
12689                // conv history <- last `pad` raw qkv rows (zeros keep their place when
12690                // t < pad).
12691                if t >= pad {
12692                    eng.copy_range_into(conv, 0, &qkv, (t - pad) * conv_dim, pad * conv_dim)?;
12693                } else {
12694                    let keep = pad - t;
12695                    let tmp = tmp.ok_or("qwen4exp_gpu: gdn conv roll needs the tmp slot")?;
12696                    eng.copy_range_into(tmp, 0, conv, t * conv_dim, keep * conv_dim)?;
12697                    eng.copy_range_into(conv, 0, tmp, 0, keep * conv_dim)?;
12698                    eng.copy_range_into(conv, keep * conv_dim, &qkv, 0, t * conv_dim)?;
12699                }
12700                Ok(())
12701            };
12702            // Segment graph (mtp9, default OFF): only the verify shape is graphed — plain
12703            // decode already has its own whole-interior graph, and prefill shapes vary.
12704            let graphable = stash.is_some() && verify_graphs_on() && step_ws_on() && !prof::on();
12705            match stash.as_deref_mut() {
12706                Some(st) if graphable => {
12707                    // Take the graph out so the snapshot buffer can be borrowed mutably.
12708                    // A different chunk width invalidates the capture (baked shapes).
12709                    let entry = match st.scan_graph.take() {
12710                        Some((gt, g)) if gt == t => Some(g),
12711                        _ => None,
12712                    };
12713                    let warm = st.scan_warm == Some(t);
12714                    st.scan_warm = Some(t);
12715                    // EXACTLY ONE of the three arms executes the chain once.
12716                    let entry = match (warm, entry) {
12717                        // First chunk at this width: eager, so every slot is allocated
12718                        // and parked before any capture region opens.
12719                        (false, _) => {
12720                            chain(
12721                                e,
12722                                conv,
12723                                state,
12724                                Some(&mut st.states),
12725                                &mut conv_out,
12726                                &mut o,
12727                                tmp.as_mut(),
12728                            )?;
12729                            None
12730                        }
12731                        // Captured at this width already: replay, no eager pass.
12732                        (true, Some(g)) => {
12733                            g.0.launch()?;
12734                            Some(g)
12735                        }
12736                        // Warm but not yet captured: capture WITHOUT executing
12737                        // (`nowarm`), then launch once — capture + launch is exactly one
12738                        // execution, so the column snapshots and the state advance happen
12739                        // exactly once.
12740                        (true, None) => {
12741                            let states = &mut st.states;
12742                            let mut tmp_ref = tmp.as_mut();
12743                            let g = e.capture_graph_retained_nowarm(|eng| {
12744                                chain(
12745                                    eng,
12746                                    conv,
12747                                    state,
12748                                    Some(states),
12749                                    &mut conv_out,
12750                                    &mut o,
12751                                    tmp_ref.as_deref_mut(),
12752                                )
12753                            })?;
12754                            g.0.launch()?;
12755                            Some(g)
12756                        }
12757                    };
12758                    if let Some(g) = entry {
12759                        st.scan_graph = Some((t, g));
12760                    }
12761                }
12762                Some(st) => chain(
12763                    e,
12764                    conv,
12765                    state,
12766                    Some(&mut st.states),
12767                    &mut conv_out,
12768                    &mut o,
12769                    tmp.as_mut(),
12770                )?,
12771                None => chain(e, conv, state, None, &mut conv_out, &mut o, tmp.as_mut())?,
12772            }
12773            ws.put_f32("gdn.conv_out", conv_out);
12774            if let Some(tmp) = tmp {
12775                ws.put_f32("gdn.tmp", tmp);
12776            }
12777            Ok(o)
12778        })?;
12779        ws.put_f32("gdn.qkv", qkv);
12780        ws.put_f32("gdn.beta", beta_raw);
12781        ws.put_f32("gdn.glog", g_log);
12782
12783        let out = prof_section(e, "gdn.norm_gate_out", || {
12784            let mut gated = ws.take_f32(e, "gdn.gated", t * nv * hv, 0)?;
12785            match p.gate_activation {
12786                // Fused norm+gate (perf round 3): one launch, bit-identical to the
12787                // rms_norm + sigmoid + mul chain below (rms_sigmul_f32 kernel doc).
12788                GdnGateActivation::Sigmoid if gdn_fuse_on() => {
12789                    launch_rms_sigmul(e, &o, &gdn.norm, &z, &mut gated, hv, t * nv, eps)?;
12790                }
12791                GdnGateActivation::Sigmoid => {
12792                    let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
12793                    e.rms_norm(&o, &gdn.norm, &mut normed, hv, t * nv, eps)?;
12794                    let mut sg = ws.take_f32(e, "gdn.sg", t * nv * hv, 0)?;
12795                    e.sigmoid(&z, &mut sg, t * nv * hv)?;
12796                    e.mul(&normed, &sg, &mut gated, t * nv * hv)?;
12797                    ws.put_f32("gdn.sg", sg);
12798                    ws.put_f32("gdn.normed", normed);
12799                }
12800                GdnGateActivation::Silu => {
12801                    let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
12802                    e.rms_norm(&o, &gdn.norm, &mut normed, hv, t * nv, eps)?;
12803                    e.silu_mul(&z, &normed, &mut gated, t * nv * hv)?;
12804                    ws.put_f32("gdn.normed", normed);
12805                }
12806            }
12807            let mut out = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
12808            linear_trunk_into(
12809                e,
12810                &gdn.out,
12811                &gdn.out_b16,
12812                &gated,
12813                &mut out,
12814                t,
12815                nv * hv,
12816                hidden,
12817            )?;
12818            ws.put_f32("gdn.gated", gated);
12819            Ok(out)
12820        })?;
12821        ws.put_f32("gdn.z", z);
12822        ws.put_f32("gdn.o", o);
12823        Ok(out)
12824    }
12825
12826    /// MoE (`moe_mlp` twin): device router GEMM, HOST softmax-top-k routing (reference
12827    /// tie rule + renorm floor), per-expert gathered GEMMs, slot scatter/FMA-reduce, and
12828    /// the sigmoid-gated shared expert.
12829    fn moe_forward(
12830        &self,
12831        e: &Engine,
12832        ws: &mut StepPool,
12833        moe: &MoeW,
12834        mixed: &CudaSlice<f32>,
12835        t: usize,
12836        // Rows mode (MTP draft + spec verify chunks): at t > 1, run the GROUPED decode
12837        // program per TOKEN — each token's launch sequence is the t == 1 program
12838        // verbatim (bit-identical rows), instead of the prefill per-expert executor.
12839        rows_grouped: bool,
12840        // Layer index, for the shared-format MoE route trace only (`MEMRA_MOE_TRACE`); it does
12841        // not select any behaviour. Threaded rather than kept in a thread-local because a hidden
12842        // ambient layer id is the kind of state that mislabels a whole trace file silently.
12843        layer: u32,
12844    ) -> Res<CudaSlice<f32>> {
12845        let hidden = self.hidden;
12846        let experts = moe.plan.expert_count as usize;
12847        let selected = moe.plan.experts_per_token as usize;
12848        let ff = moe.plan.expert_intermediate_size as usize;
12849
12850        // Device router engage (devtwin lane): grouped dispatch only — those consumers
12851        // read device sel/w(/tok) arrays, so the route never crosses. NVFP4 (trunk):
12852        // t == 1 decode or the merged verify path (the per-token grouped twin addresses
12853        // its sel slot per token, which needs the host arrays). DeviceBf16 (the card-1
12854        // draft bank, devtwin stage 2): all rows-mode shapes via `qmatvec_bf16w_sel_f32`
12855        // (per-token launches read sel at a device offset — no host expert ids). The
12856        // per-expert prefill executor keeps the host twin (host-gathered rows by
12857        // construction).
12858        let nvfp4_bank = matches!(
12859            (&moe.bank.gate, &moe.bank.up, &moe.bank.down),
12860            (
12861                BankHalf::Nvfp4 { .. },
12862                BankHalf::Nvfp4 { .. },
12863                BankHalf::Nvfp4 { .. }
12864            )
12865        );
12866        let devbf16_bank = matches!(
12867            (&moe.bank.gate, &moe.bank.up, &moe.bank.down),
12868            (
12869                BankHalf::DeviceBf16(_),
12870                BankHalf::DeviceBf16(_),
12871                BankHalf::DeviceBf16(_)
12872            )
12873        );
12874        let use_dev_router = router_dev_on()
12875            && moe_sel_path_on()
12876            && route_dev_geometry(experts, selected)
12877            && ((nvfp4_bank
12878                && hidden % 32 == 0
12879                && ff % 4 == 0
12880                && (t == 1
12881                    || (rows_grouped
12882                        && verify_mt_on()
12883                        && sel_gufuse_on()
12884                        && t * selected <= 8192)))
12885                || (devbf16_bank && hidden % 8 == 0 && ff % 8 == 0 && (t == 1 || rows_grouped)));
12886        // (routes, device route). Exactly one is populated: host routes for the host
12887        // twin arms, or the device sel/w(/tok) triplet for the grouped device arms.
12888        type DevRoute = (CudaSlice<i32>, CudaSlice<f32>, Option<CudaSlice<i32>>);
12889        let (routes, mut dev_route): (Vec<Vec<(usize, f32)>>, Option<DevRoute>) =
12890            prof_section(e, "moe.router", || {
12891                let mut router_out = ws.take_f32(e, "moe.router", t * experts, 0)?;
12892                let none: Option<CudaSlice<u8>> = None;
12893                let rb = if router_bf16_on() {
12894                    &moe.router_b16
12895                } else {
12896                    &none
12897                };
12898                linear_trunk_into(
12899                    e,
12900                    &moe.router,
12901                    rb,
12902                    mixed,
12903                    &mut router_out,
12904                    t,
12905                    hidden,
12906                    experts,
12907                )?;
12908                if use_dev_router {
12909                    let mut sel = ws.take_i32_slot(e, "moe.sel", t * selected, 0)?;
12910                    let mut w = ws.take_f32(e, "moe.w", t * selected, 0)?;
12911                    let mut tokm = if t > 1 {
12912                        Some(ws.take_i32_slot(e, "moe.tok", t * selected, 0)?)
12913                    } else {
12914                        None
12915                    };
12916                    route_topk_device(
12917                        e,
12918                        &router_out,
12919                        &mut sel,
12920                        &mut w,
12921                        tokm.as_mut().map(|m| (m, 0)),
12922                        experts,
12923                        selected,
12924                        t,
12925                        layer,
12926                    )?;
12927                    ws.put_f32("moe.router", router_out);
12928                    return Ok((Vec::new(), Some((sel, w, tokm))));
12929                }
12930                let logits = e.dtoh_view(&router_out.slice(0..t * experts))?;
12931                ws.put_f32("moe.router", router_out);
12932                let mut routes: Vec<Vec<(usize, f32)>> = Vec::with_capacity(t);
12933                for token in 0..t {
12934                    routes.push(host_route_softmax_topk(
12935                        &logits[token * experts..(token + 1) * experts],
12936                        selected,
12937                    ));
12938                }
12939                Ok((routes, None))
12940            })?;
12941        // Grouped decode path (perf-lane attack (a)): one kernel launch per PROJECTION
12942        // covers every selected expert — the per-expert dispatch below (dequant chain +
12943        // three tiny GEMVs + scatter per routed expert, ~52% of the decode token in
12944        // PROFILE-0) collapses to 6 launches per layer. NVFP4 banks + single-token decode
12945        // only (prefill keeps the gathered per-expert path); W4A16 — the kernel computes
12946        // the eager dequant chain's per-element products with a different summation order
12947        // (accumulation class, kernel doc), gated by the tiny four-arm + real gates.
12948        if (t == 1 || rows_grouped) && moe_sel_path_on() {
12949            if let (
12950                BankHalf::Nvfp4 {
12951                    codes: gc,
12952                    scales: gs,
12953                    macros_dev: gm,
12954                    ..
12955                },
12956                BankHalf::Nvfp4 {
12957                    codes: uc,
12958                    scales: us,
12959                    macros_dev: um,
12960                    ..
12961                },
12962                BankHalf::Nvfp4 {
12963                    codes: dc,
12964                    scales: ds,
12965                    macros_dev: dm,
12966                    ..
12967                },
12968            ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
12969            {
12970                // Merged verify columns (set_verify_mt): ONE gufuse launch over every
12971                // column's routed experts via the slot->token map + ONE down launch over
12972                // all slots + per-token windowed combines. Per-slot programs and the
12973                // per-token combine order are the decode program VERBATIM (bit-identical);
12974                // launch count per layer drops from 3t to 2 + t combines.
12975                if t > 1 && verify_mt_on() && sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
12976                    // Device-routed merged verify (devtwin): ONE batch (the engage
12977                    // guard bounds t*selected <= 8192 <= SLOT_CAP), per-slot programs
12978                    // and the per-token combine order the decode program VERBATIM —
12979                    // bit-identical rows; only the route's residency changed. The
12980                    // slot->token map comes from the route kernel, not a host build.
12981                    if let Some((sel, w_dev, tokm)) = dev_route.take() {
12982                        let tokm =
12983                            tokm.ok_or("moe_forward: device route at t > 1 without a tok map")?;
12984                        let out = prof_section(e, "moe.sel_grouped", || {
12985                            let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
12986                            let s_total = t * selected;
12987                            let mut act = ws.take_f32(e, "moe.act", s_total * ff, 0)?;
12988                            launch_nvfp4_sel_gu_silu(
12989                                e,
12990                                (gc, gs, gm),
12991                                (uc, us, um),
12992                                Some(&sel),
12993                                0,
12994                                s_total,
12995                                mixed,
12996                                &mut act,
12997                                hidden,
12998                                ff,
12999                                Some((&tokm, hidden)),
13000                            )?;
13001                            let mut partial = ws.take_f32(e, "moe.partial", s_total * hidden, 0)?;
13002                            launch_nvfp4_sel_matvec(
13003                                e,
13004                                dc,
13005                                ds,
13006                                dm,
13007                                &sel,
13008                                &act,
13009                                &mut partial,
13010                                s_total,
13011                                ff,
13012                                hidden,
13013                                ff,
13014                            )?;
13015                            for tok in 0..t {
13016                                launch_axpy_rows_seq_at(
13017                                    e,
13018                                    &partial,
13019                                    tok * selected,
13020                                    &w_dev,
13021                                    tok * selected,
13022                                    &mut out,
13023                                    tok,
13024                                    hidden,
13025                                    selected,
13026                                )?;
13027                            }
13028                            ws.put_i32("moe.sel", sel);
13029                            ws.put_i32("moe.tok", tokm);
13030                            ws.put_f32("moe.w", w_dev);
13031                            ws.put_f32("moe.act", act);
13032                            ws.put_f32("moe.partial", partial);
13033                            Ok(out)
13034                        })?;
13035                        return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13036                    }
13037                    let out = prof_section(e, "moe.sel_grouped", || {
13038                        let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
13039                        // Slot sub-batching: the grouped kernels index slots on grid.y,
13040                        // which CUDA caps at 65,535 — a long-context prefill chunk
13041                        // (t 8192 x 10 selected = 81,920 slots) overflowed it with
13042                        // CUDA_ERROR_INVALID_VALUE (smoke ladder, rung 32768). Sub-batches
13043                        // also bound the transients (act s*ff, partial s*hidden) on a card
13044                        // already holding the trunk. Sub-batching changes NOTHING per slot
13045                        // or per token: each slot's program and each token's combine order
13046                        // are identical to one big batch (and to the t == 1 decode
13047                        // program) — the boundary only splits launches.
13048                        const SLOT_CAP: usize = 8192;
13049                        let tok_step = (SLOT_CAP / selected.max(1)).max(1);
13050                        let mut tok0 = 0usize;
13051                        while tok0 < t {
13052                            let tok_n = tok_step.min(t - tok0);
13053                            let batch = &routes[tok0..tok0 + tok_n];
13054                            let mut sel_all: Vec<i32> = Vec::with_capacity(tok_n * selected);
13055                            let mut w_all: Vec<f32> = Vec::with_capacity(tok_n * selected);
13056                            let mut tok_all: Vec<i32> = Vec::with_capacity(tok_n * selected);
13057                            let mut ranges: Vec<(usize, usize)> = Vec::with_capacity(tok_n);
13058                            for (i, route) in batch.iter().enumerate() {
13059                                ranges.push((sel_all.len(), route.len()));
13060                                for &(eid, wgt) in route {
13061                                    sel_all.push(eid as i32);
13062                                    w_all.push(wgt);
13063                                    // ABSOLUTE token index: the kernel reads the
13064                                    // activation row at tok * hidden from the same
13065                                    // `mixed` buffer, so a sub-batch reads exactly the
13066                                    // rows one big batch would (no view, no offset math).
13067                                    tok_all.push((tok0 + i) as i32);
13068                                }
13069                            }
13070                            let s_total = sel_all.len();
13071                            let sel = ws.take_i32(e, "moe.sel", &sel_all, 0)?;
13072                            let w_dev = ws.take_f32_h2d(e, "moe.w", &w_all, 0)?;
13073                            let tokm = ws.take_i32(e, "moe.tok", &tok_all, 0)?;
13074                            let mut act = ws.take_f32(e, "moe.act", s_total * ff, 0)?;
13075                            launch_nvfp4_sel_gu_silu(
13076                                e,
13077                                (gc, gs, gm),
13078                                (uc, us, um),
13079                                Some(&sel),
13080                                0,
13081                                s_total,
13082                                mixed,
13083                                &mut act,
13084                                hidden,
13085                                ff,
13086                                Some((&tokm, hidden)),
13087                            )?;
13088                            let mut partial = ws.take_f32(e, "moe.partial", s_total * hidden, 0)?;
13089                            launch_nvfp4_sel_matvec(
13090                                e,
13091                                dc,
13092                                ds,
13093                                dm,
13094                                &sel,
13095                                &act,
13096                                &mut partial,
13097                                s_total,
13098                                ff,
13099                                hidden,
13100                                ff,
13101                            )?;
13102                            for (i, &(start, len)) in ranges.iter().enumerate() {
13103                                launch_axpy_rows_seq_at(
13104                                    e,
13105                                    &partial,
13106                                    start,
13107                                    &w_dev,
13108                                    start,
13109                                    &mut out,
13110                                    tok0 + i,
13111                                    hidden,
13112                                    len,
13113                                )?;
13114                            }
13115                            ws.put_i32("moe.sel", sel);
13116                            ws.put_i32("moe.tok", tokm);
13117                            ws.put_f32("moe.w", w_dev);
13118                            ws.put_f32("moe.act", act);
13119                            ws.put_f32("moe.partial", partial);
13120                            tok0 += tok_n;
13121                        }
13122                        Ok(out)
13123                    })?;
13124                    return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13125                }
13126                // Device-routed decode step (devtwin, t == 1 by the engage guard): the
13127                // grouped decode program launch-for-launch, sel/w read from the device
13128                // route — bit-identical to the host-routed chain on the same selection.
13129                if let Some((sel, w_dev, _)) = dev_route.take() {
13130                    let out = prof_section(e, "moe.sel_grouped", || {
13131                        let mut out = ws.take_f32(e, "moe.out", hidden, 0)?;
13132                        let mut act = ws.take_f32(e, "moe.act", selected * ff, 0)?;
13133                        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
13134                            launch_nvfp4_sel_gu_silu(
13135                                e,
13136                                (gc, gs, gm),
13137                                (uc, us, um),
13138                                Some(&sel),
13139                                0,
13140                                selected,
13141                                mixed,
13142                                &mut act,
13143                                hidden,
13144                                ff,
13145                                None,
13146                            )?;
13147                        } else {
13148                            let mut yg = ws.take_f32(e, "moe.yg", selected * ff, 0)?;
13149                            let mut yu = ws.take_f32(e, "moe.yu", selected * ff, 0)?;
13150                            launch_nvfp4_sel_matvec(
13151                                e, gc, gs, gm, &sel, mixed, &mut yg, selected, hidden, ff, 0,
13152                            )?;
13153                            launch_nvfp4_sel_matvec(
13154                                e, uc, us, um, &sel, mixed, &mut yu, selected, hidden, ff, 0,
13155                            )?;
13156                            e.silu_mul(&yg, &yu, &mut act, selected * ff)?;
13157                            ws.put_f32("moe.yg", yg);
13158                            ws.put_f32("moe.yu", yu);
13159                        }
13160                        let mut partial = ws.take_f32(e, "moe.partial", selected * hidden, 0)?;
13161                        launch_nvfp4_sel_matvec(
13162                            e,
13163                            dc,
13164                            ds,
13165                            dm,
13166                            &sel,
13167                            &act,
13168                            &mut partial,
13169                            selected,
13170                            ff,
13171                            hidden,
13172                            ff,
13173                        )?;
13174                        e.axpy_rows_seq_into(&partial, &w_dev, &mut out, hidden, selected)?;
13175                        ws.put_i32("moe.sel", sel);
13176                        ws.put_f32("moe.w", w_dev);
13177                        ws.put_f32("moe.act", act);
13178                        ws.put_f32("moe.partial", partial);
13179                        Ok(out)
13180                    })?;
13181                    return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13182                }
13183                let out = prof_section(e, "moe.sel_grouped", || {
13184                    let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
13185                    for (tok, route) in routes.iter().enumerate() {
13186                        let n_sel = route.len();
13187                        let sel_host: Vec<i32> = route.iter().map(|&(x, _)| x as i32).collect();
13188                        let w_host: Vec<f32> = route.iter().map(|&(_, w)| w).collect();
13189                        let sel = ws.take_i32(e, "moe.sel", &sel_host, 0)?;
13190                        let w_dev = ws.take_f32_h2d(e, "moe.w", &w_host, 0)?;
13191                        // Activation operand: t == 1 reads `mixed` in place (the decode
13192                        // program, launch-for-launch unchanged); rows mode stages the
13193                        // token's row in a stable slot (exact copy — the kernel reads
13194                        // identical values, so rows stay bit-identical to decode).
13195                        let x_tok = if t == 1 {
13196                            None
13197                        } else {
13198                            let mut x = ws.take_f32(e, "moe.x", hidden, 0)?;
13199                            e.copy_range_into(&mut x, 0, mixed, tok * hidden, hidden)?;
13200                            Some(x)
13201                        };
13202                        let x_ref = x_tok.as_ref().unwrap_or(mixed);
13203                        let mut act = ws.take_f32(e, "moe.act", n_sel * ff, 0)?;
13204                        // Fused gate+up+silu (round 4): ONE launch, bit-identical to the
13205                        // three-op chain below (kernel doc + oracle gufuse mode).
13206                        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
13207                            launch_nvfp4_sel_gu_silu(
13208                                e,
13209                                (gc, gs, gm),
13210                                (uc, us, um),
13211                                Some(&sel),
13212                                0,
13213                                n_sel,
13214                                x_ref,
13215                                &mut act,
13216                                hidden,
13217                                ff,
13218                                None,
13219                            )?;
13220                        } else {
13221                            let mut yg = ws.take_f32(e, "moe.yg", n_sel * ff, 0)?;
13222                            let mut yu = ws.take_f32(e, "moe.yu", n_sel * ff, 0)?;
13223                            launch_nvfp4_sel_matvec(
13224                                e, gc, gs, gm, &sel, x_ref, &mut yg, n_sel, hidden, ff, 0,
13225                            )?;
13226                            launch_nvfp4_sel_matvec(
13227                                e, uc, us, um, &sel, x_ref, &mut yu, n_sel, hidden, ff, 0,
13228                            )?;
13229                            e.silu_mul(&yg, &yu, &mut act, n_sel * ff)?;
13230                            ws.put_f32("moe.yg", yg);
13231                            ws.put_f32("moe.yu", yu);
13232                        }
13233                        let mut partial = ws.take_f32(e, "moe.partial", n_sel * hidden, 0)?;
13234                        launch_nvfp4_sel_matvec(
13235                            e,
13236                            dc,
13237                            ds,
13238                            dm,
13239                            &sel,
13240                            &act,
13241                            &mut partial,
13242                            n_sel,
13243                            ff,
13244                            hidden,
13245                            ff,
13246                        )?;
13247                        // Slot-ordered sequential combine (axpy_rows_seq_f32
13248                        // self-initializes); rows mode lands the row by exact copy.
13249                        if t == 1 {
13250                            e.axpy_rows_seq_into(&partial, &w_dev, &mut out, hidden, n_sel)?;
13251                        } else {
13252                            let mut row = ws.take_f32(e, "moe.row", hidden, 0)?;
13253                            e.axpy_rows_seq_into(&partial, &w_dev, &mut row, hidden, n_sel)?;
13254                            e.copy_range_into(&mut out, tok * hidden, &row, 0, hidden)?;
13255                            ws.put_f32("moe.row", row);
13256                        }
13257                        ws.put_i32("moe.sel", sel);
13258                        ws.put_f32("moe.w", w_dev);
13259                        ws.put_f32("moe.act", act);
13260                        ws.put_f32("moe.partial", partial);
13261                        if let Some(x) = x_tok {
13262                            ws.put_f32("moe.x", x);
13263                        }
13264                    }
13265                    Ok(out)
13266                })?;
13267                return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13268            }
13269            // DeviceBf16 bank (the MTP draft): per-selected-expert row-offset bf16
13270            // matvecs straight off the resident bytes — n_sel launches per projection
13271            // (arbitrary expert ids cannot batch through the strided kernel), silu and
13272            // combine exactly like the NVFP4 grouped chain.
13273            if let (BankHalf::DeviceBf16(gb), BankHalf::DeviceBf16(ub), BankHalf::DeviceBf16(db)) =
13274                (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
13275            {
13276                // Device-routed draft MoE (devtwin stage 2): per token, ONE
13277                // `qmatvec_bf16w_sel_f32` launch per projection reads its expert ids
13278                // from the device route at a sel offset — no host expert ids, no
13279                // per-slot launch chain. Per-row programs are the off_into chain
13280                // VERBATIM (kernel doc + the bf16 oracle's sel mode) and the combine
13281                // writes the same window `axpy_rows_seq` initialized — bit-identical.
13282                if let Some((sel, w_dev, _)) = dev_route.take() {
13283                    let out = prof_section(e, "moe.sel_bf16", || {
13284                        let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
13285                        for tok in 0..t {
13286                            let mut yg = ws.take_f32(e, "moe.yg", selected * ff, 0)?;
13287                            let mut yu = ws.take_f32(e, "moe.yu", selected * ff, 0)?;
13288                            launch_qmatvec_bf16w_sel(
13289                                e,
13290                                gb,
13291                                &sel,
13292                                tok * selected,
13293                                mixed,
13294                                tok * hidden,
13295                                0,
13296                                &mut yg,
13297                                selected,
13298                                hidden,
13299                                ff,
13300                            )?;
13301                            launch_qmatvec_bf16w_sel(
13302                                e,
13303                                ub,
13304                                &sel,
13305                                tok * selected,
13306                                mixed,
13307                                tok * hidden,
13308                                0,
13309                                &mut yu,
13310                                selected,
13311                                hidden,
13312                                ff,
13313                            )?;
13314                            let mut act = ws.take_f32(e, "moe.act", selected * ff, 0)?;
13315                            e.silu_mul(&yg, &yu, &mut act, selected * ff)?;
13316                            let mut partial =
13317                                ws.take_f32(e, "moe.partial", selected * hidden, 0)?;
13318                            launch_qmatvec_bf16w_sel(
13319                                e,
13320                                db,
13321                                &sel,
13322                                tok * selected,
13323                                &act,
13324                                0,
13325                                ff,
13326                                &mut partial,
13327                                selected,
13328                                ff,
13329                                hidden,
13330                            )?;
13331                            launch_axpy_rows_seq_at(
13332                                e,
13333                                &partial,
13334                                0,
13335                                &w_dev,
13336                                tok * selected,
13337                                &mut out,
13338                                tok,
13339                                hidden,
13340                                selected,
13341                            )?;
13342                            ws.put_f32("moe.yg", yg);
13343                            ws.put_f32("moe.yu", yu);
13344                            ws.put_f32("moe.act", act);
13345                            ws.put_f32("moe.partial", partial);
13346                        }
13347                        ws.put_i32("moe.sel", sel);
13348                        ws.put_f32("moe.w", w_dev);
13349                        Ok(out)
13350                    })?;
13351                    return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13352                }
13353                let out = prof_section(e, "moe.sel_bf16", || {
13354                    let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
13355                    for (tok, route) in routes.iter().enumerate() {
13356                        let n_sel = route.len();
13357                        let w_host: Vec<f32> = route.iter().map(|&(_, w)| w).collect();
13358                        let w_dev = ws.take_f32_h2d(e, "moe.w", &w_host, 0)?;
13359                        let mut yg = ws.take_f32(e, "moe.yg", n_sel * ff, 0)?;
13360                        let mut yu = ws.take_f32(e, "moe.yu", n_sel * ff, 0)?;
13361                        for (slot, &(eid, _)) in route.iter().enumerate() {
13362                            launch_qmatvec_bf16w_off_into(
13363                                e,
13364                                gb,
13365                                eid * ff,
13366                                mixed,
13367                                tok * hidden,
13368                                &mut yg,
13369                                slot * ff,
13370                                hidden,
13371                                ff,
13372                            )?;
13373                            launch_qmatvec_bf16w_off_into(
13374                                e,
13375                                ub,
13376                                eid * ff,
13377                                mixed,
13378                                tok * hidden,
13379                                &mut yu,
13380                                slot * ff,
13381                                hidden,
13382                                ff,
13383                            )?;
13384                        }
13385                        let mut act = ws.take_f32(e, "moe.act", n_sel * ff, 0)?;
13386                        e.silu_mul(&yg, &yu, &mut act, n_sel * ff)?;
13387                        let mut partial = ws.take_f32(e, "moe.partial", n_sel * hidden, 0)?;
13388                        for (slot, &(eid, _)) in route.iter().enumerate() {
13389                            launch_qmatvec_bf16w_off_into(
13390                                e,
13391                                db,
13392                                eid * hidden,
13393                                &act,
13394                                slot * ff,
13395                                &mut partial,
13396                                slot * hidden,
13397                                ff,
13398                                hidden,
13399                            )?;
13400                        }
13401                        let mut row = ws.take_f32(e, "moe.row", hidden, 0)?;
13402                        e.axpy_rows_seq_into(&partial, &w_dev, &mut row, hidden, n_sel)?;
13403                        e.copy_range_into(&mut out, tok * hidden, &row, 0, hidden)?;
13404                        ws.put_f32("moe.row", row);
13405                        ws.put_f32("moe.w", w_dev);
13406                        ws.put_f32("moe.yg", yg);
13407                        ws.put_f32("moe.yu", yu);
13408                        ws.put_f32("moe.act", act);
13409                        ws.put_f32("moe.partial", partial);
13410                    }
13411                    Ok(out)
13412                })?;
13413                return self.moe_shared_tail(e, ws, moe, mixed, out, t);
13414            }
13415        }
13416
13417        // A device route that reaches here would feed the per-expert executor EMPTY
13418        // host routes and silently compute nothing — fail loud instead (the engage
13419        // guard and the dispatch arms must stay in lockstep).
13420        if dev_route.is_some() {
13421            return Err(
13422                "moe_forward: device route left unconsumed (engage guard drifted from the \
13423                 dispatch arms)"
13424                    .into(),
13425            );
13426        }
13427        // expert -> [(token, slot, weight)]
13428        let mut by_expert: Vec<Vec<(i32, i32, f32)>> = vec![Vec::new(); experts];
13429        for (token, token_routes) in routes.iter().enumerate() {
13430            for (slot, &(expert, weight)) in token_routes.iter().enumerate() {
13431                by_expert[expert].push((token as i32, slot as i32, weight));
13432            }
13433        }
13434        let mut slots = e.zeros(t * selected * hidden)?;
13435        let mut wbuf = e.zeros(t * selected)?;
13436        for (expert, entries) in by_expert.iter().enumerate() {
13437            if entries.is_empty() {
13438                continue;
13439            }
13440            let m_e = entries.len();
13441            let (tok_dev, slot_dev, w_dev, xg) = prof_section(e, "moe.idx_gather", || {
13442                let tok_idx: Vec<i32> = entries.iter().map(|&(tok, _, _)| tok).collect();
13443                let slot_idx: Vec<i32> = entries.iter().map(|&(_, slot, _)| slot).collect();
13444                let weights: Vec<f32> = entries.iter().map(|&(_, _, w)| w).collect();
13445                let tok_dev = e.htod_i32(&tok_idx)?;
13446                let slot_dev = e.htod_i32(&slot_idx)?;
13447                let w_dev = e.htod(&weights)?;
13448                let mut xg = e.uninit(m_e * hidden)?;
13449                e.gather_rows(mixed, &tok_dev, &mut xg, hidden, m_e)?;
13450                Ok((tok_dev, slot_dev, w_dev, xg))
13451            })?;
13452            // Resolve this expert's operand views per bank half (F32 = view into the
13453            // resident bank; NVFP4 = per-expert kernel dequant into a transient f32).
13454            let resolve = |half: &BankHalf,
13455                           out_f: usize,
13456                           in_f: usize|
13457             -> Res<(Option<CudaSlice<f32>>, usize)> {
13458                match half {
13459                    BankHalf::F32(_) => Ok((None, expert * out_f * in_f)),
13460                    BankHalf::Nvfp4 {
13461                        codes,
13462                        scales,
13463                        macros,
13464                        ..
13465                    } => Ok((
13466                        Some(dequant_nvfp4_expert_f32(
13467                            e,
13468                            codes,
13469                            scales,
13470                            macros[expert],
13471                            expert,
13472                            out_f,
13473                            in_f,
13474                        )?),
13475                        0,
13476                    )),
13477                    // Host-resident bf16 bank: upload THIS expert's rows and upcast
13478                    // (exact) — the per-routed-expert twin of the load-time dequant.
13479                    BankHalf::HostBf16(bytes) => {
13480                        let row_bytes = out_f * in_f * 2;
13481                        let dev =
13482                            e.htod_bytes(&bytes[expert * row_bytes..(expert + 1) * row_bytes])?;
13483                        Ok((
13484                            Some(e.bf16_to_f32(&dev.slice(0..row_bytes), out_f * in_f)?),
13485                            0,
13486                        ))
13487                    }
13488                    // Device-resident bf16 bank (MTP draft): widen THIS expert's rows
13489                    // in place (exact) — the multi-token replay/prefill arm; the t == 1
13490                    // draft decode takes the grouped row-offset matvec path instead.
13491                    BankHalf::DeviceBf16(bytes) => {
13492                        let row_bytes = out_f * in_f * 2;
13493                        let view = bytes.slice(expert * row_bytes..(expert + 1) * row_bytes);
13494                        Ok((Some(e.bf16_to_f32(&view, out_f * in_f)?), 0))
13495                    }
13496                }
13497            };
13498            let ((gate_owned, gate_base), (up_owned, up_base), (down_owned, down_base)) =
13499                prof_section(e, "moe.dequant", || {
13500                    Ok((
13501                        resolve(&moe.bank.gate, ff, hidden)?,
13502                        resolve(&moe.bank.up, ff, hidden)?,
13503                        resolve(&moe.bank.down, hidden, ff)?,
13504                    ))
13505                })?;
13506            let gate_view = match (&moe.bank.gate, &gate_owned) {
13507                (_, Some(owned)) => owned.slice(0..ff * hidden),
13508                (BankHalf::F32(bank), None) => bank.slice(gate_base..gate_base + ff * hidden),
13509                (
13510                    BankHalf::Nvfp4 { .. } | BankHalf::HostBf16(_) | BankHalf::DeviceBf16(_),
13511                    None,
13512                ) => {
13513                    unreachable!("quantized/host/device-bf16 halves always resolve owned")
13514                }
13515            };
13516            let up_view = match (&moe.bank.up, &up_owned) {
13517                (_, Some(owned)) => owned.slice(0..ff * hidden),
13518                (BankHalf::F32(bank), None) => bank.slice(up_base..up_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 down_view = match (&moe.bank.down, &down_owned) {
13527                (_, Some(owned)) => owned.slice(0..hidden * ff),
13528                (BankHalf::F32(bank), None) => bank.slice(down_base..down_base + hidden * ff),
13529                (
13530                    BankHalf::Nvfp4 { .. } | BankHalf::HostBf16(_) | BankHalf::DeviceBf16(_),
13531                    None,
13532                ) => {
13533                    unreachable!("quantized/host/device-bf16 halves always resolve owned")
13534                }
13535            };
13536            prof_section(e, "moe.expert_gemms", || {
13537                let down_out =
13538                    run_routed_expert(e, &xg, &gate_view, &up_view, &down_view, m_e, hidden, ff)?;
13539                e.scatter_slot(
13540                    &down_out, &tok_dev, &slot_dev, &w_dev, &mut slots, &mut wbuf, hidden,
13541                    selected, m_e,
13542                )
13543            })?;
13544        }
13545        let out = prof_section(e, "moe.reduce", || {
13546            let mut out = e.zeros(t * hidden)?;
13547            e.reduce_slots(&slots, &wbuf, &mut out, hidden, selected, t)?;
13548            Ok(out)
13549        })?;
13550        self.moe_shared_tail(e, ws, moe, mixed, out, t)
13551    }
13552
13553    /// Shared expert, sigmoid input gate (Qwen3NextSparseMoeBlock convention) — the
13554    /// common tail of both routed-expert executors.
13555    fn moe_shared_tail(
13556        &self,
13557        e: &Engine,
13558        ws: &mut StepPool,
13559        moe: &MoeW,
13560        mixed: &CudaSlice<f32>,
13561        mut out: CudaSlice<f32>,
13562        t: usize,
13563    ) -> Res<CudaSlice<f32>> {
13564        let hidden = self.hidden;
13565        let sff = moe
13566            .plan
13567            .shared
13568            .as_ref()
13569            .map(|s| s.intermediate_size as usize)
13570            .unwrap_or(0);
13571        if sff > 0 {
13572            prof_section(e, "moe.shared", || {
13573                // hcmicro: the shared-expert mats ride the bf16 trunk residency (their
13574                // f32 reads were ~2.5 GB/token); OFF keeps the f32 cuBLASLt chain.
13575                let none: Option<CudaSlice<u8>> = None;
13576                let (gu, db) = if micro_shexp_on() {
13577                    (&moe.shared_gu_b16, &moe.shared_down_b16)
13578                } else {
13579                    (&none, &none)
13580                };
13581                let mut gate = ws.take_f32(e, "moe.sh_gate", t * sff, 0)?;
13582                let mut up = ws.take_f32(e, "moe.sh_up", t * sff, 0)?;
13583                // Proj stack (round 4): shared gate/up in ONE launch (bit-identical
13584                // rows; OFF arm = row-offset views of the same stack).
13585                if let (true, Some(stack)) =
13586                    (t == 1 && proj_stack_on() && trunk_bf16_on(), gu.as_ref())
13587                {
13588                    launch_qmatvec_bf16w_multi4(
13589                        e,
13590                        stack,
13591                        mixed,
13592                        &[(&gate, sff), (&up, sff)],
13593                        hidden,
13594                    )?;
13595                } else {
13596                    linear_trunk_stacked_into(
13597                        e,
13598                        &moe.shared_gate,
13599                        gu,
13600                        0,
13601                        mixed,
13602                        &mut gate,
13603                        t,
13604                        hidden,
13605                        sff,
13606                    )?;
13607                    linear_trunk_stacked_into(
13608                        e,
13609                        &moe.shared_up,
13610                        gu,
13611                        sff,
13612                        mixed,
13613                        &mut up,
13614                        t,
13615                        hidden,
13616                        sff,
13617                    )?;
13618                }
13619                let mut act = ws.take_f32(e, "moe.sh_act", t * sff, 0)?;
13620                e.silu_mul(&gate, &up, &mut act, t * sff)?;
13621                let mut shared = ws.take_f32(e, "moe.sh_down", t * hidden, 0)?;
13622                linear_trunk_into(e, &moe.shared_down, db, &act, &mut shared, t, sff, hidden)?;
13623                if let Some(input_gate) = moe.shared_input_gate.as_ref() {
13624                    // Into-variant (same kernel, same launch shape as `sigmoid_dot_rows`;
13625                    // the owned form allocates per call — graph capture forbids that).
13626                    let mut g = ws.take_f32(e, "moe.g", t, 0)?;
13627                    e.sigmoid_dot_rows_into(mixed, input_gate, &mut g, hidden, t)?;
13628                    e.add_scaled_rows(&shared, &g, &mut out, hidden, t)?;
13629                    ws.put_f32("moe.g", g);
13630                } else {
13631                    let mut view = out.slice_mut(0..t * hidden);
13632                    e.axpy_into(&shared, 1.0, &mut view, t * hidden)?;
13633                }
13634                ws.put_f32("moe.sh_gate", gate);
13635                ws.put_f32("moe.sh_up", up);
13636                ws.put_f32("moe.sh_act", act);
13637                ws.put_f32("moe.sh_down", shared);
13638                Ok(())
13639            })?;
13640        }
13641        Ok(out)
13642    }
13643
13644    /// PLE block (`ple_block` twin): host n-gram hashing + host gather from the
13645    /// host-resident table, H2D of the gathered rows, device projections / grouped norms /
13646    /// dilated depthwise conv, host signed-sqrt sigmoid gate scalars.
13647    #[allow(clippy::too_many_arguments)]
13648    fn ple_block(
13649        &self,
13650        e: &Engine,
13651        layer: &LayerW,
13652        ple: &PleW,
13653        table: &NgramTable,
13654        ple_state: &mut PleState,
13655        planes: &mut [CudaSlice<f32>],
13656        tokens: &[u32],
13657        t: usize,
13658        // Verify-exact rows: per-token cuBLASLt launches (m == 1, the decode shape) so
13659        // chunk rows stay bit-identical to decode; `stash` retains the pre-chunk conv
13660        // history + the chunk's normed rows (the rewind rebuild inputs).
13661        exact: bool,
13662        mut stash: Option<&mut PleStash>,
13663    ) -> Res<()> {
13664        let hidden = self.hidden;
13665        let streams = self.streams;
13666        let plan = &ple.plan;
13667        let heads = plan.ngram_heads as usize;
13668        let head_dim = plan.head_embed_dim as usize;
13669        let embed_dim = plan.embed_dim as usize;
13670        let kernel = plan.conv_kernel as usize;
13671        let max_ngram = plan.max_ngram as usize;
13672        let dilation = max_ngram;
13673        let pad = (kernel - 1) * dilation;
13674        let eps = layer.eps_attn;
13675
13676        // Host n-gram ids over the FULL history (exact segment semantics), last t rows.
13677        let gathered = prof_section(e, "ple.host_ngram_gather", || {
13678            let total_heads = heads;
13679            // `plecache`: extend the state's id cache instead of rebuilding the whole
13680            // history's hashes. `ids` owns the vector only on the OFF arm; on the ON arm the
13681            // chunk rows are read in place out of the state (no O(context) clone).
13682            let mut ids: Vec<i64> = Vec::new();
13683            if ple_cache_on() {
13684                host_ngram_ids_cached(
13685                    &mut ple_state.ngram_ids,
13686                    &mut ple_state.ngram_history,
13687                    &mut ple_state.ngram_last_eos,
13688                    tokens,
13689                    &ple.multipliers,
13690                    &ple.sizes,
13691                    &ple.offsets,
13692                    max_ngram,
13693                    heads / (max_ngram - 1),
13694                    plan.eos_token_id,
13695                );
13696                if ple_cache_audit_on() {
13697                    let twin = host_ngram_ids(
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                    let from = (tokens.len() - t) * total_heads;
13707                    let mism = twin[from..]
13708                        .iter()
13709                        .zip(&ple_state.ngram_ids[from..])
13710                        .filter(|(a, b)| a != b)
13711                        .count() as u64;
13712                    PLE_CACHE_AUDIT_ROWS.fetch_add(t as u64, std::sync::atomic::Ordering::Relaxed);
13713                    PLE_CACHE_AUDIT_MISMATCH.fetch_add(mism, std::sync::atomic::Ordering::Relaxed);
13714                    PLE_CACHE_AUDIT_MAX_FILL
13715                        .fetch_max(tokens.len() as u64, std::sync::atomic::Ordering::Relaxed);
13716                    if mism > 0 {
13717                        return Err(format!(
13718                            "plecache audit: {mism} cached n-gram ids differ from the full twin \
13719                             at history {} (t={t})",
13720                            tokens.len()
13721                        )
13722                        .into());
13723                    }
13724                }
13725            } else {
13726                ids = host_ngram_ids(
13727                    tokens,
13728                    &ple.multipliers,
13729                    &ple.sizes,
13730                    &ple.offsets,
13731                    max_ngram,
13732                    heads / (max_ngram - 1),
13733                    plan.eos_token_id,
13734                );
13735            }
13736            let all_ids: &[i64] = if ple_cache_on() {
13737                &ple_state.ngram_ids
13738            } else {
13739                &ids
13740            };
13741            let chunk_ids = &all_ids[(tokens.len() - t) * total_heads..];
13742            let table_rows = table.rows(head_dim);
13743            let mut gathered = vec![0.0f32; t * embed_dim];
13744            for token in 0..t {
13745                for head in 0..heads {
13746                    let id = chunk_ids[token * total_heads + head];
13747                    if id < 0 || id as usize >= table_rows {
13748                        return Err("qwen4exp_gpu: n-gram id outside the embedding table".into());
13749                    }
13750                    table.gather_into(
13751                        id as usize,
13752                        head_dim,
13753                        &mut gathered[token * embed_dim + head * head_dim
13754                            ..token * embed_dim + (head + 1) * head_dim],
13755                    );
13756                }
13757            }
13758            Ok(gathered)
13759        })?;
13760        let emb = prof_section(e, "ple.h2d", || e.htod(&gathered))?;
13761
13762        // Per-token cuBLASLt twin (verify-exact): every m == 1 launch matches the
13763        // decode dispatch for that projection, so chunk rows equal decode rows bitwise.
13764        let lin_rows = |x: &CudaSlice<f32>,
13765                        w: &CudaSlice<f32>,
13766                        in_f: usize,
13767                        out_f: usize|
13768         -> Res<CudaSlice<f32>> {
13769            let mut out = e.uninit(t * out_f)?;
13770            if exact && t > 1 {
13771                let wv = w.slice(0..w.len());
13772                for tok in 0..t {
13773                    let xv = x.slice(tok * in_f..(tok + 1) * in_f);
13774                    let mut yv = out.slice_mut(tok * out_f..(tok + 1) * out_f);
13775                    e.linear_device_into(&xv, &wv, &mut yv, 1, in_f, out_f)?;
13776                }
13777            } else {
13778                e.linear_device_into(x, w, &mut out, t, in_f, out_f)?;
13779            }
13780            Ok(out)
13781        };
13782        let (value, mut dots_host) = prof_section(e, "ple.key_gate", || {
13783            let value = lin_rows(&emb, &ple.value_proj, embed_dim, hidden)?;
13784            let ones = e.htod(&vec![1.0f32; hidden])?;
13785            let mut dots_host = vec![0.0f32; streams * t];
13786            for s in 0..streams {
13787                let key = lin_rows(&emb, &ple.key_proj[s], embed_dim, hidden)?;
13788                let mut key_normed = e.uninit(t * hidden)?;
13789                e.rms_norm(&key, &ple.norm_key[s], &mut key_normed, hidden, t, eps)?;
13790                let mut query = e.uninit(t * hidden)?;
13791                e.rms_norm(&planes[s], &ple.norm_query[s], &mut query, hidden, t, eps)?;
13792                let mut prod = e.uninit(t * hidden)?;
13793                e.mul(&key_normed, &query, &mut prod, t * hidden)?;
13794                let dots = lin_rows(&prod, &ones, hidden, 1)?;
13795                dots_host[s * t..(s + 1) * t].copy_from_slice(&e.dtoh(&dots)?);
13796            }
13797            Ok((value, dots_host))
13798        })?;
13799        // signed sqrt + sigmoid (modular L770; torch sign(0) = 0) — host scalars.
13800        for dot in dots_host.iter_mut() {
13801            let gate = *dot / (hidden as f32).sqrt();
13802            let magnitude = gate.abs().max(1e-6).sqrt();
13803            let signed = if gate > 0.0 {
13804                magnitude
13805            } else if gate < 0.0 {
13806                -magnitude
13807            } else {
13808                0.0
13809            };
13810            *dot = host_sigmoid(signed);
13811        }
13812
13813        prof_section(e, "ple.conv_write", || {
13814            for s in 0..streams {
13815                let g = e.htod(&dots_host[s * t..(s + 1) * t])?;
13816                let mut gated = e.zeros(t * hidden)?;
13817                e.add_scaled_rows(&value, &g, &mut gated, hidden, t)?;
13818                let mut normed = e.uninit(t * hidden)?;
13819                e.rms_norm(&gated, &ple.norm_conv[s], &mut normed, hidden, t, eps)?;
13820                // Verify stash: pre-chunk history + this chunk's normed rows (rewind
13821                // rebuild inputs; pure retains).
13822                if let Some(st) = stash.as_deref_mut() {
13823                    e.copy_range_into(
13824                        &mut st.hist_pre[s],
13825                        0,
13826                        &ple_state.conv_hist[s],
13827                        0,
13828                        pad * hidden,
13829                    )?;
13830                    e.copy_range_into(&mut st.normed_rows[s], 0, &normed, 0, t * hidden)?;
13831                }
13832                // out = gated + silu(dilated causal conv(normed)) — dwconv mode 2 adds in place.
13833                launch_dwconv(
13834                    e,
13835                    &normed,
13836                    &ple_state.conv_hist[s],
13837                    &ple.conv_w[s],
13838                    &mut gated,
13839                    t,
13840                    pad,
13841                    hidden,
13842                    kernel,
13843                    dilation,
13844                    2,
13845                )?;
13846                // conv history <- last `pad` NORMED rows.
13847                let hist = &mut ple_state.conv_hist[s];
13848                if t >= pad {
13849                    e.copy_range_into(hist, 0, &normed, (t - pad) * hidden, pad * hidden)?;
13850                } else {
13851                    let keep = pad - t;
13852                    let mut tmp = e.uninit(keep * hidden)?;
13853                    e.copy_range_into(&mut tmp, 0, hist, t * hidden, keep * hidden)?;
13854                    e.copy_range_into(hist, 0, &tmp, 0, keep * hidden)?;
13855                    e.copy_range_into(hist, keep * hidden, &normed, 0, t * hidden)?;
13856                }
13857                // wide stream gains the PLE output BEFORE the attention read gate.
13858                let mut view = planes[s].slice_mut(0..t * hidden);
13859                e.axpy_into(&gated, 1.0, &mut view, t * hidden)?;
13860            }
13861            Ok(())
13862        })
13863    }
13864}
13865
13866// ---------------------------------------------------------------- MTP draft (mtp-spec lane)
13867
13868/// The MTP draft's persistent state: its own QSA KV rows + indexer raw-key cache + a
13869/// dedicated step workspace. DRAFT CACHE ROW i HOLDS TARGET POSITION i + 1 (position 0
13870/// never enters the draft — its first input pairs token x_1 with trunk hidden h_0), so
13871/// every spec-loop forward runs at `pos_off = 1`; the reference-parity gate runs at
13872/// `pos_off = 0` to match the reference executor's row-indexed positions.
13873pub struct MtpDraftState {
13874    mixer: MixerState,
13875    /// Rows currently in the cache (committed + speculative chain rows).
13876    rows: usize,
13877    /// Rows whose inputs were TRUE trunk hidden states (survive a round). The spec loop
13878    /// truncates to here and replays accepted tokens with verify-produced hiddens.
13879    pub committed: usize,
13880    capacity: usize,
13881    ws: StepPool,
13882}
13883
13884impl MtpDraftState {
13885    pub fn rows(&self) -> usize {
13886        self.rows
13887    }
13888}
13889
13890/// The draft forward's token source (mtp11): host ids (the mtp10 program), host ids
13891/// GATHERED ON DEVICE from the full-vocab chain table (the defer arm's prefill/replay
13892/// shape — a 4t-byte htod replaces t 10 KB pageable embed rows, the spec.rs
13893/// embed_gather_device_t precedent), or ONE device slot holding the previous chain
13894/// step's RAW argmax (the deferred chain).
13895#[derive(Clone, Copy)]
13896enum DraftTokSrc<'a> {
13897    Host(&'a [u32]),
13898    HostDev(&'a [u32]),
13899    DevSlot(&'a CudaSlice<u32>, usize),
13900}
13901
13902impl Qwen4ExpGpu {
13903    pub fn has_mtp(&self) -> bool {
13904        self.mtp.is_some()
13905    }
13906
13907    /// Card-1 draft placement armed? (`load_from_dir_dev1` — the draft's device tensors
13908    /// live on `mtp_dev1.dev`, and every draft call must present an engine there.)
13909    pub fn mtp_on_dev1(&self) -> bool {
13910        self.mtp_dev1.is_some()
13911    }
13912
13913    /// The draft's device tensors were built on ONE engine; a call presenting another
13914    /// engine would launch kernels on the wrong context (UVA would make it "work"
13915    /// slowly instead of failing). Enforced, never assumed.
13916    fn check_draft_engine(&self, e: &Engine) -> Res<()> {
13917        if let Some(d) = self.mtp_dev1.as_ref() {
13918            if e.ctx().ordinal() != d.dev {
13919                return Err(format!(
13920                    "qwen4exp_gpu: the draft lives on device {} (card-1 placement); \
13921                     this call presented device {}",
13922                    d.dev,
13923                    e.ctx().ordinal()
13924                )
13925                .into());
13926            }
13927        }
13928        Ok(())
13929    }
13930
13931    /// Allocate the draft's persistent state (its own KV plane; `capacity` rows).
13932    /// With the card-1 placement, `e` must be the DRAFT engine.
13933    pub fn mtp_state(&self, e: &Engine, capacity: usize) -> Res<MtpDraftState> {
13934        self.check_draft_engine(e)?;
13935        let mtp = self
13936            .mtp
13937            .as_ref()
13938            .ok_or("qwen4exp_gpu: no MTP block loaded (LoadOptions::load_mtp)")?;
13939        let MixerW::Qsa(qsa) = &mtp.layer.mixer else {
13940            return Err("qwen4exp_gpu: MTP mixer is not QSA".into());
13941        };
13942        let kv_width = qsa.attn.kv_heads as usize * qsa.attn.key_head_dim as usize;
13943        let v_width = qsa.attn.kv_heads as usize * qsa.attn.value_head_dim as usize;
13944        // kvq/idxq: the draft's QSA cache follows the same latched formats as the trunk
13945        // (uniform storage; the spec byte-identity gates run same-config on both arms).
13946        let kv = if kv_quant_on() {
13947            QsaKvStore::Q8Q5 {
13948                k: e.alloc_u8(capacity * q8_row_bytes(kv_width))?,
13949                v: e.alloc_u8(capacity * q5_row_bytes(v_width))?,
13950            }
13951        } else {
13952            QsaKvStore::F32 {
13953                k: e.zeros(capacity * kv_width)?,
13954                v: e.zeros(capacity * v_width)?,
13955            }
13956        };
13957        Ok(MtpDraftState {
13958            mixer: MixerState::Qsa {
13959                kv,
13960                raw_keys: IdxRawCache::new(idxq_mode()),
13961                pooled_keys: Vec::new(),
13962                pooled_dev: None,
13963                pooled_dev_rows: 0,
13964                raw_dev: None,
13965                raw_dev_rows: 0,
13966                idx_audit: None,
13967            },
13968            rows: 0,
13969            committed: 0,
13970            capacity,
13971            ws: StepPool::default(),
13972        })
13973    }
13974
13975    /// Truncate the draft cache to `rows` (speculative chain rows die; KV rows are
13976    /// overwritten in place by the next append, the host raw-key cache truncates).
13977    pub fn mtp_rewind(&self, dstate: &mut MtpDraftState, rows: usize) -> Res<()> {
13978        if rows > dstate.rows {
13979            return Err("qwen4exp_gpu: mtp_rewind past the cache".into());
13980        }
13981        let mtp = self.mtp.as_ref().ok_or("qwen4exp_gpu: no MTP block")?;
13982        let MixerW::Qsa(qsa) = &mtp.layer.mixer else {
13983            return Err("qwen4exp_gpu: MTP mixer is not QSA".into());
13984        };
13985        let MixerState::Qsa {
13986            raw_keys,
13987            pooled_keys,
13988            pooled_dev_rows,
13989            raw_dev_rows,
13990            ..
13991        } = &mut dstate.mixer
13992        else {
13993            return Err("qwen4exp_gpu: MTP state is not QSA".into());
13994        };
13995        let idx_dim = qsa.overlay.head_dim as usize;
13996        raw_keys.truncate_rows(rows, idx_dim);
13997        let block = qsa.overlay.block_size as usize;
13998        pooled_keys.truncate((rows / block) * idx_dim);
13999        // The device mirror's row count MUST follow the host truncation, or the next
14000        // scorer call skips the H2D of rebuilt rows and scores STALE keys (caught by the
14001        // spec byte-identity arms).
14002        *pooled_dev_rows = (*pooled_dev_rows).min(pooled_keys.len() / idx_dim);
14003        // Device raw-key cache (idxcache): clamp to the ABSOLUTE kept row count — the
14004        // host cache may legitimately lag below it (the lazy materialization).
14005        *raw_dev_rows = (*raw_dev_rows).min(rows);
14006        dstate.rows = rows;
14007        dstate.committed = dstate.committed.min(rows);
14008        Ok(())
14009    }
14010
14011    /// One MTP draft forward over `t` rows (SEMANTICS.md §MTP): fused input =
14012    /// `fc_embedding(norm(embed(tok)))` broadcast over streams + per-stream
14013    /// `fc_hidden(FLAT norm(wide hidden))`; ONE QSA+MoE decoder layer on the draft's own
14014    /// cache; exit through the draft mixer into the SHARED lm_head. Returns
14015    /// `(logits [t, vocab], carrier [t, wide])` — the carrier is the POST-LAYER wide
14016    /// state, the K > 1 multi-step seed. Recycle both via `mtp_recycle`.
14017    ///
14018    /// `hidden_wide` rows start at row `wide_off` of the given buffer; row r seeds
14019    /// token r. `pos_off` = 1 in the spec loop (draft row i ↔ target position i+1),
14020    /// 0 in the reference-parity gate.
14021    #[allow(clippy::too_many_arguments)]
14022    pub fn mtp_draft_forward(
14023        &self,
14024        e: &Engine,
14025        tokens: &[u32],
14026        hidden_wide: &CudaSlice<f32>,
14027        wide_off: usize,
14028        dstate: &mut MtpDraftState,
14029        pos_off: usize,
14030        // true => logits for EVERY row (the parity gates); false => the LAST row only
14031        // (the spec loop's shape — earlier rows exist for the KV cache + carrier, and
14032        // the full-vocab head must not scale with the replay length).
14033        logits_all: bool,
14034    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
14035        self.mtp_draft_forward_impl(
14036            e,
14037            DraftTokSrc::Host(tokens),
14038            hidden_wide,
14039            wide_off,
14040            dstate,
14041            pos_off,
14042            logits_all,
14043        )
14044    }
14045
14046    /// One DEFERRED chain step (mtp11): the input token is the previous step's device
14047    /// argmax, read from `toks[slot]` (RAW draft-index space; embeds through the armed
14048    /// chain table). t == 1 by construction; `pos_off` is the spec loop's 1.
14049    fn mtp_draft_forward_devslot(
14050        &self,
14051        e: &Engine,
14052        toks: &CudaSlice<u32>,
14053        slot: usize,
14054        hidden_wide: &CudaSlice<f32>,
14055        wide_off: usize,
14056        dstate: &mut MtpDraftState,
14057    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
14058        self.mtp_draft_forward_impl(
14059            e,
14060            DraftTokSrc::DevSlot(toks, slot),
14061            hidden_wide,
14062            wide_off,
14063            dstate,
14064            1,
14065            false,
14066        )
14067    }
14068
14069    /// Spec-loop host-token draft forward (prefill / bootstrap / replay shapes):
14070    /// `dev_embed` keys the defer arm's device-gather embed (full-vocab chain table)
14071    /// vs the mtp10 host embed — the control arm stays byte- AND structure-frozen.
14072    fn mtp_draft_forward_spec(
14073        &self,
14074        e: &Engine,
14075        tokens: &[u32],
14076        dev_embed: bool,
14077        hidden_wide: &CudaSlice<f32>,
14078        wide_off: usize,
14079        dstate: &mut MtpDraftState,
14080    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
14081        let src = if dev_embed {
14082            DraftTokSrc::HostDev(tokens)
14083        } else {
14084            DraftTokSrc::Host(tokens)
14085        };
14086        self.mtp_draft_forward_impl(e, src, hidden_wide, wide_off, dstate, 1, false)
14087    }
14088
14089    /// `mtp_draft_forward_spec` over RING-slotted seed rows: absolute seed row
14090    /// `first_row + i` lives at slot `(first_row + i) % ring`, and a range crossing the
14091    /// ring seam splits into two draft calls. The split changes the draft GEMM shape on
14092    /// seam rounds (drafted tokens may differ there — acceptance-only; commits are
14093    /// always the target rows, so spec byte-identity is untouched by construction).
14094    /// Returns the LAST piece's (logits row, carrier, piece length).
14095    fn draft_consume_ring(
14096        &self,
14097        de: &Engine,
14098        tokens: &[u32],
14099        dev_embed: bool,
14100        seed: &CudaSlice<f32>,
14101        ring: usize,
14102        first_row: usize,
14103        dstate: &mut MtpDraftState,
14104    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>, usize)> {
14105        let mut out: Option<(CudaSlice<f32>, CudaSlice<f32>, usize)> = None;
14106        let mut done = 0usize;
14107        while done < tokens.len() {
14108            let slot = (first_row + done) % ring;
14109            let len = (tokens.len() - done).min(ring - slot);
14110            let (l, c) = self.mtp_draft_forward_spec(
14111                de,
14112                &tokens[done..done + len],
14113                dev_embed,
14114                seed,
14115                slot,
14116                dstate,
14117            )?;
14118            if let Some((pl, pc, _)) = out.take() {
14119                self.mtp_recycle(dstate, pl, pc);
14120            }
14121            out = Some((l, c, len));
14122            done += len;
14123        }
14124        out.ok_or("qwen4exp_gpu: empty draft consume".into())
14125    }
14126
14127    #[allow(clippy::too_many_arguments)]
14128    fn mtp_draft_forward_impl(
14129        &self,
14130        e: &Engine,
14131        tok_src: DraftTokSrc<'_>,
14132        hidden_wide: &CudaSlice<f32>,
14133        wide_off: usize,
14134        dstate: &mut MtpDraftState,
14135        pos_off: usize,
14136        logits_all: bool,
14137    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
14138        self.check_draft_engine(e)?;
14139        let mtp = self
14140            .mtp
14141            .as_ref()
14142            .ok_or("qwen4exp_gpu: no MTP block loaded (LoadOptions::load_mtp)")?;
14143        let t = match tok_src {
14144            DraftTokSrc::Host(tokens) | DraftTokSrc::HostDev(tokens) => tokens.len(),
14145            DraftTokSrc::DevSlot(..) => 1,
14146        };
14147        let hidden = self.hidden;
14148        let streams = self.streams;
14149        let wide = streams * hidden;
14150        if t == 0 {
14151            return Err("qwen4exp_gpu: empty draft input".into());
14152        }
14153        if dstate.rows + t > dstate.capacity {
14154            return Err("qwen4exp_gpu: draft state capacity exceeded".into());
14155        }
14156        if hidden_wide.len() < (wide_off + t) * wide {
14157            return Err("qwen4exp_gpu: draft hidden seed rows out of range".into());
14158        }
14159        let base = dstate.rows;
14160        let ws = &mut dstate.ws;
14161        let cap = dstate.capacity;
14162
14163        // ---- input fusion
14164        let mut planes = prof_section(e, "mtp.fuse", || {
14165            let emb = match tok_src {
14166                DraftTokSrc::Host(tokens) => {
14167                    let mut embedded = vec![0.0f32; t * hidden];
14168                    for (row, &token) in tokens.iter().enumerate() {
14169                        let token = token as usize;
14170                        if token >= self.vocab {
14171                            return Err(
14172                                format!("qwen4exp_gpu: draft token {token} out of range").into()
14173                            );
14174                        }
14175                        embedded[row * hidden..(row + 1) * hidden].copy_from_slice(
14176                            &self.embed_host[token * hidden..(token + 1) * hidden],
14177                        );
14178                    }
14179                    ws.take_f32_h2d(e, "mtp.emb", &embedded, cap * hidden)?
14180                }
14181                DraftTokSrc::HostDev(tokens) => {
14182                    // Defer arm's prefill/replay embed (mtp11): host ids validated
14183                    // here, then a 4t-byte htod + device gather from the FULL-VOCAB
14184                    // chain table — bit-identical rows (ChainEmbed contract), no
14185                    // t x 10 KB pageable h2d. The caller keys this on a full-vocab
14186                    // table (a trim table cannot embed arbitrary target ids).
14187                    let ce = self
14188                        .chain_embed
14189                        .as_ref()
14190                        .filter(|ce| !ce.for_trim && ce.rows == self.vocab)
14191                        .ok_or("qwen4exp_gpu: HostDev embed needs the full-vocab chain table")?;
14192                    for &token in tokens {
14193                        if token as usize >= self.vocab {
14194                            return Err(
14195                                format!("qwen4exp_gpu: draft token {token} out of range").into()
14196                            );
14197                        }
14198                    }
14199                    let tok_d = e.gpu.stream().clone_htod(tokens)?;
14200                    let mut emb = ws.take_f32(e, "mtp.emb", t * hidden, cap * hidden)?;
14201                    let tv = tok_d.slice(0..t);
14202                    embed_gather_rows_into(
14203                        e,
14204                        &ce.table,
14205                        &tv,
14206                        &mut emb,
14207                        t,
14208                        hidden,
14209                        ce.qt,
14210                        ce.row_bytes,
14211                    )?;
14212                    emb
14213                }
14214                DraftTokSrc::DevSlot(toks, slot) => {
14215                    // Deferred chain (mtp11): gather THE row for the RAW draft index
14216                    // in `toks[slot]` from the armed chain table — bit-identical to
14217                    // the host row (ChainEmbed contract), no host round trip of the
14218                    // token id, no pageable h2d. Index bound is by construction:
14219                    // the argmax that wrote the slot scanned exactly `rows` columns.
14220                    let ce = self
14221                        .chain_embed
14222                        .as_ref()
14223                        .ok_or("qwen4exp_gpu: deferred draft step without arm_spec_devchain")?;
14224                    let mut emb = ws.take_f32(e, "mtp.emb", hidden, cap * hidden)?;
14225                    let tv = toks.slice(slot..slot + 1);
14226                    embed_gather_rows_into(
14227                        e,
14228                        &ce.table,
14229                        &tv,
14230                        &mut emb,
14231                        1,
14232                        hidden,
14233                        ce.qt,
14234                        ce.row_bytes,
14235                    )?;
14236                    emb
14237                }
14238            };
14239            let mut enorm = ws.take_f32(e, "mtp.enorm", t * hidden, 0)?;
14240            e.rms_norm(
14241                &emb,
14242                &mtp.pre_norm_embed,
14243                &mut enorm,
14244                hidden,
14245                t,
14246                mtp.eps_embed,
14247            )?;
14248            let mut evec = ws.take_f32(e, "mtp.evec", t * hidden, 0)?;
14249            linear_trunk_into(
14250                e,
14251                &mtp.fc_embed,
14252                &mtp.fc_embed_b16,
14253                &enorm,
14254                &mut evec,
14255                t,
14256                hidden,
14257                hidden,
14258            )?;
14259            // Stage the seed rows at offset 0 (exact copy), then FLAT-norm the whole
14260            // wide vector per token (GemmaRMSNorm_wide — SEMANTICS.md §MTP).
14261            let mut hin = ws.take_f32(e, "mtp.hin", t * wide, 0)?;
14262            e.copy_range_into(&mut hin, 0, hidden_wide, wide_off * wide, t * wide)?;
14263            let mut hnorm = ws.take_f32(e, "mtp.hnorm", t * wide, 0)?;
14264            e.rms_norm(
14265                &hin,
14266                &mtp.pre_norm_hidden,
14267                &mut hnorm,
14268                wide,
14269                t,
14270                mtp.eps_hidden,
14271            )?;
14272            // fc_hidden per stream = the same [H, H] mat over every (token, stream) row
14273            // of the normed wide buffer viewed [t*streams, H].
14274            let mut fused = ws.take_f32(e, "mtp.fused", t * wide, 0)?;
14275            linear_trunk_into(
14276                e,
14277                &mtp.fc_hidden,
14278                &mtp.fc_hidden_b16,
14279                &hnorm,
14280                &mut fused,
14281                t * streams,
14282                hidden,
14283                hidden,
14284            )?;
14285            let mut planes: Vec<CudaSlice<f32>> = Vec::with_capacity(streams);
14286            for s in 0..streams {
14287                let mut plane = ws.take_f32(e, PLANE_SLOTS[s], t * hidden, cap * hidden)?;
14288                for tok in 0..t {
14289                    e.copy_range_into(
14290                        &mut plane,
14291                        tok * hidden,
14292                        &fused,
14293                        (tok * streams + s) * hidden,
14294                        hidden,
14295                    )?;
14296                }
14297                let mut view = plane.slice_mut(0..t * hidden);
14298                e.axpy_into(&evec, 1.0, &mut view, t * hidden)?;
14299                planes.push(plane);
14300            }
14301            ws.put_f32("mtp.emb", emb);
14302            ws.put_f32("mtp.enorm", enorm);
14303            ws.put_f32("mtp.evec", evec);
14304            ws.put_f32("mtp.hin", hin);
14305            ws.put_f32("mtp.hnorm", hnorm);
14306            ws.put_f32("mtp.fused", fused);
14307            Ok(planes)
14308        })?;
14309
14310        let ptr_vals: Vec<u64> = {
14311            let stream = e.gpu.stream();
14312            planes.iter().map(|p| p.device_ptr(&stream).0).collect()
14313        };
14314        let ptrs = ws.take_u64_h2d(e, "hc.ptrs", &ptr_vals, 0)?;
14315
14316        // ---- the one decoder layer (trunk program, draft weights/cache)
14317        let layer = &mtp.layer;
14318        let (mixed, inject) = prof_section(e, "mtp.hyper.read", || {
14319            self.gate_read(
14320                e,
14321                ws,
14322                &ptrs,
14323                &layer.attn_gate,
14324                &planes,
14325                t,
14326                layer.eps_attn,
14327                false,
14328            )
14329        })?;
14330        let MixerW::Qsa(qsa) = &layer.mixer else {
14331            return Err("qwen4exp_gpu: MTP mixer is not QSA".into());
14332        };
14333        let block_out = prof_section(e, "mtp.qsa", || {
14334            self.qsa_forward(
14335                e,
14336                ws,
14337                layer,
14338                qsa,
14339                &mixed,
14340                &mut dstate.mixer,
14341                base,
14342                t,
14343                pos_off,
14344                false,
14345            )
14346        })?;
14347        ws.put_f32("hc.mixed", mixed);
14348        prof_section(e, "mtp.hyper.write", || {
14349            self.gate_write(e, &mut planes, &ptrs, &block_out, &inject, t)
14350        })?;
14351        ws.put_f32("mixer.out", block_out);
14352        put_inject(ws, inject);
14353        let (mixed, inject) = prof_section(e, "mtp.hyper.read", || {
14354            self.gate_read(
14355                e,
14356                ws,
14357                &ptrs,
14358                &layer.mlp_gate,
14359                &planes,
14360                t,
14361                layer.eps_mlp,
14362                false,
14363            )
14364        })?;
14365        let mlp = prof_section(e, "mtp.moe", || {
14366            // Rows mode for chain/replay shapes; the big draft PREFILL takes the
14367            // per-expert executor (each expert's rows widen once for all its tokens).
14368            self.moe_forward(e, ws, &layer.moe, &mixed, t, t <= 32, layer.index)
14369        })?;
14370        ws.put_f32("hc.mixed", mixed);
14371        prof_section(e, "mtp.hyper.write", || {
14372            self.gate_write(e, &mut planes, &ptrs, &mlp, &inject, t)
14373        })?;
14374        ws.put_f32("moe.out", mlp);
14375        put_inject(ws, inject);
14376
14377        // ---- carrier (post-layer wide state, PRE exit mixer — the K>1 seed)
14378        let mut carrier = ws.take_f32(e, "mtp.carrier", t * wide, 0)?;
14379        for (s, plane) in planes.iter().enumerate() {
14380            for tok in 0..t {
14381                e.copy_range_into(
14382                    &mut carrier,
14383                    tok * wide + s * hidden,
14384                    plane,
14385                    tok * hidden,
14386                    hidden,
14387                )?;
14388            }
14389        }
14390
14391        // ---- exit: the draft's own mixer read (no inject) -> shared lm_head.
14392        // Only the LAST row's logits are ever consumed (chain steps run t == 1; the
14393        // replay/prefill rows exist for the KV cache and the carrier), so the head
14394        // reads one hidden row — the full-vocab matvec is the draft's single largest
14395        // cost (mtp4 profile) and must not scale with the replay length.
14396        let x = prof_section(e, "mtp.exit", || {
14397            Ok(self
14398                .gate_read_inner(
14399                    e,
14400                    ws,
14401                    &ptrs,
14402                    &mtp.mixer,
14403                    &planes,
14404                    t,
14405                    self.exit_eps,
14406                    false,
14407                    false,
14408                )?
14409                .0)
14410        })?;
14411        ws.put_u64("hc.ptrs", ptrs);
14412        // The head is the SHARED trunk head, or its FR-Spec trimmed gather when the draft
14413        // trim is armed (mtp9): out_f drops from the 248,320 vocab to N, which is the
14414        // draft's single largest cost. Same bytes either way — a trimmed row's logit is
14415        // bit-identical to its full-vocab twin.
14416        let trim = self.draft_trim.as_ref();
14417        let out_f = trim.map_or(self.vocab, |t| t.n);
14418        // Card-1 placement reads its private head copy (same bytes, same program);
14419        // otherwise the shared trunk head. Trim + dev1 is refused at build time.
14420        let (head_w, head_b16) = match self.mtp_dev1.as_ref() {
14421            Some(d) => (&d.output, &d.output_b16),
14422            None => (&self.output, &self.output_b16),
14423        };
14424        let head_into =
14425            |e: &Engine, x: &CudaSlice<f32>, y: &mut CudaSlice<f32>, rows: usize| -> Res<()> {
14426                match trim {
14427                    Some(trim) => linear_trim_into(e, trim, x, y, rows, hidden),
14428                    None => linear_trunk_into(e, head_w, head_b16, x, y, rows, hidden, self.vocab),
14429                }
14430            };
14431        let logits = prof_section(e, "mtp.lm_head", || {
14432            if logits_all {
14433                let mut logits = ws.take_f32(e, "mtp.logits", t * out_f, 0)?;
14434                head_into(e, &x, &mut logits, t)?;
14435                return Ok(logits);
14436            }
14437            let mut logits = ws.take_f32(e, "mtp.logits", out_f, 0)?;
14438            let mut x_last = ws.take_f32(e, "mtp.xlast", hidden, 0)?;
14439            e.copy_range_into(&mut x_last, 0, &x, (t - 1) * hidden, hidden)?;
14440            head_into(e, &x_last, &mut logits, 1)?;
14441            ws.put_f32("mtp.xlast", x_last);
14442            Ok(logits)
14443        })?;
14444        ws.put_f32("hc.mixed", x);
14445        for (s, plane) in planes.into_iter().enumerate() {
14446            ws.put_f32(PLANE_SLOTS[s], plane);
14447        }
14448        dstate.rows += t;
14449        Ok((logits, carrier))
14450    }
14451
14452    /// Return a draft step's logits/carrier buffers to the draft workspace (address
14453    /// reuse across the hot loop).
14454    pub fn mtp_recycle(
14455        &self,
14456        dstate: &mut MtpDraftState,
14457        logits: CudaSlice<f32>,
14458        carrier: CudaSlice<f32>,
14459    ) {
14460        dstate.ws.put_f32("mtp.logits", logits);
14461        dstate.ws.put_f32("mtp.carrier", carrier);
14462    }
14463}
14464
14465// ---------------------------------------------------------------- spec decode (mtp-spec lane)
14466
14467/// Vendor-default sampling config for the SAMPLED spec run (the serving law's probe
14468/// shape): temp 1.0 / top_p 0.95 / top_k 20 on qwen4_exp. Greedy (None) stays the
14469/// byte-identity instrument.
14470#[derive(Clone, Copy)]
14471pub struct SpecSamplerCfg {
14472    pub temperature: f32,
14473    pub top_p: f32,
14474    pub top_k: usize,
14475    pub seed: u64,
14476}
14477
14478/// xorshift64* — deterministic, seedable, dependency-free (receipt reproducibility).
14479struct SpecRng(u64);
14480
14481impl SpecRng {
14482    fn next_f32(&mut self) -> f32 {
14483        let mut x = self.0;
14484        x ^= x >> 12;
14485        x ^= x << 25;
14486        x ^= x >> 27;
14487        self.0 = x;
14488        let bits = (x.wrapping_mul(0x2545_F491_4F6C_DD1D) >> 40) as u32;
14489        bits as f32 / (1u64 << 24) as f32
14490    }
14491}
14492
14493/// Host top-k/top-p/temperature sample over one logits row.
14494fn sample_row(cfg: &SpecSamplerCfg, rng: &mut SpecRng, row: &[f32]) -> u32 {
14495    let k = cfg.top_k.max(1).min(row.len());
14496    let mut idx: Vec<u32> = (0..row.len() as u32).collect();
14497    idx.select_nth_unstable_by(k - 1, |&a, &b| row[b as usize].total_cmp(&row[a as usize]));
14498    let mut top: Vec<(u32, f32)> = idx[..k].iter().map(|&i| (i, row[i as usize])).collect();
14499    top.sort_by(|a, b| b.1.total_cmp(&a.1));
14500    let temp = cfg.temperature.max(1e-6);
14501    let mx = top[0].1;
14502    let mut probs: Vec<f32> = top.iter().map(|&(_, v)| ((v - mx) / temp).exp()).collect();
14503    let sum: f32 = probs.iter().sum();
14504    for p in &mut probs {
14505        *p /= sum;
14506    }
14507    // top_p nucleus over the sorted tail.
14508    let mut cut = probs.len();
14509    let mut acc = 0.0f32;
14510    for (i, &p) in probs.iter().enumerate() {
14511        acc += p;
14512        if acc >= cfg.top_p {
14513            cut = i + 1;
14514            break;
14515        }
14516    }
14517    let renorm: f32 = probs[..cut].iter().sum();
14518    let draw = rng.next_f32() * renorm;
14519    let mut acc = 0.0f32;
14520    for (i, &p) in probs[..cut].iter().enumerate() {
14521        acc += p;
14522        if draw < acc {
14523            return top[i].0;
14524        }
14525    }
14526    top[cut - 1].0
14527}
14528
14529/// Host argmax with the plain chain's tie rule (strictly-greater keeps the smallest
14530/// index) — bit-identical to the device 2-pass argmax (argmax-gate contract), which is
14531/// what lets the trace and plain-tail paths commit host argmaxes without moving a chain.
14532fn host_argmax(row: &[f32]) -> usize {
14533    let mut best = 0usize;
14534    for (i, &v) in row.iter().enumerate() {
14535        if v > row[best] {
14536            best = i;
14537        }
14538    }
14539    best
14540}
14541
14542/// P2P-copy `t` wide rows at row offset `off` from the card-0 verify wide stash into
14543/// the card-1 mirror (mtp10 dev1 draft placement), issued on the DRAFT engine's stream
14544/// and host-synced — the sync is where the crossing is TIMED, and the draft's next
14545/// kernels queue behind the copy on the same stream either way. Host ordering
14546/// guarantees the source rows are complete: every call site sits after a `forward`
14547/// whose host dtoh (logits or argmax) synced card 0's stream.
14548/// Ring-contiguous pieces of an absolute wide-row range [off, off+t): (slot_off, len)
14549/// per piece — one piece unless the range crosses the ring seam (then two). Identity
14550/// slots when ring >= off + t never wraps (the historical whole-history stash).
14551fn ring_pieces(ring: usize, off: usize, t: usize) -> Vec<(usize, usize)> {
14552    debug_assert!(t <= ring, "wide-ring consumer wider than the ring");
14553    let slot = off % ring;
14554    if slot + t <= ring {
14555        vec![(slot, t)]
14556    } else {
14557        vec![(slot, ring - slot), (0, t - (ring - slot))]
14558    }
14559}
14560
14561fn cross_wide_rows(
14562    e: &Engine,
14563    de: &Engine,
14564    src: &CudaSlice<f32>,
14565    dst: &mut CudaSlice<f32>,
14566    off: usize,
14567    t: usize,
14568    wide: usize,
14569) -> Res<f64> {
14570    let t0 = std::time::Instant::now();
14571    let stream = de.gpu.stream();
14572    let bytes = t * wide * 4;
14573    let byte_off = (off * wide * 4) as u64;
14574    let (sp, _g0) = src.device_ptr(&stream);
14575    let (dp, _g1) = dst.device_ptr_mut(&stream);
14576    unsafe {
14577        cudarc::driver::result::memcpy_peer_async(
14578            de.ctx().cu_ctx(),
14579            dp + byte_off,
14580            e.ctx().cu_ctx(),
14581            sp + byte_off,
14582            bytes,
14583            stream.cu_stream(),
14584        )?;
14585    }
14586    stream.synchronize()?;
14587    Ok(t0.elapsed().as_secs_f64() * 1e3)
14588}
14589
14590/// Launch `embed_gather_u32_t` for ONE device-slot token into the pooled `mtp.emb`
14591/// buffer (mtp11 deferred chain). Same kernel as the lib.rs `embed_gather_device_*`
14592/// family — bit-identical rows by the same per-dtype deq contract. Lives here (not as
14593/// an Engine method) because the deferred chain is this module's machinery.
14594fn embed_gather_rows_into(
14595    e: &Engine,
14596    table: &CudaSlice<u8>,
14597    tok_v: &CudaView<u32>,
14598    x_out: &mut CudaSlice<f32>,
14599    t: usize,
14600    n_embd: usize,
14601    qtype: i32,
14602    row_bytes: usize,
14603) -> Res<()> {
14604    let f = e.func("embed_gather_u32_t");
14605    let cfg = LaunchConfig {
14606        grid_dim: (((n_embd as u32).div_ceil(256)).max(1), t as u32, 1),
14607        block_dim: (256, 1, 1),
14608        shared_mem_bytes: 0,
14609    };
14610    let (ne, qt, rb, ti) = (n_embd as i32, qtype, row_bytes as i64, t as i32);
14611    let stream = e.gpu.stream();
14612    let mut b = stream.launch_builder(&f);
14613    b.arg(table)
14614        .arg(tok_v)
14615        .arg(x_out)
14616        .arg(&ne)
14617        .arg(&qt)
14618        .arg(&rb)
14619        .arg(&ti);
14620    unsafe {
14621        b.launch(cfg)?;
14622    }
14623    Ok(())
14624}
14625
14626/// One spec run's counters (the accept-length table's source).
14627#[derive(Debug, Default, Clone)]
14628pub struct SpecReport {
14629    pub tokens: Vec<u32>,
14630    pub rounds: usize,
14631    pub drafted: u64,
14632    pub accepted: u64,
14633    /// hist[a] = rounds that accepted exactly `a` drafts (a in 0..=k).
14634    pub accept_hist: Vec<u64>,
14635    pub draft_ms: f64,
14636    pub verify_ms: f64,
14637    pub prefill_ms: f64,
14638    pub total_ms: f64,
14639    /// draft_ms split (the round-cost identity table): the K-step chain, the accepted-
14640    /// token catch-up replay, and the one-time draft prefill. draft_ms is their sum.
14641    pub chain_ms: f64,
14642    pub replay_ms: f64,
14643    pub draft_prefill_ms: f64,
14644    /// Card-1 crossing cost (mtp10 dev1 placement): wall time and bytes of the P2P
14645    /// wide-row copies (prefill seed + per-round replay seeds). 0 on one card.
14646    pub cross_ms: f64,
14647    pub cross_bytes: u64,
14648    /// Dynamic-K admission (mtp10): every decay as (round, new_k). Empty = K never moved.
14649    pub k_decays: Vec<(usize, usize)>,
14650    /// Token count at which the policy turned spec fully OFF (k reached 0); the rest of
14651    /// the generation ran plain decode steps (counted in `plain_steps`, not `rounds`).
14652    pub spec_off_at: Option<usize>,
14653    pub plain_steps: usize,
14654    /// Per-round wall samples: (tokens committed so far, ms since generation start),
14655    /// appended after every round/plain step — lets a caller derive N timing sub-rounds
14656    /// from ONE generation (the x3-rounds protocol where a fresh prefill per timing
14657    /// round is prohibitive, e.g. the 1M ladder).
14658    pub round_wall: Vec<(usize, f64)>,
14659    /// p-min guard accounting: rounds that drafted NOTHING (verify = plain t==1 step)
14660    /// and chain steps cut short (the sub-threshold token discarded uncounted).
14661    pub zero_draft_rounds: usize,
14662    pub guard_stops: usize,
14663}
14664
14665/// Bounded shape-aware spec admission (mtp10): rolling-accept-driven K decay. Every
14666/// round pushes its accept count into a window of the last `window` rounds; when the
14667/// window is full and its mean accept < `thr` (draft tokens per round, 0..=k), K steps
14668/// DOWN by one (never up — decay only, bounded and monotone) and the window resets so
14669/// decays are at least `window` rounds apart. At K = `k_floor` the decay stops; with
14670/// `k_floor` = 0 reaching it turns spec OFF for the REST of the generation (plain
14671/// greedy decode steps — the draft cost is what the collapsed shape was paying for).
14672/// Byte identity is untouched BY CONSTRUCTION at every K: committed tokens are always
14673/// the target rows' argmax, and the plain tail IS the plain program.
14674#[derive(Clone, Copy, Debug)]
14675pub struct DynKCfg {
14676    pub window: usize,
14677    pub thr: f64,
14678    pub k_floor: usize,
14679}
14680
14681/// Spec-round admission options (mtp10). Every knob defaults OFF; each is a bounded
14682/// policy that can only shrink the drafted window — the committed output is the target
14683/// rows' argmax at every setting, so byte identity is untouched by construction.
14684#[derive(Clone, Copy, Debug, Default)]
14685pub struct SpecOpts {
14686    /// Rolling-window K decay (the last-resort shape bound). See `DynKCfg`.
14687    pub dynk: Option<DynKCfg>,
14688    /// Adaptive per-round window (the dflash MEMRA_DFLASH_ADAPT "accepted+1" recipe):
14689    /// next round drafts clamp(last_accept + 1, k_lo, k). `Some(k_lo)` arms it.
14690    pub adapt_k_lo: Option<usize>,
14691    /// p-min draft-confidence guard (the MEMRA_SPEC_PMIN mechanism, sub-threshold token
14692    /// DISCARDED UNCOUNTED — the reference engines' normalization). Applies at j == 0
14693    /// too (the MEMRA_SPEC_PMIN0 zero-draft-round semantics): a low-confidence round
14694    /// drafts NOTHING and its verify is a plain t == 1 step that still commits one
14695    /// token — unpredictable stretches never pay draft + verify-column overhead.
14696    /// 0.0 = off.
14697    pub pmin: f32,
14698    /// Deferred round readback (mtp11, the spec.rs slice-2 structure ported): the
14699    /// chain's argmax feeds the next step ON DEVICE through the armed chain-embed
14700    /// table (`arm_spec_devchain` required), the guard's confidences land in device
14701    /// slots, and the chain drains ONCE per round before the verify (the PLE host
14702    /// n-gram gather needs the chunk's token ids, so this family's floor is a 2-drain
14703    /// round, not spec.rs's 1). t == 1 steps take the device-argmax fast path and the
14704    /// prefill dtoh shrinks to one row. Committed bytes identical BY CONSTRUCTION
14705    /// (same kernels, same picks; spec-gate arbitrates). Default OFF (flags law);
14706    /// mutually exclusive with `trace` (trace reads per-step host rows).
14707    pub defer: bool,
14708    /// With `defer` + `pmin`: keep the guard SEQUENTIAL — one 4-byte prob dtoh per
14709    /// chain step, the chain stops exactly at the sub-threshold step (today's cost
14710    /// shape). Default OFF = the deferred guard: probabilities drain with the chain
14711    /// and truncate at the FIRST sub-threshold step — same picks and counters
14712    /// bit-for-bit, but the dispatched suffix past the stop is work the sequential
14713    /// arm never paid. The guard-forces-a-readback A/B the owner asked to measure.
14714    pub defer_guard_sync: bool,
14715    /// Long-context lane: chunked co-prefill (trunk chunk forward with the head
14716    /// skipped, then the draft consumes that chunk's wide rows) instead of the one-shot
14717    /// prompt forward — the one-shot shape at 500k+ would materialize chunk-sized
14718    /// transients per plane AND a [n, vocab] logits block. `None` = the historical
14719    /// one-shot (byte-stable receipts).
14720    pub prefill_chunk: Option<usize>,
14721    /// Long-context lane: RING-bounded wide stash rows (`spec_arm_ring`) — at 1M
14722    /// capacity the whole-history stash is ~41 GB/card. Requires `prefill_chunk` (the
14723    /// co-prefill consumes each chunk before the ring overwrites it) and must be
14724    /// >= 2 * prefill_chunk. `None` = whole-history (the historical layout).
14725    pub wide_ring: Option<usize>,
14726}
14727
14728/// The deferred guard's drain-time truncation (mtp11): the FIRST sub-threshold
14729/// confidence (predicate `p < pmin` — the host chain's exact stop rule, boundary
14730/// p == pmin PASSES) ends the drafted window; picks before it survive, the
14731/// sub-threshold pick is discarded uncounted, everything after is dispatch the
14732/// sequential arm never paid. Pure so the tiny gate can pin the walk on arbitrary
14733/// windows: mid-chain dips are unreachable on the deterministic tiny fixture
14734/// (intra-round confidence never crosses a passed threshold there), so this pin plus
14735/// the real-model `--defer-ab` counter identity are the mid-chain coverage.
14736pub fn spec_guard_trunc(probs: &[f32], pmin: f32) -> usize {
14737    probs.iter().position(|&p| p < pmin).unwrap_or(probs.len())
14738}
14739
14740/// One traced spec round (the mtp10 thinkon-decay diagnosis instrument). Trace mode
14741/// changes NOTHING the accept walk sees — it only reads: draft logit rows, carrier
14742/// seeds, and the verify's captured wide rows come to host for margin/drift stats.
14743/// (Greedy trace runs with host-argmax targets — the same argmax the plain chain uses,
14744/// proven equal to the device walk by the spec-gate.)
14745#[derive(Debug, Default, Clone)]
14746pub struct SpecTraceRound {
14747    pub round: usize,
14748    /// Committed generation length BEFORE this round (position within the generation).
14749    pub gen_pos: usize,
14750    /// Trunk committed rows before the round (the tip's absolute position).
14751    pub base: usize,
14752    pub k: usize,
14753    pub a: usize,
14754    pub drafts: Vec<u32>,
14755    /// k+1 target rows (the committed prefix is targets[0..=a]).
14756    pub targets: Vec<u32>,
14757    /// Fork-row stats (row `a`, present when a < k): the draft's top-2 logits, the
14758    /// draft's logit and rank of the token the TARGET wanted, the target's top-2 logits,
14759    /// the target's logit of the token the DRAFT proposed, and the target row's softmax
14760    /// entropy (nats). NaN/0 when the round accepted everything (no fork).
14761    pub draft_top1: f32,
14762    pub draft_top2: f32,
14763    pub draft_tgt_logit: f32,
14764    pub draft_tgt_rank: usize,
14765    pub target_top1: f32,
14766    pub target_top2: f32,
14767    pub target_draft_logit: f32,
14768    pub target_entropy: f64,
14769    /// Carrier drift per carrier-seeded chain step j = 1..k-1: the seed the draft used
14770    /// (its own predicted wide for position base+j-1) vs the trunk's TRUE wide row at
14771    /// that position (captured by the verify chunk). rel_l2 = ||seed-true||/||true||.
14772    pub carrier_rel_l2: Vec<f32>,
14773    pub carrier_cos: Vec<f32>,
14774}
14775
14776impl SpecReport {
14777    pub fn accept_rate(&self) -> f64 {
14778        if self.drafted == 0 {
14779            0.0
14780        } else {
14781            self.accepted as f64 / self.drafted as f64
14782        }
14783    }
14784    /// Mean committed tokens per round (accepted + bonus).
14785    pub fn mean_accept_len(&self) -> f64 {
14786        if self.rounds == 0 {
14787            0.0
14788        } else {
14789            self.tokens.len() as f64 / self.rounds as f64
14790        }
14791    }
14792}
14793
14794impl Qwen4ExpGpu {
14795    /// Arm the verify instrument on `state`: absolute-position wide capture (the
14796    /// draft's hidden seeds) + per-column GDN/PLE stashes for chunks up to `k_cap`
14797    /// columns. Idempotent for the same k_cap.
14798    pub fn spec_arm(&self, e: &Engine, state: &mut Qwen4ExpState, k_cap: usize) -> Res<()> {
14799        self.spec_arm_ring(e, state, k_cap, state.capacity)
14800    }
14801
14802    /// `spec_arm` with a RING-bounded wide stash (long-context lane): the stash holds the
14803    /// last `ring_rows` wide rows (slot = row % ring_rows) instead of `capacity` rows —
14804    /// at 1M capacity the full stash is ~41 GB/card, the ring ~0.7 GB. Every consumer
14805    /// reads rows within `ring_rows` of the write head (chunked co-prefill consumes each
14806    /// chunk before the next lands; rounds read the last k+2 rows), asserted at the read
14807    /// helpers. `spec_arm` (ring = capacity) keeps the historical byte-stable layout.
14808    pub fn spec_arm_ring(
14809        &self,
14810        e: &Engine,
14811        state: &mut Qwen4ExpState,
14812        k_cap: usize,
14813        ring_rows: usize,
14814    ) -> Res<()> {
14815        let ring_rows = ring_rows.min(state.capacity).max(k_cap + 2);
14816        if let Some(v) = state.verify.as_ref() {
14817            if v.k_cap == k_cap && v.ring_rows == ring_rows {
14818                return Ok(());
14819            }
14820        }
14821        let wide = self.streams * self.hidden;
14822        let mut gdn = Vec::with_capacity(self.layers.len());
14823        let mut ple = Vec::with_capacity(self.layers.len());
14824        for layer in &self.layers {
14825            gdn.push(match &layer.mixer {
14826                MixerW::Gdn(g) => {
14827                    let p = &g.plan;
14828                    let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
14829                    let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
14830                    let conv_dim = 2 * nk * hk + nv * hv;
14831                    let pad = p.conv_kernel as usize - 1;
14832                    Some(GdnStash {
14833                        states: e.zeros(k_cap * nv * hv * hk)?,
14834                        conv_pre: e.zeros(pad * conv_dim)?,
14835                        qkv_rows: e.zeros(k_cap * conv_dim)?,
14836                        scan_graph: None,
14837                        scan_warm: None,
14838                    })
14839                }
14840                MixerW::Qsa(_) => None,
14841            });
14842            ple.push(match layer.ple.as_ref() {
14843                Some(pw) => {
14844                    let pad = (pw.plan.conv_kernel as usize - 1) * pw.plan.max_ngram as usize;
14845                    let mut hist_pre = Vec::with_capacity(self.streams);
14846                    let mut normed_rows = Vec::with_capacity(self.streams);
14847                    for _ in 0..self.streams {
14848                        hist_pre.push(e.zeros(pad * self.hidden)?);
14849                        normed_rows.push(e.zeros(k_cap * self.hidden)?);
14850                    }
14851                    Some(PleStash {
14852                        hist_pre,
14853                        normed_rows,
14854                    })
14855                }
14856                None => None,
14857            });
14858        }
14859        state.verify = Some(VerifyStash {
14860            k_cap,
14861            chunk: None,
14862            fused_chunk: None,
14863            gdn,
14864            ple,
14865            wide: e.zeros(ring_rows * wide)?,
14866            ring_rows,
14867            wide_dev1: None,
14868            argmax: Vec::new(),
14869            toks: unsafe { e.gpu.stream().alloc::<u32>(k_cap)? },
14870            want_argmax: false,
14871            want_argmax_t1: false,
14872            last_row_only: false,
14873        });
14874        Ok(())
14875    }
14876
14877    pub fn spec_disarm(&self, state: &mut Qwen4ExpState) {
14878        state.verify = None;
14879    }
14880
14881    pub fn set_verify_want_argmax(&self, state: &mut Qwen4ExpState, on: bool) -> Res<()> {
14882        state
14883            .verify
14884            .as_mut()
14885            .ok_or("qwen4exp_gpu: verify not armed")?
14886            .want_argmax = on;
14887        Ok(())
14888    }
14889
14890    /// The last exact chunk's per-row device-argmax tokens (want_argmax mode).
14891    pub fn verify_argmax_rows<'s>(&self, state: &'s Qwen4ExpState) -> Res<&'s [u32]> {
14892        Ok(&state
14893            .verify
14894            .as_ref()
14895            .ok_or("qwen4exp_gpu: verify not armed")?
14896            .argmax)
14897    }
14898
14899    /// Rewind the trunk state to the first `keep` rows of the live verify chunk:
14900    /// bookkeeping truncation + GDN state restore from the per-column snapshots + GDN/
14901    /// PLE conv-history rebuild from the stashed pre-chunk history and chunk rows.
14902    /// `keep == t` is the all-accepted fast path (state already correct).
14903    pub fn verify_rewind(&self, e: &Engine, state: &mut Qwen4ExpState, keep: usize) -> Res<()> {
14904        let Some(v) = state.verify.as_mut() else {
14905            return Err("qwen4exp_gpu: verify not armed".into());
14906        };
14907        let Some((base, t)) = v.chunk.take() else {
14908            if let Some((fb, ft)) = v.fused_chunk.take() {
14909                return Err(format!(
14910                    "qwen4exp_gpu: verify chunk (base {fb}, t {ft}) ran the FUSED program \
14911                     (`vfuse` cost instrument) — no per-column GDN/PLE stash exists, so it \
14912                     cannot be rewound. vfuse is a timing probe on a throwaway state; drop \
14913                     the seam to run a spec loop."
14914                )
14915                .into());
14916            }
14917            return Err("qwen4exp_gpu: no live verify chunk to rewind".into());
14918        };
14919        if keep == 0 || keep > t {
14920            return Err("qwen4exp_gpu: rewind keep out of range".into());
14921        }
14922        if keep == t {
14923            return Ok(());
14924        }
14925        state.pos = base + keep;
14926        state.tokens.truncate(base + keep);
14927        for (li, (layer, lstate)) in self.layers.iter().zip(state.layers.iter_mut()).enumerate() {
14928            match (&layer.mixer, &mut lstate.mixer) {
14929                (
14930                    MixerW::Qsa(qsa),
14931                    MixerState::Qsa {
14932                        raw_keys,
14933                        pooled_keys,
14934                        pooled_dev_rows,
14935                        raw_dev_rows,
14936                        idx_audit,
14937                        ..
14938                    },
14939                ) => {
14940                    let idx_dim = qsa.overlay.head_dim as usize;
14941                    raw_keys.truncate_rows(base + keep, idx_dim);
14942                    let block = qsa.overlay.block_size as usize;
14943                    pooled_keys.truncate(((base + keep) / block) * idx_dim);
14944                    // Device mirror follows the host truncation (see mtp_rewind).
14945                    *pooled_dev_rows = (*pooled_dev_rows).min(pooled_keys.len() / idx_dim);
14946                    // Device raw-key cache (idxcache): clamp to the ABSOLUTE kept row
14947                    // count (the host cache may lag below it — lazy materialization).
14948                    *raw_dev_rows = (*raw_dev_rows).min(base + keep);
14949                    // The audit twin tracks the cache rows exactly (instrument).
14950                    if let Some(audit) = idx_audit.as_deref_mut() {
14951                        audit.raw_f32.truncate_rows(base + keep, idx_dim);
14952                        audit.pooled_f32.truncate(((base + keep) / block) * idx_dim);
14953                    }
14954                }
14955                (MixerW::Gdn(g), MixerState::Gdn { conv, state: rec }) => {
14956                    let st = v.gdn[li]
14957                        .as_mut()
14958                        .ok_or("qwen4exp_gpu: GDN layer without a verify stash")?;
14959                    let p = &g.plan;
14960                    let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
14961                    let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
14962                    let conv_dim = 2 * nk * hk + nv * hv;
14963                    let pad = p.conv_kernel as usize - 1;
14964                    let state_len = nv * hv * hk;
14965                    e.copy_range_into(rec, 0, &st.states, (keep - 1) * state_len, state_len)?;
14966                    if keep >= pad {
14967                        e.copy_range_into(
14968                            conv,
14969                            0,
14970                            &st.qkv_rows,
14971                            (keep - pad) * conv_dim,
14972                            pad * conv_dim,
14973                        )?;
14974                    } else {
14975                        let keep_hist = pad - keep;
14976                        e.copy_range_into(
14977                            conv,
14978                            0,
14979                            &st.conv_pre,
14980                            keep * conv_dim,
14981                            keep_hist * conv_dim,
14982                        )?;
14983                        e.copy_range_into(
14984                            conv,
14985                            keep_hist * conv_dim,
14986                            &st.qkv_rows,
14987                            0,
14988                            keep * conv_dim,
14989                        )?;
14990                    }
14991                }
14992                _ => return Err("qwen4exp_gpu: mixer/state mismatch in rewind".into()),
14993            }
14994            if let (Some(pw), Some(ps)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
14995                let st = v.ple[li]
14996                    .as_mut()
14997                    .ok_or("qwen4exp_gpu: PLE layer without a verify stash")?;
14998                let pad = (pw.plan.conv_kernel as usize - 1) * pw.plan.max_ngram as usize;
14999                let hidden = self.hidden;
15000                for s in 0..self.streams {
15001                    let hist = &mut ps.conv_hist[s];
15002                    if keep >= pad {
15003                        e.copy_range_into(
15004                            hist,
15005                            0,
15006                            &st.normed_rows[s],
15007                            (keep - pad) * hidden,
15008                            pad * hidden,
15009                        )?;
15010                    } else {
15011                        let keep_hist = pad - keep;
15012                        e.copy_range_into(
15013                            hist,
15014                            0,
15015                            &st.hist_pre[s],
15016                            keep * hidden,
15017                            keep_hist * hidden,
15018                        )?;
15019                        e.copy_range_into(
15020                            hist,
15021                            keep_hist * hidden,
15022                            &st.normed_rows[s],
15023                            0,
15024                            keep * hidden,
15025                        )?;
15026                    }
15027                }
15028            }
15029        }
15030        Ok(())
15031    }
15032
15033    /// Device argmax of ONE draft-logits row (4-byte dtoh), returned as a TARGET vocab
15034    /// id: the row width is the trim width when armed and the winning row maps back
15035    /// through d2t (identity when the trim is off). `conf` (the p-min guard, prior art
15036    /// MEMRA_SPEC_PMIN / gemma confidence-adaptive draft depth — the SAME
15037    /// prob_of_token kernels) additionally returns the head's softmax confidence in its
15038    /// own pick: one extra 2-pass sum-exp launch + a 4-byte dtoh. Under a trim the
15039    /// confidence reads the TRIMMED row (inflated vs full softmax — thresholds are
15040    /// per-configuration, stated in the receipt).
15041    fn draft_row_argmax(
15042        &self,
15043        e: &Engine,
15044        logits: &CudaSlice<f32>,
15045        row: usize,
15046        conf: bool,
15047    ) -> Res<(u32, f32)> {
15048        let width = self.draft_logits_width();
15049        let mut tok = unsafe { e.gpu.stream().alloc::<u32>(1)? };
15050        e.argmax_token_device_col(logits, row, width, &mut tok, 0)?;
15051        let p = if conf {
15052            if row != 0 {
15053                // The chain shape is single-row; prob_of_token reads logits[0..width].
15054                return Err("qwen4exp_gpu: draft confidence reads row 0 (the chain shape)".into());
15055            }
15056            let pd = e.prob_of_token_device(logits, &tok, width)?;
15057            e.gpu.stream().clone_dtoh(&pd)?[0]
15058        } else {
15059            1.0
15060        };
15061        Ok((self.draft_token(e.gpu.stream().clone_dtoh(&tok)?[0])?, p))
15062    }
15063
15064    /// MTP speculative decode (mtp-spec lane): prefill, draft-prefill the MTP block
15065    /// over the prompt, then rounds of K-token drafting (single-layer draft, carrier-
15066    /// chained) + ONE trunk verify chunk (t = K+1, every row bit-identical to the
15067    /// t == 1 decode program) + greedy accept walk + replay-free partial rewind.
15068    ///
15069    /// Greedy (sampler None) is the byte-identity instrument: output must equal the
15070    /// spec-off greedy chain token for token. `Some(cfg)` runs the vendor-default
15071    /// sampled shape: targets are SAMPLED per verify row (draft accepted on exact
15072    /// match — distribution-preserving), the serving law's probe.
15073    ///
15074    /// This wrapper is the single-card, no-admission, no-trace shape; the full seam is
15075    /// `spec_generate_ext`.
15076    #[allow(clippy::too_many_arguments)]
15077    pub fn spec_generate(
15078        &self,
15079        e: &Engine,
15080        prompt: &[u32],
15081        max_new: usize,
15082        k: usize,
15083        state: &mut Qwen4ExpState,
15084        dstate: &mut MtpDraftState,
15085        sampler: Option<SpecSamplerCfg>,
15086    ) -> Res<SpecReport> {
15087        self.spec_generate_ext(
15088            e,
15089            e,
15090            prompt,
15091            max_new,
15092            k,
15093            state,
15094            dstate,
15095            sampler,
15096            SpecOpts::default(),
15097            None,
15098        )
15099    }
15100
15101    /// `spec_generate` with the mtp10 seams:
15102    /// - `de` — the DRAFT engine. Same card as `e` by default; the card-1 placement
15103    ///   (`load_from_dir_dev1`) requires the dev1 engine here and P2P-crosses the wide
15104    ///   seed rows per round (timed into `report.cross_ms`).
15105    /// - `opts` — bounded spec admission (p-min guard / adaptive K / dyn-K decay), all
15106    ///   default OFF. Every knob only shrinks the drafted window; commits are always
15107    ///   the target rows, so byte identity holds at every setting by construction.
15108    /// - `trace` — per-round diagnosis records (accept positions, fork margins, carrier
15109    ///   drift). Trace mode only ADDS reads (dtoh) and swaps the device accept-argmax
15110    ///   for the bit-identical host argmax; the committed chain is unchanged.
15111    #[allow(clippy::too_many_arguments)]
15112    pub fn spec_generate_ext(
15113        &self,
15114        e: &Engine,
15115        de: &Engine,
15116        prompt: &[u32],
15117        max_new: usize,
15118        k: usize,
15119        state: &mut Qwen4ExpState,
15120        dstate: &mut MtpDraftState,
15121        sampler: Option<SpecSamplerCfg>,
15122        opts: SpecOpts,
15123        mut trace: Option<&mut Vec<SpecTraceRound>>,
15124    ) -> Res<SpecReport> {
15125        use std::time::Instant;
15126        if k == 0 {
15127            return Err("qwen4exp_gpu: spec needs k >= 1".into());
15128        }
15129        let n = prompt.len();
15130        if n < 2 {
15131            return Err("qwen4exp_gpu: spec needs a >= 2 token prompt".into());
15132        }
15133        if state.pos != 0 || dstate.rows != 0 {
15134            return Err("qwen4exp_gpu: spec_generate wants FRESH trunk + draft states".into());
15135        }
15136        if state.capacity < n + max_new + k + 2 || dstate.capacity < n + max_new + k + 2 {
15137            return Err("qwen4exp_gpu: state capacity too small for prompt + max_new + k".into());
15138        }
15139        self.check_draft_engine(de)?;
15140        let dev1 = self.mtp_dev1.is_some();
15141        if !dev1 && de.ctx().ordinal() != e.ctx().ordinal() {
15142            return Err(
15143                "qwen4exp_gpu: draft engine on another card, but the draft was not \
15144                 built there (load_from_dir_dev1)"
15145                    .into(),
15146            );
15147        }
15148        let vocab = self.vocab;
15149        let wide_w = self.streams * self.hidden;
15150        let greedy = sampler.is_none();
15151        let tracing = trace.is_some();
15152        let guard = opts.pmin > 0.0;
15153        let deferred = opts.defer;
15154        if deferred && tracing {
15155            return Err(
15156                "qwen4exp_gpu: spec defer + trace are mutually exclusive (the trace \
15157                 instrument reads per-step host rows); run the trace on the host-chain arm"
15158                    .into(),
15159            );
15160        }
15161        if deferred {
15162            let ce = self.chain_embed.as_ref().ok_or(
15163                "qwen4exp_gpu: SpecOpts::defer needs arm_spec_devchain on the draft engine",
15164            )?;
15165            if ce.dev != de.ctx().ordinal() {
15166                return Err(format!(
15167                    "qwen4exp_gpu: the chain-embed table lives on device {} but the \
15168                     draft engine is device {} — re-arm arm_spec_devchain",
15169                    ce.dev,
15170                    de.ctx().ordinal()
15171                )
15172                .into());
15173            }
15174            if ce.for_trim != self.draft_trim.is_some() || ce.rows != self.draft_logits_width() {
15175                return Err(
15176                    "qwen4exp_gpu: the chain-embed table was armed for a different trim \
15177                     state — re-arm arm_spec_devchain after trim changes"
15178                        .into(),
15179                );
15180            }
15181        }
15182        // Deferred-round device slots (ONE alloc per generation, on the draft engine):
15183        // chain picks in RAW draft-index space + the guard's per-step confidence.
15184        let (mut chain_toks_d, mut chain_probs_d) = if deferred {
15185            (
15186                Some(unsafe { de.gpu.stream().alloc::<u32>(k)? }),
15187                Some(de.zeros(k)?),
15188            )
15189        } else {
15190            (None, None)
15191        };
15192        let mut rng = sampler
15193            .as_ref()
15194            .map(|cfg| SpecRng(cfg.seed | 1))
15195            .unwrap_or(SpecRng(1));
15196        let t_total = Instant::now();
15197        let mut report = SpecReport {
15198            accept_hist: vec![0; k + 1],
15199            ..Default::default()
15200        };
15201
15202        match opts.wide_ring {
15203            Some(ring) => {
15204                let chunk = opts
15205                    .prefill_chunk
15206                    .ok_or("qwen4exp_gpu: SpecOpts::wide_ring needs prefill_chunk")?;
15207                if ring < 2 * chunk || ring < 2 * (k + 2) {
15208                    return Err("qwen4exp_gpu: wide_ring must cover 2 prefill chunks".into());
15209                }
15210                self.spec_arm_ring(e, state, k + 1, ring)?;
15211            }
15212            None => self.spec_arm(e, state, k + 1)?,
15213        }
15214        self.set_verify_want_argmax(state, false)?;
15215        if let Some(v) = state.verify.as_mut() {
15216            // mtp11 deferred seam: t == 1 steps commit through the device argmax
15217            // (greedy only) and big-t prefills dtoh one row instead of the block.
15218            v.want_argmax_t1 = deferred && greedy && !tracing;
15219            v.last_row_only = deferred;
15220        }
15221        // Card-1 mirror of the wide stash (the draft's seed source on the dev1 route) —
15222        // ring-sized like the stash itself (same slot addressing on both cards).
15223        let ring = state.verify.as_ref().expect("armed above").ring_rows;
15224        if dev1 {
15225            let v = state.verify.as_mut().expect("armed above");
15226            if v.wide_dev1.as_ref().is_none_or(|m| m.len() < ring * wide_w) {
15227                v.wide_dev1 = Some(de.zeros(ring * wide_w)?);
15228            }
15229        }
15230        // Defer arm's draft-side embed route: device gather from the full-vocab chain
15231        // table (a trim table cannot embed arbitrary target/prompt ids — host embed
15232        // stays the trim fallback, stated). Control arm (defer off): host embed,
15233        // structure-frozen.
15234        let dev_embed = deferred
15235            && self
15236                .chain_embed
15237                .as_ref()
15238                .is_some_and(|ce| !ce.for_trim && ce.rows == self.vocab);
15239        let t_prefill = Instant::now();
15240        let mut draft_prefill_ms = 0f64;
15241        let x0: u32 = match opts.prefill_chunk {
15242            // ---- Long-context CO-PREFILL (chunked): trunk chunk forward with the head
15243            // skipped (LastRow on the final chunk — a [n, vocab] logits block at 500k
15244            // would be hundreds of GB), then the dev1 crossing + the draft consuming
15245            // THAT chunk's wide rows before the ring overwrites them. Piece boundaries
15246            // keep the final piece past k_cap so no prefill chunk takes the verify-exact
15247            // path.
15248            Some(chunk) if n > chunk => {
15249                let mut b = 0usize;
15250                let mut last = Vec::new();
15251                // The spec arm banks ONE receipt row per rung, at the end. A long
15252                // co-prefill therefore looks identical to a hang from the outside, which
15253                // is exactly what happened in memra#53: two cells were killed by an
15254                // operator (45 min, 113 min) with no way to tell "slow route" from
15255                // "stuck". Progress prints on the non-spec ladder's cadence (every 8
15256                // chunks, plus the last) so a rung in flight is always observable.
15257                let mut chunks = 0usize;
15258                while b < n {
15259                    let mut t = chunk.min(n - b);
15260                    // Never leave a <= k_cap remainder as its own final piece.
15261                    if n - (b + t) > 0 && n - (b + t) <= k + 1 {
15262                        t = n - b;
15263                    }
15264                    let is_last = b + t == n;
15265                    let head = if is_last {
15266                        HeadMode::LastRow
15267                    } else {
15268                        HeadMode::Skip
15269                    };
15270                    let piece = self.forward_with(e, &prompt[b..b + t], state, None, head)?;
15271                    let t_draft = Instant::now();
15272                    if dev1 {
15273                        let v = state.verify.as_mut().expect("armed above");
15274                        let VerifyStash {
15275                            wide, wide_dev1, ..
15276                        } = v;
15277                        let mirror = wide_dev1.as_mut().expect("allocated above");
15278                        for (slot, len) in ring_pieces(ring, b, t) {
15279                            report.cross_ms +=
15280                                cross_wide_rows(e, de, wide, mirror, slot, len, wide_w)?;
15281                        }
15282                        report.cross_bytes += (t * wide_w * 4) as u64;
15283                    }
15284                    // Draft rows for positions [max(b,1), b+t): token p seeds wide[p-1]
15285                    // (the previous chunk's last row stays live: ring >= 2 chunks).
15286                    let p0 = b.max(1);
15287                    if b + t > p0 {
15288                        let v = state.verify.as_ref().expect("armed above");
15289                        let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
15290                        let (ld, cd, _) = self.draft_consume_ring(
15291                            de,
15292                            &prompt[p0..b + t],
15293                            dev_embed,
15294                            seed,
15295                            ring,
15296                            p0 - 1,
15297                            dstate,
15298                        )?;
15299                        self.mtp_recycle(dstate, ld, cd);
15300                    }
15301                    draft_prefill_ms += t_draft.elapsed().as_secs_f64() * 1e3;
15302                    b += t;
15303                    chunks += 1;
15304                    if chunks % 8 == 0 || is_last {
15305                        println!(
15306                            "# spec-prefill-progress\tfill={b}/{n}\tchunks={chunks}\t\
15307                             elapsed_s={:.1}\tdraft_s={:.1}",
15308                            t_prefill.elapsed().as_secs_f64(),
15309                            draft_prefill_ms / 1e3,
15310                        );
15311                    }
15312                    if is_last {
15313                        last = piece;
15314                    }
15315                }
15316                dstate.committed = n - 1;
15317                // Prefill is over and nothing wider than k + 1 rows runs again in this
15318                // generation: hand the t = 2,048 workspace back before the decode phase
15319                // asks for its own buffers (see `StepPool::shed`). Graphs bake slot
15320                // addresses, so they are invalidated here for the same reason a growing
15321                // multi-token chunk invalidates them — at this point they are already
15322                // default, because every t > 1 chunk reset them.
15323                let shed_bytes = state.ws.shed();
15324                state.graphs = StepGraphs::default();
15325                println!(
15326                    "# spec-prefill-shed\tworkspace_mib={:.1}\tchunks={chunks}",
15327                    shed_bytes as f64 / (1024.0 * 1024.0),
15328                );
15329                debug_assert_eq!(last.len(), vocab);
15330                match sampler.as_ref() {
15331                    None => host_argmax(&last) as u32,
15332                    Some(cfg) => sample_row(cfg, &mut rng, &last),
15333                }
15334            }
15335            // ---- Historical one-shot prefill (byte-stable receipts).
15336            _ => {
15337                let prefill = self.forward(e, prompt, state, None)?;
15338                // Shape-agnostic last-row read: the deferred seam's prefill dtoh is ONE
15339                // row (last_row_only), the control arm's is the full block; both end at
15340                // the row x0 reads. (A prompt shorter than k+2 runs the prefill as an
15341                // exact chunk and returns full rows on both arms.)
15342                let last = &prefill[prefill.len() - vocab..];
15343                let x0 = match sampler.as_ref() {
15344                    None => host_argmax(last) as u32,
15345                    Some(cfg) => sample_row(cfg, &mut rng, last),
15346                };
15347                let t_draft0 = Instant::now();
15348                if dev1 {
15349                    let v = state.verify.as_mut().expect("armed above");
15350                    let VerifyStash {
15351                        wide, wide_dev1, ..
15352                    } = v;
15353                    let mirror = wide_dev1.as_mut().expect("allocated above");
15354                    for (slot, len) in ring_pieces(ring, 0, n) {
15355                        report.cross_ms += cross_wide_rows(e, de, wide, mirror, slot, len, wide_w)?;
15356                    }
15357                    report.cross_bytes += (n * wide_w * 4) as u64;
15358                }
15359                {
15360                    let v = state.verify.as_ref().expect("armed above");
15361                    let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
15362                    if n >= 2 {
15363                        let (ld, cd, _) = self.draft_consume_ring(
15364                            de,
15365                            &prompt[1..],
15366                            dev_embed,
15367                            seed,
15368                            ring,
15369                            0,
15370                            dstate,
15371                        )?;
15372                        self.mtp_recycle(dstate, ld, cd);
15373                    }
15374                    dstate.committed = n - 1;
15375                }
15376                draft_prefill_ms += t_draft0.elapsed().as_secs_f64() * 1e3;
15377                x0
15378            }
15379        };
15380        report.prefill_ms = t_prefill.elapsed().as_secs_f64() * 1e3 - draft_prefill_ms;
15381        // Trace mode keeps the full verify-logits dtoh (want_argmax off) so fork
15382        // margins can be read; targets then come from the bit-identical host argmax.
15383        self.set_verify_want_argmax(state, greedy && !tracing)?;
15384        // x0 is the first generated token (parity with the plain chain's first argmax).
15385        report.tokens.push(x0);
15386
15387        // Bootstrap tip row: (x0 at position n, hidden wide[n-1]).
15388        let t_boot = Instant::now();
15389        let (mut tip_logits, mut tip_carrier) = {
15390            let v = state.verify.as_ref().expect("armed above");
15391            let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
15392            self.mtp_draft_forward_spec(de, &[x0], dev_embed, seed, (n - 1) % ring, dstate)?
15393        };
15394        let mut tip_rows = 1usize;
15395        dstate.committed = dstate.rows;
15396        report.draft_prefill_ms = draft_prefill_ms + t_boot.elapsed().as_secs_f64() * 1e3;
15397        report.draft_ms += report.draft_prefill_ms;
15398        // Prefills are done: a rounds-only profile starts HERE (see prof::split_prefill).
15399        prof::split_prefill();
15400
15401        let mut m = n; // trunk committed rows; tip sits at position m
15402        let mut tip = x0;
15403        // Admission state: k_cur = the dyn-K ceiling (decay-only), k_next = the
15404        // adaptive per-round window (accepted+1 recipe), window = the dyn-K ring.
15405        let mut k_cur = k;
15406        let mut k_next = k;
15407        let mut window: Vec<usize> = Vec::new();
15408        let mut round_idx = 0usize;
15409        while report.tokens.len() < max_new {
15410            if k_cur == 0 {
15411                // Dyn-K floored at 0: spec OFF for the remainder. Plain decode steps
15412                // (host argmax = the plain program — byte identity by construction);
15413                // the draft never runs again, which is exactly the saved cost.
15414                let row = self.forward(e, &[tip], state, None)?;
15415                let next: u32 = match sampler.as_ref() {
15416                    // Deferred seam: the plain step's token is the device argmax
15417                    // (bit-identical, argmax-gate contract); `row` is empty here.
15418                    None if deferred => self.verify_argmax_rows(state)?[0],
15419                    None => host_argmax(&row) as u32,
15420                    Some(cfg) => sample_row(cfg, &mut rng, &row),
15421                };
15422                report.tokens.push(next);
15423                report.plain_steps += 1;
15424                report
15425                    .round_wall
15426                    .push((report.tokens.len(), t_total.elapsed().as_secs_f64() * 1e3));
15427                m += 1;
15428                tip = next;
15429                continue;
15430            }
15431            let k_round = k_next.min(k_cur).max(1);
15432            // ---- draft chain: d1 from the tip row; steps 2..k_round carrier-chained.
15433            // The p-min guard stops the chain at the first sub-threshold pick (token
15434            // discarded uncounted); at j == 0 that makes a ZERO-draft round whose
15435            // verify is a plain t == 1 step.
15436            let t_draft = Instant::now();
15437            let mut drafts: Vec<u32> = Vec::with_capacity(k_round);
15438            let mut chain_rows_h: Vec<Vec<f32>> = Vec::new(); // trace: draft logit rows
15439            let mut seeds_h: Vec<Vec<f32>> = Vec::new(); // trace: carrier seeds used
15440            if let (Some(toks), Some(probs)) = (chain_toks_d.as_mut(), chain_probs_d.as_mut()) {
15441                // ---- DEFERRED chain (mtp11): picks and confidences stay in device
15442                // slots; the next step's embed gathers from the chain table, so host
15443                // dispatch of step j+1 overlaps device execution of step j and the
15444                // round drains ONCE (below) instead of blocking 2 dtoh per step.
15445                let width = self.draft_logits_width();
15446                de.argmax_token_device_col(&tip_logits, 0, width, toks, 0)?;
15447                if guard {
15448                    de.prob_of_token_device_col(&tip_logits, toks, 0, probs, 0, width)?;
15449                }
15450                let mut prev_logits = tip_logits;
15451                let mut prev_carrier = tip_carrier;
15452                let mut prev_rows = tip_rows;
15453                // Device slots holding a pick so far (guard_sync: a CHECKED pick).
15454                let mut drafted = 1usize;
15455                let mut stopped = false;
15456                if guard && opts.defer_guard_sync {
15457                    // Sequential-guard sub-arm: one 4-byte prob dtoh per step, the
15458                    // chain stops exactly where the host arm would (the discarded
15459                    // sub-threshold pick stays in its slot, uncounted).
15460                    let p = de.gpu.stream().clone_dtoh(&probs.slice(0..1))?[0];
15461                    if p < opts.pmin {
15462                        drafted = 0;
15463                        stopped = true;
15464                        report.guard_stops += 1;
15465                    }
15466                }
15467                while !stopped && drafted < k_round {
15468                    let (l2, c2) = self.mtp_draft_forward_devslot(
15469                        de,
15470                        toks,
15471                        drafted - 1,
15472                        &prev_carrier,
15473                        prev_rows - 1,
15474                        dstate,
15475                    )?;
15476                    self.mtp_recycle(dstate, prev_logits, prev_carrier);
15477                    prev_logits = l2;
15478                    prev_carrier = c2;
15479                    prev_rows = 1;
15480                    de.argmax_token_device_col(&prev_logits, 0, width, toks, drafted)?;
15481                    if guard {
15482                        de.prob_of_token_device_col(
15483                            &prev_logits,
15484                            toks,
15485                            drafted,
15486                            probs,
15487                            drafted,
15488                            width,
15489                        )?;
15490                        if opts.defer_guard_sync {
15491                            let p = de
15492                                .gpu
15493                                .stream()
15494                                .clone_dtoh(&probs.slice(drafted..drafted + 1))?[0];
15495                            if p < opts.pmin {
15496                                report.guard_stops += 1;
15497                                break;
15498                            }
15499                        }
15500                    }
15501                    drafted += 1;
15502                }
15503                self.mtp_recycle(dstate, prev_logits, prev_carrier);
15504                // ---- the round's ONE chain drain: the picks (and the deferred
15505                // guard's confidences) cross together; raw indices map to target ids
15506                // through draft_token, and the deferred guard truncates at the FIRST
15507                // sub-threshold step — the same discard the sequential arm makes.
15508                if drafted > 0 {
15509                    let raw = de.gpu.stream().clone_dtoh(&toks.slice(0..drafted))?;
15510                    let trunc = if guard && !opts.defer_guard_sync {
15511                        let pw = de.gpu.stream().clone_dtoh(&probs.slice(0..drafted))?;
15512                        let trunc = spec_guard_trunc(&pw, opts.pmin);
15513                        if trunc < drafted {
15514                            report.guard_stops += 1;
15515                        }
15516                        trunc
15517                    } else {
15518                        drafted
15519                    };
15520                    for &r in raw.iter().take(trunc) {
15521                        drafts.push(self.draft_token(r)?);
15522                    }
15523                }
15524            } else {
15525                let (d1, c1) = self.draft_row_argmax(de, &tip_logits, 0, guard)?;
15526                if !(guard && c1 < opts.pmin) {
15527                    drafts.push(d1);
15528                    if tracing {
15529                        chain_rows_h
15530                            .push(de.dtoh_view(&tip_logits.slice(0..self.draft_logits_width()))?);
15531                    }
15532                } else {
15533                    report.guard_stops += 1;
15534                }
15535                let mut prev_logits = tip_logits;
15536                let mut prev_carrier = tip_carrier;
15537                let mut prev_rows = tip_rows;
15538                while !drafts.is_empty() && drafts.len() < k_round {
15539                    if tracing {
15540                        seeds_h.push(de.dtoh_view(
15541                            &prev_carrier.slice((prev_rows - 1) * wide_w..prev_rows * wide_w),
15542                        )?);
15543                    }
15544                    let lastd = *drafts.last().expect("non-empty");
15545                    let (l2, c2) = self.mtp_draft_forward(
15546                        de,
15547                        &[lastd],
15548                        &prev_carrier,
15549                        prev_rows - 1,
15550                        dstate,
15551                        1,
15552                        false,
15553                    )?;
15554                    self.mtp_recycle(dstate, prev_logits, prev_carrier);
15555                    prev_logits = l2;
15556                    prev_carrier = c2;
15557                    prev_rows = 1;
15558                    let (dn, cn) = self.draft_row_argmax(de, &prev_logits, 0, guard)?;
15559                    if guard && cn < opts.pmin {
15560                        report.guard_stops += 1;
15561                        break;
15562                    }
15563                    drafts.push(dn);
15564                    if tracing {
15565                        chain_rows_h
15566                            .push(de.dtoh_view(&prev_logits.slice(0..self.draft_logits_width()))?);
15567                    }
15568                }
15569                self.mtp_recycle(dstate, prev_logits, prev_carrier);
15570            }
15571            let chain_ms = t_draft.elapsed().as_secs_f64() * 1e3;
15572            report.chain_ms += chain_ms;
15573            report.draft_ms += chain_ms;
15574
15575            // ---- verify chunk [tip, d1..] at base m (t == 1 on a zero-draft round —
15576            // a plain decode step that still commits one token).
15577            let t_ver = Instant::now();
15578            let mut chunk = Vec::with_capacity(drafts.len() + 1);
15579            chunk.push(tip);
15580            chunk.extend_from_slice(&drafts);
15581            let tlen = chunk.len();
15582            let host_logits = self.forward(e, &chunk, state, None)?;
15583            // Deferred seam: the t == 1 zero-draft verify also commits through the
15584            // device argmax (want_argmax_t1) — no [1, vocab] row + host scan.
15585            let targets: Vec<u32> = if greedy && !tracing && (tlen > 1 || deferred) {
15586                self.verify_argmax_rows(state)?.to_vec()
15587            } else if greedy {
15588                (0..tlen)
15589                    .map(|row| host_argmax(&host_logits[row * vocab..(row + 1) * vocab]) as u32)
15590                    .collect()
15591            } else {
15592                let cfg = sampler.as_ref().expect("sampled mode");
15593                (0..tlen)
15594                    .map(|row| {
15595                        sample_row(cfg, &mut rng, &host_logits[row * vocab..(row + 1) * vocab])
15596                    })
15597                    .collect()
15598            };
15599            report.verify_ms += t_ver.elapsed().as_secs_f64() * 1e3;
15600            if targets.len() != tlen {
15601                return Err("qwen4exp_gpu: verify produced the wrong row count".into());
15602            }
15603
15604            // ---- greedy accept walk (exact match to the target row).
15605            let mut a = 0usize;
15606            while a < drafts.len() && drafts[a] == targets[a] {
15607                a += 1;
15608            }
15609            report.rounds += 1;
15610            report.drafted += drafts.len() as u64;
15611            report.accepted += a as u64;
15612            report.accept_hist[a] += 1;
15613            if drafts.is_empty() {
15614                report.zero_draft_rounds += 1;
15615            }
15616            report.tokens.extend_from_slice(&targets[0..=a]);
15617
15618            // ---- trace record (fork margins from the stashed rows; carrier drift vs
15619            // the verify chunk's TRUE wide rows).
15620            if let Some(tr) = trace.as_deref_mut() {
15621                let mut rec = SpecTraceRound {
15622                    round: round_idx,
15623                    gen_pos: report.tokens.len() - (a + 1),
15624                    base: m,
15625                    k: drafts.len(),
15626                    a,
15627                    drafts: drafts.clone(),
15628                    targets: targets.clone(),
15629                    draft_top1: f32::NAN,
15630                    draft_top2: f32::NAN,
15631                    draft_tgt_logit: f32::NAN,
15632                    draft_tgt_rank: 0,
15633                    target_top1: f32::NAN,
15634                    target_top2: f32::NAN,
15635                    target_draft_logit: f32::NAN,
15636                    target_entropy: 0.0,
15637                    carrier_rel_l2: Vec::new(),
15638                    carrier_cos: Vec::new(),
15639                };
15640                if a < drafts.len() {
15641                    let drow = &chain_rows_h[a];
15642                    let trow = &host_logits[a * vocab..(a + 1) * vocab];
15643                    let tgt = targets[a] as usize;
15644                    let dtok = drafts[a] as usize;
15645                    let (mut d1v, mut d2v) = (f32::NEG_INFINITY, f32::NEG_INFINITY);
15646                    let mut rank = 0usize;
15647                    let dt = drow[tgt];
15648                    for &v in drow.iter() {
15649                        if v > d1v {
15650                            d2v = d1v;
15651                            d1v = v;
15652                        } else if v > d2v {
15653                            d2v = v;
15654                        }
15655                        if v > dt {
15656                            rank += 1;
15657                        }
15658                    }
15659                    let (mut t1v, mut t2v) = (f32::NEG_INFINITY, f32::NEG_INFINITY);
15660                    for &v in trow.iter() {
15661                        if v > t1v {
15662                            t2v = t1v;
15663                            t1v = v;
15664                        } else if v > t2v {
15665                            t2v = v;
15666                        }
15667                    }
15668                    // Softmax entropy of the target row (nats), f64 accumulation.
15669                    let mx = t1v as f64;
15670                    let mut z = 0.0f64;
15671                    let mut sxl = 0.0f64;
15672                    for &v in trow.iter() {
15673                        let ev = ((v as f64) - mx).exp();
15674                        z += ev;
15675                        sxl += ev * ((v as f64) - mx);
15676                    }
15677                    rec.draft_top1 = d1v;
15678                    rec.draft_top2 = d2v;
15679                    rec.draft_tgt_logit = dt;
15680                    rec.draft_tgt_rank = rank;
15681                    rec.target_top1 = t1v;
15682                    rec.target_top2 = t2v;
15683                    rec.target_draft_logit = trow[dtok];
15684                    rec.target_entropy = z.ln() - sxl / z;
15685                }
15686                let v = state.verify.as_ref().expect("armed above");
15687                for (j, seed) in seeds_h.iter().enumerate() {
15688                    let slot = (m + j) % ring;
15689                    let truth = e.dtoh_view(&v.wide.slice(slot * wide_w..(slot + 1) * wide_w))?;
15690                    let mut dd = 0.0f64;
15691                    let mut tt = 0.0f64;
15692                    let mut st = 0.0f64;
15693                    let mut ss = 0.0f64;
15694                    for (&s, &t) in seed.iter().zip(truth.iter()) {
15695                        let (s, t) = (s as f64, t as f64);
15696                        dd += (s - t) * (s - t);
15697                        tt += t * t;
15698                        st += s * t;
15699                        ss += s * s;
15700                    }
15701                    rec.carrier_rel_l2
15702                        .push((dd.sqrt() / tt.sqrt().max(1e-30)) as f32);
15703                    rec.carrier_cos
15704                        .push((st / (ss.sqrt() * tt.sqrt()).max(1e-30)) as f32);
15705                }
15706                tr.push(rec);
15707            }
15708
15709            // ---- rewind trunk to the accepted rows; draft catch-up replay.
15710            if tlen > 1 {
15711                self.verify_rewind(e, state, a + 1)?;
15712            }
15713            self.mtp_rewind(dstate, m)?;
15714            let t_draft2 = Instant::now();
15715            let x_next = targets[a];
15716            let mut replay: Vec<u32> = drafts[0..a].to_vec();
15717            replay.push(x_next);
15718            if dev1 {
15719                let v = state.verify.as_mut().expect("armed above");
15720                let VerifyStash {
15721                    wide, wide_dev1, ..
15722                } = v;
15723                let mirror = wide_dev1.as_mut().expect("allocated above");
15724                for (slot, len) in ring_pieces(ring, m, replay.len()) {
15725                    report.cross_ms += cross_wide_rows(e, de, wide, mirror, slot, len, wide_w)?;
15726                }
15727                report.cross_bytes += (replay.len() * wide_w * 4) as u64;
15728            }
15729            let (l, c, last_len) = {
15730                let v = state.verify.as_ref().expect("armed above");
15731                let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
15732                self.draft_consume_ring(de, &replay, dev_embed, seed, ring, m, dstate)?
15733            };
15734            tip_logits = l;
15735            tip_carrier = c;
15736            tip_rows = last_len;
15737            dstate.committed = dstate.rows;
15738            let replay_ms = t_draft2.elapsed().as_secs_f64() * 1e3;
15739            report.replay_ms += replay_ms;
15740            report.draft_ms += replay_ms;
15741            m += a + 1;
15742            tip = x_next;
15743            report
15744                .round_wall
15745                .push((report.tokens.len(), t_total.elapsed().as_secs_f64() * 1e3));
15746
15747            // ---- bounded admission updates (both decay-only within the round budget).
15748            if let Some(lo) = opts.adapt_k_lo {
15749                k_next = (a + 1).clamp(lo.max(1), k);
15750            }
15751            if let Some(cfg) = opts.dynk {
15752                window.push(a);
15753                if window.len() >= cfg.window.max(1) {
15754                    let mean = window.iter().sum::<usize>() as f64 / window.len() as f64;
15755                    if mean < cfg.thr {
15756                        let new_k = k_cur.saturating_sub(1).max(cfg.k_floor);
15757                        if new_k < k_cur {
15758                            k_cur = new_k;
15759                            report.k_decays.push((round_idx, k_cur));
15760                            if k_cur == 0 {
15761                                report.spec_off_at = Some(report.tokens.len());
15762                            }
15763                        }
15764                    }
15765                    window.clear();
15766                }
15767            }
15768            round_idx += 1;
15769        }
15770        report.tokens.truncate(max_new);
15771        report.total_ms = t_total.elapsed().as_secs_f64() * 1e3;
15772        Ok(report)
15773    }
15774}
15775
15776// ---------------------------------------------------------------- checkpoint loading
15777//
15778// The pack/plan/contract walk over an HF safetensors dir. The loader PROBES the artifact
15779// for its routed-expert dialect (ExpertDialect: the BF16 export's fused 3D banks, or the
15780// NVFP4 mint's per-expert modelopt projections — census receipt
15781// research/qwen4exp-bringup-20260829/raw/nvfp4-census-names.tsv) and binds through the
15782// pack's dialect contract. Trunk + globals materialize into reference-layout weights; the
15783// n-gram table stays host-resident (sharded or the mint's single tensor); expert banks
15784// admit BF16 (dequantized) or modelopt NVFP4 (as-stored device residency). `input_scale`
15785// (modelopt static activation scale) is contract-declared as an auxiliary, VALIDATED here
15786// (F32 scalar) and deliberately UNUSED: the eager arm is W4A16-class (weights dequantize
15787// to f32, activations stay f32), so the scale has no consumer until the W4A4 kernel lane
15788// quantizes activations — the dsv4 precedent ("W4A8 activation scale, unused for decode").
15789// MTP and vision tensors are validated owners but not materialized — the eager arm
15790// executes neither (module header).
15791
15792/// One expert bank tensor (one PROJECTION: gate, up, or down), assembled across experts.
15793enum BankTensorSrc {
15794    /// Dequantized f32, logical [n_expert, out_f, in_f].
15795    F32(Vec<f32>),
15796    /// modelopt NVFP4: e2m1 codes [E, out, in/2], e4m3 scales [E, out, in/16],
15797    /// per-expert finite macro scales (the real mint's are amax-derived non-pow2), and
15798    /// the projection's STATIC ACTIVATION scale — the max of the per-expert
15799    /// `input_scale` siblings. RECORDED-ONLY by owner order (2026-08-30): activation
15800    /// quantization is retired as a serving lever (it measurably moved decode argmax —
15801    /// perf22 seam-gate receipt, PROFILE-4 §W4A4); no compute path consumes this value,
15802    /// and no future lane re-proposes consuming it without a fresh owner ruling.
15803    Nvfp4 {
15804        codes: Vec<u8>,
15805        scales: Vec<u8>,
15806        macros: Vec<f32>,
15807        act_scale: Option<f32>,
15808    },
15809    /// Raw bf16 bytes at the logical shape [n_expert, out_f, in_f] — kept when
15810    /// `LoadOptions::host_bf16_banks` asks for the host-resident gate residency.
15811    Bf16(Vec<u8>),
15812}
15813
15814struct BankSrc {
15815    gate: BankTensorSrc, // logical [E, ff, H]
15816    up: BankTensorSrc,   // logical [E, ff, H]
15817    down: BankTensorSrc, // logical [E, H, ff]
15818    n_expert: usize,
15819    ff: usize,
15820    hidden: usize,
15821}
15822
15823/// One fused bank tensor's read address: the artifact name plus the contract shape the
15824/// walk already validated it against ([E, out_f, in_f], logical).
15825struct FusedTensorPlan {
15826    name: String,
15827    shape: [usize; 3],
15828}
15829
15830/// One PER-EXPERT projection's read addresses, in EXPERT ORDER 0..E. The walk builds this
15831/// from a numerically-keyed map and checks contiguity there, so this vector's index IS the
15832/// expert id — the lexicographic-arrival trap (`experts.10` before `experts.2`) is already
15833/// absorbed before anything is read.
15834struct PerExpertPlan {
15835    names: Vec<String>, // expert order 0..E
15836    out_f: usize,
15837    in_f: usize,
15838    quant: memra_gguf::tensor_contract::QuantConstraint,
15839}
15840
15841enum BankPlanSrc {
15842    /// FusedBanks dialect: the fused [E, 2ff, H] gate_up tensor + the [E, H, ff] down.
15843    Fused {
15844        gate_up: FusedTensorPlan,
15845        down: FusedTensorPlan,
15846        /// Residency decided at WALK time, exactly as before
15847        /// (`LoadOptions::host_bf16_banks`, or an MTP bank at index >= n_trunk): a bf16
15848        /// bank keeps raw bytes instead of dequantizing to f32. Fused-only — the
15849        /// per-expert modelopt rows are F32 or NVFP4 by geometry, never a bf16 arm.
15850        keep_bf16: bool,
15851    },
15852    /// PerExpertModelopt dialect: one name list per projection.
15853    PerExpert {
15854        gate: PerExpertPlan,
15855        up: PerExpertPlan,
15856        down: PerExpertPlan,
15857    },
15858}
15859
15860/// WHERE one layer's expert bank lives in the artifact and HOW to bind it — everything
15861/// `BankSrc` needs except the bytes.
15862///
15863/// This is the streaming seam. The walk validates names/shapes/dtypes/geometry/expert
15864/// contiguity and records this plan; the bytes are read one LAYER at a time inside the
15865/// consuming loop (`from_loaded_checkpoint_dual`, `build_tp2_shard`,
15866/// `into_reference_weights`) straight off the safetensors mmap, uploaded, and dropped.
15867/// Pre-materializing all 48 layers cost the whole artifact in host anon memory at once
15868/// (~72 GB of banks on top of the 102 GB n-gram table and ~20 GB of trunk f32), which
15869/// OOM-killed the real gate at 179.7 GB anon-RSS on a 180 GB-RAM box — the cheapest
15870/// 2-card class. Nothing about the BYTES changes: the same
15871/// `read_bank_tensor`/`read_per_expert`/`assemble_per_expert_bank`/`split_fused_gate_up`
15872/// chain runs on the same file offsets in the same expert order, just later.
15873struct BankPlan {
15874    n_expert: usize,
15875    ff: usize,
15876    hidden: usize,
15877    src: BankPlanSrc,
15878}
15879
15880impl BankPlan {
15881    /// Read + assemble THIS layer's bank off the mmap. Peak host cost is one layer's bank
15882    /// (~1.5 GB on the real mint), not the artifact.
15883    fn read(&self, model: &memra_gguf::safetensors::StModel) -> Res<BankSrc> {
15884        let (gate, up, down) = match &self.src {
15885            BankPlanSrc::Fused {
15886                gate_up,
15887                down,
15888                keep_bf16,
15889            } => {
15890                let fused = read_bank_tensor(
15891                    model,
15892                    &gate_up.name,
15893                    gate_up.shape[0],
15894                    gate_up.shape[1],
15895                    gate_up.shape[2],
15896                    *keep_bf16,
15897                )?;
15898                let (gate, up) = split_fused_gate_up(fused, self.n_expert, self.ff, self.hidden)?;
15899                let down = read_bank_tensor(
15900                    model,
15901                    &down.name,
15902                    down.shape[0],
15903                    down.shape[1],
15904                    down.shape[2],
15905                    *keep_bf16,
15906                )?;
15907                (gate, up, down)
15908            }
15909            BankPlanSrc::PerExpert { gate, up, down } => (
15910                read_per_expert_bank(model, gate)?,
15911                read_per_expert_bank(model, up)?,
15912                read_per_expert_bank(model, down)?,
15913            ),
15914        };
15915        Ok(BankSrc {
15916            gate,
15917            up,
15918            down,
15919            n_expert: self.n_expert,
15920            ff: self.ff,
15921            hidden: self.hidden,
15922        })
15923    }
15924}
15925
15926/// WALK-time refusal for a bank tensor whose PAYLOAD is read later: the name must exist in
15927/// the census and carry a dtype the bank readers admit.
15928///
15929/// `StModel::info` is header-only, so this faults no weight page and costs no host memory.
15930/// It keeps the contract walk's "every declared name exists" property — a mint missing a
15931/// projection is refused before the 102 GB table is allocated and before one byte reaches
15932/// the device. Shape, scale siblings, macro finiteness and `input_scale` validity are
15933/// checked by `read_bank_tensor`/`read_per_expert` when the layer is read, which is still
15934/// load time (before any forward), just per layer instead of all at once.
15935fn check_bank_header(model: &memra_gguf::safetensors::StModel, name: &str) -> Res<()> {
15936    let info = model
15937        .info(name)
15938        .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
15939    match info.dtype.as_str() {
15940        "BF16" | "F32" | "U8" => Ok(()),
15941        other => Err(format!("qwen4exp_gpu: {name} bank dtype {other} unsupported").into()),
15942    }
15943}
15944
15945/// Read one per-expert projection in expert order and stack it — the deferred half of the
15946/// old walk's `read_per_expert` + `assemble_per_expert_bank` pair, byte-for-byte.
15947fn read_per_expert_bank(
15948    model: &memra_gguf::safetensors::StModel,
15949    plan: &PerExpertPlan,
15950) -> Res<BankTensorSrc> {
15951    let mut experts = Vec::with_capacity(plan.names.len());
15952    for name in &plan.names {
15953        experts.push(read_per_expert(
15954            model, name, plan.out_f, plan.in_f, plan.quant,
15955        )?);
15956    }
15957    assemble_per_expert_bank(experts)
15958}
15959
15960/// A checkpoint materialized through the pack contract: reference-layout weights for the
15961/// trunk + globals (effective norms — the (1+w) fold applied per the module-header rule),
15962/// plus the table carrier that stays out of `ReferenceWeights` and the LAZY bank plans.
15963///
15964/// The open safetensors mmap is part of the value: expert banks are read from it per layer
15965/// at consume time (see `BankPlan`). It stays mapped until the checkpoint is dropped, so a
15966/// consumer must not outlive it — every consumer here is a constructor that finishes
15967/// uploading before returning.
15968pub struct LoadedCheckpoint {
15969    pub plan: ModelPlan,
15970    pub weights: ReferenceWeights,
15971    model: memra_gguf::safetensors::StModel,
15972    bank_plans: std::collections::BTreeMap<u32, BankPlan>,
15973    tables: std::collections::BTreeMap<u32, Vec<u8>>, // bf16 bytes, [rows, head_dim]
15974}
15975
15976/// (1+w) fold rule for checkpoint norm rows — the qwen35 receipt (hf_mapping.rs,
15977/// qwen.py:302-303): every `*norm*.weight` EXCEPT `linear_attn.norm` (RMSNormGated binds
15978/// raw weights; SEMANTICS.md §GDN keeps the qwen3_5 GDN program). VERIFY vs the goldens
15979/// lane for the indexer layernorms (assumed the family (1+w) class — the zero-init
15980/// receipt, modular L860).
15981fn norm_fold_add_one(name: &str) -> bool {
15982    name.contains("norm") && name.ends_with(".weight") && !name.ends_with("linear_attn.norm.weight")
15983}
15984
15985/// The QSA indexer's q/k layernorm rows — the SEMANTICS.md VERIFY subject. The default
15986/// fold treats them as family (1+w); `LoadOptions::indexer_norm_raw` binds them raw so
15987/// the real-checkpoint per-layer gate can measure both arms and settle the question.
15988fn indexer_layernorm(name: &str) -> bool {
15989    name.contains(".indexer.")
15990        && (name.ends_with("q_layernorm.weight") || name.ends_with("k_layernorm.weight"))
15991}
15992
15993/// Real-checkpoint loader knobs (defaults = the tiny-gate behavior).
15994#[derive(Default, Clone, Copy)]
15995pub struct LoadOptions {
15996    /// Keep BF16 expert banks HOST-resident (raw bf16) and upload+upcast per ROUTED
15997    /// expert at forward time. Gate-mode residency for artifacts whose f32 banks
15998    /// exceed device memory; value chain identical to the f32 device arm (bf16→f32
15999    /// is exact). Never a serving configuration.
16000    pub host_bf16_banks: bool,
16001    /// Bind the indexer q/k layernorms RAW (skip the (1+w) fold) — the two-arm probe
16002    /// for the SEMANTICS.md VERIFY marker. Default keeps the family fold.
16003    pub indexer_norm_raw: bool,
16004    /// Materialize the mtp.* namespace (the NextN draft block) — the mtp-spec lane.
16005    /// The MTP expert bank keeps its raw BF16 bytes at read time and goes DEVICE
16006    /// bf16-resident at build (`BankHalf::DeviceBf16`, ~5 GB beside the NVFP4 trunk).
16007    /// Default OFF: the plain eager arm executes no draft.
16008    pub load_mtp: bool,
16009}
16010
16011fn bridge_transform(
16012    transform: memra_gguf::tensor_contract::TensorTransform,
16013) -> Res<memra_gguf::hf_mapping::TransformKind> {
16014    use memra_gguf::hf_mapping::TransformKind as K;
16015    use memra_gguf::tensor_contract::TensorTransform as T;
16016    Ok(match transform {
16017        T::Identity => K::Identity,
16018        T::NormAddOne => K::NormPlusOne,
16019        T::QkvVReorderRows => K::QkvVReorderRows,
16020        T::ZReorderRows => K::ZReorderRows,
16021        T::AbReorderRows => K::AbReorderRows,
16022        T::NegExpReorderHeads => K::NegExpReorderHeads,
16023        T::ReorderHeads => K::ReorderHeads,
16024        T::Conv1dSqueezeReorder => K::Conv1dSqueezeReorder,
16025        T::OutReorderColumns => K::OutReorderCols,
16026        other => return Err(format!("qwen4exp_gpu: unsupported transform {other:?}").into()),
16027    })
16028}
16029
16030fn dequant_float(
16031    name: &str,
16032    info: &memra_gguf::safetensors::StInfo,
16033    bytes: &[u8],
16034) -> Res<Vec<f32>> {
16035    let elements: usize = info.shape.iter().map(|&d| d as usize).product();
16036    match info.dtype.as_str() {
16037        "BF16" | "F32" => Ok(memra_gguf::dequant::dequantize(
16038            info.ggml_type()
16039                .map_err(|error| format!("qwen4exp_gpu: {name}: {error}"))?,
16040            bytes,
16041            elements,
16042        )),
16043        other => Err(format!("qwen4exp_gpu: {name} has unsupported float dtype {other}").into()),
16044    }
16045}
16046
16047fn read_i64(name: &str, info: &memra_gguf::safetensors::StInfo, bytes: &[u8]) -> Res<Vec<i64>> {
16048    if info.dtype != "I64" {
16049        return Err(format!("qwen4exp_gpu: {name} must be I64, got {}", info.dtype).into());
16050    }
16051    Ok(bytes
16052        .chunks_exact(8)
16053        .map(|chunk| i64::from_le_bytes(chunk.try_into().unwrap()))
16054        .collect())
16055}
16056
16057/// Macro-scale validation. The dsv4 pow2 law does NOT apply here: this module's dequant
16058/// chain applies the macro post-upcast in f32 (`dequant_nvfp4_expert_f32`), which is
16059/// exact-then-single-rounding for ANY finite positive macro — and the real qwen4_exp
16060/// mint ships modelopt's amax-derived NON-pow2 `weight_scale_2` (first value refused by
16061/// the inherited pow2 assert on the fleet box, 2026-08-29: 5.9945243e-5 on
16062/// layers.0.mlp.experts.0.down_proj). Refusal is reserved for values that poison the
16063/// arithmetic outright.
16064fn validate_macro(stem: &str, value: f32) -> Res<()> {
16065    if !(value.is_finite() && value > 0.0) {
16066        return Err(format!(
16067            "qwen4exp_gpu: {stem}.weight_scale_2 carries a non-finite/non-positive \
16068             macro {value}"
16069        )
16070        .into());
16071    }
16072    Ok(())
16073}
16074
16075/// Read one STACKED expert bank (FusedBanks dialect): BF16 at the declared logical shape,
16076/// or the modelopt-NVFP4 stacked triplet whose validation mirrors
16077/// `find_nvfp4_stacked_native` (source.rs): U8 codes [E, out, in/2] + F8_E4M3
16078/// `weight_scale` [E, out, in/16] + optional F32 `weight_scale_2` [E] (absent -> 1.0).
16079fn read_bank_tensor(
16080    model: &memra_gguf::safetensors::StModel,
16081    name: &str,
16082    n_expert: usize,
16083    out_f: usize,
16084    in_f: usize,
16085    host_bf16: bool,
16086) -> Res<BankTensorSrc> {
16087    let (info, bytes) = model
16088        .raw(name)
16089        .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16090    match info.dtype.as_str() {
16091        "BF16" | "F32" => {
16092            if info.shape != [n_expert as u64, out_f as u64, in_f as u64] {
16093                return Err(format!("qwen4exp_gpu: {name} bank shape mismatch").into());
16094            }
16095            if host_bf16 && info.dtype == "BF16" {
16096                if bytes.len() != n_expert * out_f * in_f * 2 {
16097                    return Err(format!("qwen4exp_gpu: {name} bank byte-length mismatch").into());
16098                }
16099                return Ok(BankTensorSrc::Bf16(bytes.to_vec()));
16100            }
16101            Ok(BankTensorSrc::F32(dequant_float(name, info, bytes)?))
16102        }
16103        "U8" => {
16104            if in_f % 16 != 0
16105                || info.shape != [n_expert as u64, out_f as u64, (in_f / 2) as u64]
16106                || bytes.len() != n_expert * out_f * in_f / 2
16107            {
16108                return Err(format!("qwen4exp_gpu: {name} NVFP4 code shape mismatch").into());
16109            }
16110            let stem = name.strip_suffix(".weight").unwrap_or(name);
16111            let scale_name = format!("{stem}.weight_scale");
16112            let (scale_info, scale_bytes) = model
16113                .raw(&scale_name)
16114                .ok_or_else(|| format!("qwen4exp_gpu: missing {scale_name}"))?;
16115            if scale_info.dtype != "F8_E4M3"
16116                || scale_info.shape != [n_expert as u64, out_f as u64, (in_f / 16) as u64]
16117                || scale_bytes.len() != n_expert * out_f * in_f / 16
16118            {
16119                return Err(format!("qwen4exp_gpu: {scale_name} shape mismatch").into());
16120            }
16121            let macros = match model.raw(&format!("{stem}.weight_scale_2")) {
16122                Some((macro_info, macro_bytes))
16123                    if macro_info.dtype == "F32" && macro_bytes.len() == n_expert * 4 =>
16124                {
16125                    macro_bytes
16126                        .chunks_exact(4)
16127                        .map(|chunk| f32::from_le_bytes(chunk.try_into().unwrap()))
16128                        .collect()
16129                }
16130                None => vec![1.0; n_expert],
16131                _ => return Err(format!("qwen4exp_gpu: {stem}.weight_scale_2 malformed").into()),
16132            };
16133            for &m in &macros {
16134                validate_macro(stem, m)?;
16135            }
16136            // Optional stacked input_scale [E] (the per-expert mint carries scalars via
16137            // the PerExpertModelopt path; a stacked artifact may carry the vector) —
16138            // reduced to the per-layer max for the W4A4 activation quantization.
16139            let act_scale = match model.raw(&format!("{stem}.input_scale")) {
16140                Some((is_info, is_bytes))
16141                    if is_info.dtype == "F32" && is_bytes.len() == n_expert * 4 =>
16142                {
16143                    let mut mx = 0.0f32;
16144                    for chunk in is_bytes.chunks_exact(4) {
16145                        let v = f32::from_le_bytes(chunk.try_into().unwrap());
16146                        if !(v.is_finite() && v > 0.0) {
16147                            return Err(format!(
16148                                "qwen4exp_gpu: {stem}.input_scale carries a non-finite/\
16149                                 non-positive value {v}"
16150                            )
16151                            .into());
16152                        }
16153                        mx = mx.max(v);
16154                    }
16155                    Some(mx)
16156                }
16157                Some(_) => {
16158                    return Err(format!("qwen4exp_gpu: {stem}.input_scale malformed").into());
16159                }
16160                None => None,
16161            };
16162            Ok(BankTensorSrc::Nvfp4 {
16163                codes: bytes.to_vec(),
16164                scales: scale_bytes.to_vec(),
16165                macros,
16166                act_scale,
16167            })
16168        }
16169        other => Err(format!("qwen4exp_gpu: {name} bank dtype {other} unsupported").into()),
16170    }
16171}
16172
16173/// Split a FUSED gate_up source ([E, 2ff, H], gate rows first per expert) into per-
16174/// projection gate/up sources. F32 splits data rows; NVFP4 splits code/scale byte rows
16175/// (row-granular, byte-clean) and duplicates the per-expert macro to both halves.
16176fn split_fused_gate_up(
16177    fused: BankTensorSrc,
16178    n_expert: usize,
16179    ff: usize,
16180    hidden: usize,
16181) -> Res<(BankTensorSrc, BankTensorSrc)> {
16182    match fused {
16183        BankTensorSrc::F32(data) => {
16184            if data.len() != n_expert * 2 * ff * hidden {
16185                return Err("qwen4exp_gpu: fused gate_up bank size mismatch".into());
16186            }
16187            let mut gate = Vec::with_capacity(n_expert * ff * hidden);
16188            let mut up = Vec::with_capacity(n_expert * ff * hidden);
16189            for expert in 0..n_expert {
16190                let base = expert * 2 * ff * hidden;
16191                gate.extend_from_slice(&data[base..base + ff * hidden]);
16192                up.extend_from_slice(&data[base + ff * hidden..base + 2 * ff * hidden]);
16193            }
16194            Ok((BankTensorSrc::F32(gate), BankTensorSrc::F32(up)))
16195        }
16196        BankTensorSrc::Bf16(bytes) => {
16197            let row = hidden * 2; // bf16 bytes per fused row
16198            if bytes.len() != n_expert * 2 * ff * row {
16199                return Err("qwen4exp_gpu: fused bf16 gate_up bank size mismatch".into());
16200            }
16201            let mut gate = Vec::with_capacity(n_expert * ff * row);
16202            let mut up = Vec::with_capacity(n_expert * ff * row);
16203            for expert in 0..n_expert {
16204                let base = expert * 2 * ff * row;
16205                gate.extend_from_slice(&bytes[base..base + ff * row]);
16206                up.extend_from_slice(&bytes[base + ff * row..base + 2 * ff * row]);
16207            }
16208            Ok((BankTensorSrc::Bf16(gate), BankTensorSrc::Bf16(up)))
16209        }
16210        BankTensorSrc::Nvfp4 {
16211            codes,
16212            scales,
16213            macros,
16214            act_scale,
16215        } => {
16216            let code_row = hidden / 2;
16217            let scale_row = hidden / 16;
16218            let mut gate_codes = Vec::with_capacity(n_expert * ff * code_row);
16219            let mut up_codes = Vec::with_capacity(n_expert * ff * code_row);
16220            let mut gate_scales = Vec::with_capacity(n_expert * ff * scale_row);
16221            let mut up_scales = Vec::with_capacity(n_expert * ff * scale_row);
16222            for expert in 0..n_expert {
16223                let cbase = expert * 2 * ff * code_row;
16224                gate_codes.extend_from_slice(&codes[cbase..cbase + ff * code_row]);
16225                up_codes
16226                    .extend_from_slice(&codes[cbase + ff * code_row..cbase + 2 * ff * code_row]);
16227                let sbase = expert * 2 * ff * scale_row;
16228                gate_scales.extend_from_slice(&scales[sbase..sbase + ff * scale_row]);
16229                up_scales
16230                    .extend_from_slice(&scales[sbase + ff * scale_row..sbase + 2 * ff * scale_row]);
16231            }
16232            Ok((
16233                BankTensorSrc::Nvfp4 {
16234                    codes: gate_codes,
16235                    scales: gate_scales,
16236                    macros: macros.clone(),
16237                    act_scale,
16238                },
16239                BankTensorSrc::Nvfp4 {
16240                    codes: up_codes,
16241                    scales: up_scales,
16242                    macros,
16243                    act_scale,
16244                },
16245            ))
16246        }
16247    }
16248}
16249
16250/// One PER-EXPERT projection (PerExpertModelopt dialect): the modelopt sibling schema
16251/// (`nvfp4_quant`'s modelopt arm, source.rs — weight U8 [out, in/2] + weight_scale +
16252/// scalar weight_scale_2), or a plain BF16 row where geometry forbids per-16 groups.
16253/// `input_scale` is validated (F32 scalar) and dropped — see the section header.
16254enum PerExpertSrc {
16255    F32(Vec<f32>),
16256    Nvfp4 {
16257        codes: Vec<u8>,
16258        scales: Vec<u8>,
16259        macro_scale: f32,
16260        input_scale: Option<f32>,
16261    },
16262}
16263
16264fn read_per_expert(
16265    model: &memra_gguf::safetensors::StModel,
16266    name: &str,
16267    out_f: usize,
16268    in_f: usize,
16269    quant: memra_gguf::tensor_contract::QuantConstraint,
16270) -> Res<PerExpertSrc> {
16271    use memra_gguf::tensor_contract::QuantConstraint;
16272    let (info, bytes) = model
16273        .raw(name)
16274        .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16275    match quant {
16276        QuantConstraint::ExactFloat(_) => {
16277            if info.shape != [out_f as u64, in_f as u64] {
16278                return Err(format!("qwen4exp_gpu: {name} shape mismatch").into());
16279            }
16280            Ok(PerExpertSrc::F32(dequant_float(name, info, bytes)?))
16281        }
16282        QuantConstraint::Nvfp4 => {
16283            if info.dtype != "U8"
16284                || in_f % 16 != 0
16285                || info.shape != [out_f as u64, (in_f / 2) as u64]
16286                || bytes.len() != out_f * in_f / 2
16287            {
16288                return Err(format!("qwen4exp_gpu: {name} NVFP4 code shape mismatch").into());
16289            }
16290            let stem = name.strip_suffix(".weight").unwrap_or(name);
16291            let (scale_info, scale_bytes) = model
16292                .raw(&format!("{stem}.weight_scale"))
16293                .ok_or_else(|| format!("qwen4exp_gpu: missing {stem}.weight_scale"))?;
16294            if scale_info.dtype != "F8_E4M3"
16295                || scale_info.shape != [out_f as u64, (in_f / 16) as u64]
16296                || scale_bytes.len() != out_f * in_f / 16
16297            {
16298                return Err(format!("qwen4exp_gpu: {stem}.weight_scale shape mismatch").into());
16299            }
16300            let macro_scale = match model.raw(&format!("{stem}.weight_scale_2")) {
16301                Some((macro_info, macro_bytes))
16302                    if macro_info.dtype == "F32" && macro_bytes.len() == 4 =>
16303                {
16304                    f32::from_le_bytes(macro_bytes.try_into().unwrap())
16305                }
16306                None => 1.0,
16307                _ => return Err(format!("qwen4exp_gpu: {stem}.weight_scale_2 malformed").into()),
16308            };
16309            validate_macro(stem, macro_scale)?;
16310            // input_scale: modelopt's STATIC ACTIVATION scale (= calibrated amax /
16311            // (448*6)) — validated AND consumed since round 4: the W4A4 expert path
16312            // quantizes activations against the per-layer max of these (see
16313            // BankTensorSrc::Nvfp4::act_scale).
16314            let input_scale = match model.raw(&format!("{stem}.input_scale")) {
16315                Some((input_info, input_bytes)) => {
16316                    if input_info.dtype != "F32" || input_bytes.len() != 4 {
16317                        return Err(format!("qwen4exp_gpu: {stem}.input_scale malformed").into());
16318                    }
16319                    let v = f32::from_le_bytes(input_bytes.try_into().unwrap());
16320                    if !(v.is_finite() && v > 0.0) {
16321                        return Err(format!(
16322                            "qwen4exp_gpu: {stem}.input_scale carries a non-finite/non-positive \
16323                             value {v}"
16324                        )
16325                        .into());
16326                    }
16327                    Some(v)
16328                }
16329                None => None,
16330            };
16331            Ok(PerExpertSrc::Nvfp4 {
16332                codes: bytes.to_vec(),
16333                scales: scale_bytes.to_vec(),
16334                macro_scale,
16335                input_scale,
16336            })
16337        }
16338        other => Err(format!("qwen4exp_gpu: per-expert quant {other:?} unsupported").into()),
16339    }
16340}
16341
16342/// Concatenate per-expert sources (expert order 0..E) into one stacked BankTensorSrc.
16343/// Kinds must be uniform across a projection (the census derives them per geometry).
16344fn assemble_per_expert_bank(experts: Vec<PerExpertSrc>) -> Res<BankTensorSrc> {
16345    let mut f32_data: Vec<f32> = Vec::new();
16346    let mut codes: Vec<u8> = Vec::new();
16347    let mut scales: Vec<u8> = Vec::new();
16348    let mut macros: Vec<f32> = Vec::new();
16349    let mut act_scale: Option<f32> = None;
16350    let mut act_scale_complete = true;
16351    let mut kinds = (false, false);
16352    for expert in experts {
16353        match expert {
16354            PerExpertSrc::F32(data) => {
16355                kinds.0 = true;
16356                f32_data.extend_from_slice(&data);
16357            }
16358            PerExpertSrc::Nvfp4 {
16359                codes: c,
16360                scales: s,
16361                macro_scale,
16362                input_scale,
16363            } => {
16364                kinds.1 = true;
16365                codes.extend_from_slice(&c);
16366                scales.extend_from_slice(&s);
16367                macros.push(macro_scale);
16368                match input_scale {
16369                    Some(v) => act_scale = Some(act_scale.map_or(v, |a: f32| a.max(v))),
16370                    None => act_scale_complete = false,
16371                }
16372            }
16373        }
16374    }
16375    match kinds {
16376        (true, false) => Ok(BankTensorSrc::F32(f32_data)),
16377        (false, true) => Ok(BankTensorSrc::Nvfp4 {
16378            codes,
16379            scales,
16380            macros,
16381            act_scale: if act_scale_complete { act_scale } else { None },
16382        }),
16383        _ => Err("qwen4exp_gpu: mixed per-expert kinds within one projection".into()),
16384    }
16385}
16386
16387/// Trunk layer index of a family-keyed requirement (`trunk.layers.{il}. ...`).
16388fn family_layer_index(key: &str) -> Option<u32> {
16389    key.strip_prefix("trunk.layers.")?
16390        .split('.')
16391        .next()?
16392        .parse()
16393        .ok()
16394}
16395
16396/// Walk the pack contract over an HF safetensors dir and materialize the eager arm's
16397/// weight set. The expert dialect is PROBED from the artifact (per-expert names present
16398/// => the NVFP4 mint layout). Fails loudly on any missing name, shape/dtype mismatch, or
16399/// unsupported transform — nothing is skipped silently except the declared MTP/vision
16400/// owners.
16401/// Resolve a layer plan by GLOBAL index: trunk layers [0, n_trunk), then MTP blocks at
16402/// n_trunk + depth (the pack's mtp.layers.* mapping).
16403fn plan_layer_at(plan: &ModelPlan, index: u32) -> Option<&memra_gguf::model_plan::LayerPlan> {
16404    let n_trunk = plan.layers.len() as u32;
16405    if index < n_trunk {
16406        plan.layers.get(index as usize)
16407    } else {
16408        plan.mtp_blocks
16409            .iter()
16410            .find(|block| block.layer.index == index)
16411            .map(|block| &block.layer)
16412    }
16413}
16414
16415pub fn read_checkpoint(dir: &std::path::Path) -> Res<LoadedCheckpoint> {
16416    read_checkpoint_with(dir, LoadOptions::default())
16417}
16418
16419/// `read_checkpoint` with real-checkpoint loader knobs (`LoadOptions`).
16420pub fn read_checkpoint_with(dir: &std::path::Path, opts: LoadOptions) -> Res<LoadedCheckpoint> {
16421    use memra_gguf::model_packs::qwen4_exp::{ExpertDialect, tensor_contract_for};
16422    use memra_gguf::tensor_contract::{TensorMatch, TensorOwner};
16423    let config = std::fs::read_to_string(dir.join("config.json"))?;
16424    let cfg =
16425        memra_gguf::config::ModelConfig::from_hf(&memra_gguf::config::HfConfig::parse(&config));
16426    let pack = memra_gguf::model_packs::for_config(&cfg)
16427        .ok_or("qwen4exp_gpu: no model pack matches this config")?;
16428    if pack.family != "qwen4_exp" {
16429        return Err(format!("qwen4exp_gpu: config resolves to pack {}", pack.family).into());
16430    }
16431    let plan = pack.compile_plan(&cfg)?;
16432    let model = memra_gguf::safetensors::StModel::open(dir)?;
16433    // Dialect probe: layer 0 is always MoE; the mint un-fuses its experts.
16434    let dialect = if model
16435        .raw("model.language_model.layers.0.mlp.experts.0.gate_proj.weight")
16436        .is_some()
16437    {
16438        ExpertDialect::PerExpertModelopt
16439    } else {
16440        ExpertDialect::FusedBanks
16441    };
16442    let contract = tensor_contract_for(&cfg, &plan, dialect)?;
16443
16444    let mut weights = ReferenceWeights::new();
16445    let mut gate_up_banks: std::collections::BTreeMap<u32, FusedTensorPlan> = Default::default();
16446    // Keyed by numeric expert index: the contract iterates the census BTreeMap in
16447    // LEXICOGRAPHIC name order (experts.10 before experts.2), so per-expert rows arrive
16448    // out of numeric order on any E > 9 — assembly must not assume arrival order.
16449    let mut per_expert: std::collections::BTreeMap<
16450        (u32, u8),
16451        std::collections::BTreeMap<
16452            u32,
16453            (
16454                String,
16455                usize,
16456                usize,
16457                memra_gguf::tensor_contract::QuantConstraint,
16458            ),
16459        >,
16460    > = Default::default();
16461    let mut down_banks: std::collections::BTreeMap<u32, FusedTensorPlan> = Default::default();
16462    let mut tables: std::collections::BTreeMap<u32, Vec<u8>> = Default::default();
16463    let n_trunk = plan.layers.len() as u32;
16464
16465    for requirement in &contract.requirements {
16466        match requirement.owner {
16467            // The eager trunk executes neither; vision rows stay contract-declared for
16468            // the census/checkpoint-parity gates but are never materialized here. MTP
16469            // rows materialize when the mtp-spec lane asks (`LoadOptions::load_mtp`).
16470            TensorOwner::Mtp(_) if !opts.load_mtp => continue,
16471            TensorOwner::Vision(_) => continue,
16472            TensorOwner::Global | TensorOwner::Layer(_) | TensorOwner::Mtp(_) => {}
16473        }
16474        // The n-gram shard bank: one semantic tensor, `names` in shard order (pack sorts).
16475        if requirement.match_mode == TensorMatch::All {
16476            let TensorId::Family { key, .. } = &requirement.id else {
16477                return Err("qwen4exp_gpu: unexpected All-mode requirement".into());
16478            };
16479            let layer =
16480                family_layer_index(key).ok_or("qwen4exp_gpu: n-gram bank outside a trunk layer")?;
16481            let mut bytes = Vec::new();
16482            for name in &requirement.names {
16483                let (info, shard) = model
16484                    .raw(name)
16485                    .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16486                if info.dtype != "BF16" || info.shape != requirement.shape {
16487                    return Err(format!("qwen4exp_gpu: {name} shard shape/dtype mismatch").into());
16488                }
16489                bytes.extend_from_slice(shard);
16490            }
16491            tables.insert(layer, bytes);
16492            continue;
16493        }
16494        let name = &requirement.names[0];
16495        // The mint's UNSHARDED table: same Family bank id, one BF16 tensor — read raw
16496        // bytes (a host f32 materialization of 51B rows is not a thing).
16497        if let TensorId::Family { key, .. } = &requirement.id {
16498            if key.ends_with(".ple_embedding.ngram_embedding") {
16499                let layer = family_layer_index(key)
16500                    .ok_or("qwen4exp_gpu: n-gram table outside a trunk layer")?;
16501                let (info, bytes) = model
16502                    .raw(name)
16503                    .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16504                if info.dtype != "BF16" || info.shape != requirement.shape {
16505                    return Err(format!("qwen4exp_gpu: {name} table shape/dtype mismatch").into());
16506                }
16507                tables.insert(layer, bytes.to_vec());
16508                continue;
16509            }
16510        }
16511        // Per-expert projections (PerExpertModelopt).
16512        if let TensorId::Expert {
16513            layer,
16514            expert,
16515            tensor,
16516        } = requirement.id
16517        {
16518            let (out_f, in_f) = (requirement.shape[0] as usize, requirement.shape[1] as usize);
16519            check_bank_header(&model, name)?;
16520            let proj = match tensor {
16521                memra_gguf::tensor_contract::ExpertTensor::Gate => 0u8,
16522                memra_gguf::tensor_contract::ExpertTensor::Up => 1,
16523                memra_gguf::tensor_contract::ExpertTensor::Down => 2,
16524            };
16525            if per_expert
16526                .entry((layer, proj))
16527                .or_default()
16528                .insert(expert, (name.clone(), out_f, in_f, requirement.quant))
16529                .is_some()
16530            {
16531                return Err(format!(
16532                    "qwen4exp_gpu: duplicate per-expert row layer {layer} expert {expert}"
16533                )
16534                .into());
16535            }
16536            continue;
16537        }
16538        // Fused expert banks (FusedBanks) bypass ReferenceWeights (device residency).
16539        if let TensorId::Layer { index, tensor } = requirement.id {
16540            if matches!(
16541                tensor,
16542                LayerTensor::MoeExpertGateUpBank | LayerTensor::MoeExpertDownBank
16543            ) {
16544                let shape = [
16545                    requirement.shape[0] as usize,
16546                    requirement.shape[1] as usize,
16547                    requirement.shape[2] as usize,
16548                ];
16549                check_bank_header(&model, name)?;
16550                let address = FusedTensorPlan {
16551                    name: name.clone(),
16552                    shape,
16553                };
16554                if tensor == LayerTensor::MoeExpertGateUpBank {
16555                    gate_up_banks.insert(index, address);
16556                } else {
16557                    down_banks.insert(index, address);
16558                }
16559                continue;
16560            }
16561        }
16562        let (info, bytes) = model
16563            .raw(name)
16564            .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
16565        if info.shape != requirement.shape {
16566            return Err(format!(
16567                "qwen4exp_gpu: {name} shape {:?} != contract {:?}",
16568                info.shape, requirement.shape
16569            )
16570            .into());
16571        }
16572        if info.dtype == "I64" {
16573            let ints = read_i64(name, info, bytes)?;
16574            let shape: Vec<usize> = info.shape.iter().map(|&d| d as usize).collect();
16575            weights.insert(
16576                requirement.id.clone(),
16577                ReferenceTensor::new_i64(shape, ints)?,
16578            );
16579            continue;
16580        }
16581        let mut data = dequant_float(name, info, bytes)?;
16582        if norm_fold_add_one(name) && !(opts.indexer_norm_raw && indexer_layernorm(name)) {
16583            for value in &mut data {
16584                *value += 1.0;
16585            }
16586        }
16587        let kind = bridge_transform(requirement.transform)?;
16588        let (ne_out, out_bytes) = kind.apply(&mut data, info.ne(), &cfg);
16589        let data: Vec<f32> = out_bytes
16590            .chunks_exact(4)
16591            .map(|chunk| f32::from_le_bytes(chunk.try_into().unwrap()))
16592            .collect();
16593        let mut shape: Vec<usize> = ne_out.iter().rev().map(|&d| d as usize).collect();
16594        // The PLE conv ships [wide, 1, K]; the reference executor (and the depthwise
16595        // kernel) consume the squeezed [wide, K] form — same bytes, GDN-conv precedent.
16596        if name.ends_with("ple.conv1d.weight") && shape.len() == 3 && shape[1] == 1 {
16597            shape = vec![shape[0], shape[2]];
16598        }
16599        // shared_expert_gate ships [1, H]; the reference binds the squeezed [H] row.
16600        if name.ends_with("mlp.shared_expert_gate.weight") && shape.len() == 2 && shape[0] == 1 {
16601            shape = vec![shape[1]];
16602        }
16603        weights.insert(requirement.id.clone(), ReferenceTensor::new(shape, data)?);
16604    }
16605
16606    let mut bank_plans = std::collections::BTreeMap::new();
16607    // FusedBanks: pair the fused gate_up with its down twin (trunk layers AND the MTP
16608    // block, whose layer plan lives at index n_trunk in plan.mtp_blocks). The fused split
16609    // itself happens per layer at read time (`BankPlan::read`).
16610    for (index, gate_up) in gate_up_banks {
16611        let down = down_banks
16612            .remove(&index)
16613            .ok_or_else(|| format!("qwen4exp_gpu: layer {index} has gate_up but no down bank"))?;
16614        let layer_plan = plan_layer_at(&plan, index)
16615            .ok_or_else(|| format!("qwen4exp_gpu: bank at unknown layer index {index}"))?;
16616        let MlpPlan::Moe(moe) = &layer_plan.mlp else {
16617            return Err(format!("qwen4exp_gpu: bank on non-MoE layer {index}").into());
16618        };
16619        bank_plans.insert(
16620            index,
16621            BankPlan {
16622                n_expert: moe.expert_count as usize,
16623                ff: moe.expert_intermediate_size as usize,
16624                hidden: plan.hidden_size as usize,
16625                src: BankPlanSrc::Fused {
16626                    gate_up,
16627                    down,
16628                    // The MTP bank (index >= n_trunk) keeps raw bf16 bytes: it goes DEVICE
16629                    // bf16-resident at build (never f32-expanded — 10 GB vs 5 GB).
16630                    keep_bf16: opts.host_bf16_banks || index >= n_trunk,
16631                },
16632            },
16633        );
16634    }
16635    if !down_banks.is_empty() {
16636        return Err("qwen4exp_gpu: down bank without a gate_up twin".into());
16637    }
16638    // PerExpertModelopt: order the per-projection name lists by expert index. The STACK
16639    // itself is read+concatenated per layer at consume time (`read_per_expert_bank`).
16640    let mut per_layer: std::collections::BTreeMap<u32, [Option<PerExpertPlan>; 3]> =
16641        Default::default();
16642    for ((layer, proj), experts) in per_expert {
16643        let layer_plan = plan_layer_at(&plan, layer)
16644            .ok_or_else(|| format!("qwen4exp_gpu: per-expert rows at unknown layer {layer}"))?;
16645        let MlpPlan::Moe(moe) = &layer_plan.mlp else {
16646            return Err(format!("qwen4exp_gpu: per-expert rows on non-MoE layer {layer}").into());
16647        };
16648        let count = moe.expert_count as usize;
16649        // Contiguity check: BTreeMap<u32, _> iteration is numeric order; every expert
16650        // index 0..E must be present exactly once.
16651        if experts.len() != count || experts.keys().last().copied() != Some(count as u32 - 1) {
16652            return Err(format!(
16653                "qwen4exp_gpu: layer {layer} proj {proj} has {} experts, plan says {count}",
16654                experts.len()
16655            )
16656            .into());
16657        }
16658        // Geometry is uniform across a projection (the census derives it per requirement);
16659        // the contiguity check above pins the map to exactly experts 0..E, so
16660        // `into_values` yields expert order and its index IS the expert id.
16661        let mut names = Vec::with_capacity(count);
16662        let mut geometry: Option<(usize, usize, memra_gguf::tensor_contract::QuantConstraint)> =
16663            None;
16664        for (name, out_f, in_f, quant) in experts.into_values() {
16665            match geometry {
16666                None => geometry = Some((out_f, in_f, quant)),
16667                Some((o, i, q)) if (o, i) == (out_f, in_f) && q == quant => {}
16668                Some((o, i, _)) => {
16669                    return Err(format!(
16670                        "qwen4exp_gpu: layer {layer} proj {proj} mixes expert geometry \
16671                         ({out_f}, {in_f}) vs ({o}, {i}) or quant classes"
16672                    )
16673                    .into());
16674                }
16675            }
16676            names.push(name);
16677        }
16678        let (out_f, in_f, quant) = geometry
16679            .ok_or_else(|| format!("qwen4exp_gpu: layer {layer} proj {proj} has no expert rows"))?;
16680        per_layer.entry(layer).or_default()[proj as usize] = Some(PerExpertPlan {
16681            names,
16682            out_f,
16683            in_f,
16684            quant,
16685        });
16686    }
16687    for (layer, mut projections) in per_layer {
16688        let MlpPlan::Moe(moe) = &plan_layer_at(&plan, layer).expect("checked above").mlp else {
16689            unreachable!("checked above");
16690        };
16691        let take = |slot: &mut Option<PerExpertPlan>, what: &str| -> Res<PerExpertPlan> {
16692            slot.take()
16693                .ok_or_else(|| format!("qwen4exp_gpu: layer {layer} missing {what} experts").into())
16694        };
16695        bank_plans.insert(
16696            layer,
16697            BankPlan {
16698                n_expert: moe.expert_count as usize,
16699                ff: moe.expert_intermediate_size as usize,
16700                hidden: plan.hidden_size as usize,
16701                src: BankPlanSrc::PerExpert {
16702                    gate: take(&mut projections[0], "gate")?,
16703                    up: take(&mut projections[1], "up")?,
16704                    down: take(&mut projections[2], "down")?,
16705                },
16706            },
16707        );
16708    }
16709    Ok(LoadedCheckpoint {
16710        plan,
16711        weights,
16712        model,
16713        bank_plans,
16714        tables,
16715    })
16716}
16717
16718/// One expert-bank projection's byte fingerprint — the loader's memory-ordering gate.
16719///
16720/// A change that only moves WHEN bank bytes are materialized has to leave WHICH bytes
16721/// untouched, and "untouched" is a digest, not an argument. `digest` is sha256 over the
16722/// projection's payload in device-upload order (NVFP4: codes then scales then the
16723/// little-endian macro row; f32/bf16: the raw uploaded bytes), so it pins the expert order,
16724/// the fused gate/up split, and the per-expert stack concatenation at once.
16725pub struct BankFingerprint {
16726    pub layer: u32,
16727    /// "gate" | "up" | "down".
16728    pub projection: &'static str,
16729    /// "f32" | "bf16" | "nvfp4".
16730    pub kind: &'static str,
16731    pub bytes: usize,
16732    /// Lowercase hex sha256.
16733    pub digest: String,
16734}
16735
16736impl LoadedCheckpoint {
16737    /// Read ONE layer's expert bank off the still-open mmap. The streaming seam every bank
16738    /// consumer goes through; the returned source is the caller's to drop.
16739    fn read_bank(&self, index: u32) -> Res<BankSrc> {
16740        self.bank_plans
16741            .get(&index)
16742            .ok_or_else(|| format!("qwen4exp_gpu: no bank source for layer {index}"))?
16743            .read(&self.model)
16744    }
16745
16746    /// Per-projection byte fingerprints for every bank, read one layer at a time (so this
16747    /// costs one layer of host memory, not the artifact). Gate instrument only — see
16748    /// `BankFingerprint`; the tiny-fixture gate compares these against banked goldens.
16749    pub fn bank_fingerprints(&self) -> Res<Vec<BankFingerprint>> {
16750        use sha2::{Digest, Sha256};
16751        let mut out = Vec::new();
16752        for (&layer, plan) in &self.bank_plans {
16753            let bank = plan.read(&self.model)?;
16754            for (projection, src) in [("gate", &bank.gate), ("up", &bank.up), ("down", &bank.down)]
16755            {
16756                let mut hasher = Sha256::new();
16757                let (kind, bytes) = match src {
16758                    // f32 bit patterns little-endian: the exact bytes `htod` uploads.
16759                    BankTensorSrc::F32(data) => {
16760                        for value in data {
16761                            hasher.update(value.to_le_bytes());
16762                        }
16763                        ("f32", data.len() * 4)
16764                    }
16765                    BankTensorSrc::Bf16(raw) => {
16766                        hasher.update(raw);
16767                        ("bf16", raw.len())
16768                    }
16769                    BankTensorSrc::Nvfp4 {
16770                        codes,
16771                        scales,
16772                        macros,
16773                        ..
16774                    } => {
16775                        hasher.update(codes);
16776                        hasher.update(scales);
16777                        for m in macros {
16778                            hasher.update(m.to_le_bytes());
16779                        }
16780                        ("nvfp4", codes.len() + scales.len() + macros.len() * 4)
16781                    }
16782                };
16783                out.push(BankFingerprint {
16784                    layer,
16785                    projection,
16786                    kind,
16787                    bytes,
16788                    digest: hasher
16789                        .finalize()
16790                        .iter()
16791                        .map(|b| format!("{b:02x}"))
16792                        .collect(),
16793                });
16794            }
16795        }
16796        Ok(out)
16797    }
16798
16799    /// Expand banks and n-gram tables into plain `ReferenceWeights` entries so
16800    /// memra-reference can execute the checkpoint. TINY/SIBLING SCALE ONLY — the real
16801    /// artifact's banks/table do not fit host f32; the GPU path never takes this.
16802    pub fn into_reference_weights(mut self) -> Res<ReferenceWeights> {
16803        let bank_plans = std::mem::take(&mut self.bank_plans);
16804        for (index, plan) in bank_plans {
16805            let bank = plan.read(&self.model)?;
16806            let gate = bank_to_f32(&bank.gate, bank.n_expert, bank.ff, bank.hidden)?;
16807            let up = bank_to_f32(&bank.up, bank.n_expert, bank.ff, bank.hidden)?;
16808            let down = bank_to_f32(&bank.down, bank.n_expert, bank.hidden, bank.ff)?;
16809            self.weights.insert(
16810                layer_id(index, LayerTensor::MoeExpertGateBank),
16811                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], gate)?,
16812            );
16813            self.weights.insert(
16814                layer_id(index, LayerTensor::MoeExpertUpBank),
16815                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], up)?,
16816            );
16817            self.weights.insert(
16818                layer_id(index, LayerTensor::MoeExpertDownBank),
16819                ReferenceTensor::new(vec![bank.n_expert, bank.hidden, bank.ff], down)?,
16820            );
16821        }
16822        for (index, bytes) in self.tables {
16823            let ple = self.plan.layers[index as usize]
16824                .ple
16825                .as_ref()
16826                .ok_or("qwen4exp_gpu: table on a non-PLE layer")?;
16827            let head_dim = ple.head_embed_dim as usize;
16828            let table = NgramTable::Bf16(bytes);
16829            let rows = table.rows(head_dim);
16830            let mut data = vec![0.0f32; rows * head_dim];
16831            for row in 0..rows {
16832                table.gather_into(
16833                    row,
16834                    head_dim,
16835                    &mut data[row * head_dim..(row + 1) * head_dim],
16836                );
16837            }
16838            self.weights.insert(
16839                family_id(format!(
16840                    "trunk.layers.{index}.ple.ple_embedding.ngram_embedding"
16841                )),
16842                ReferenceTensor::new(vec![rows, head_dim], data)?,
16843            );
16844        }
16845        Ok(self.weights)
16846    }
16847}
16848
16849impl LoadedCheckpoint {
16850    /// CLONE the float weights and expand ONLY the MTP bank(s) into `ReferenceWeights`
16851    /// entries — the real-checkpoint draft-parity instrument (mtp-spec lane): the host
16852    /// reference twin needs the mtp.* rows + embed/head, and must NOT expand the trunk
16853    /// banks (48 layers of f32 experts do not fit anywhere). Borrowing form so ONE
16854    /// checkpoint read serves both the engine model and the host twin.
16855    pub fn mtp_reference_weights(&self) -> Res<ReferenceWeights> {
16856        let mut weights = self.weights.clone();
16857        let n_trunk = self.plan.layers.len() as u32;
16858        for (index, plan) in &self.bank_plans {
16859            if *index < n_trunk {
16860                continue;
16861            }
16862            let bank = plan.read(&self.model)?;
16863            let gate = bank_to_f32(&bank.gate, bank.n_expert, bank.ff, bank.hidden)?;
16864            let up = bank_to_f32(&bank.up, bank.n_expert, bank.ff, bank.hidden)?;
16865            let down = bank_to_f32(&bank.down, bank.n_expert, bank.hidden, bank.ff)?;
16866            weights.insert(
16867                layer_id(*index, LayerTensor::MoeExpertGateBank),
16868                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], gate)?,
16869            );
16870            weights.insert(
16871                layer_id(*index, LayerTensor::MoeExpertUpBank),
16872                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], up)?,
16873            );
16874            weights.insert(
16875                layer_id(*index, LayerTensor::MoeExpertDownBank),
16876                ReferenceTensor::new(vec![bank.n_expert, bank.hidden, bank.ff], down)?,
16877            );
16878        }
16879        Ok(weights)
16880    }
16881}
16882
16883/// Host-dequant a bank tensor to f32 [E, out, in] (NVFP4 via the pub dsv4 decoder — the
16884/// same value chain the device kernel reproduces).
16885fn bank_to_f32(bank: &BankTensorSrc, n_expert: usize, out_f: usize, in_f: usize) -> Res<Vec<f32>> {
16886    match bank {
16887        BankTensorSrc::F32(data) => Ok(data.clone()),
16888        BankTensorSrc::Bf16(bytes) => Ok(bytes
16889            .chunks_exact(2)
16890            .map(|b| f32::from_bits(u32::from(u16::from_le_bytes([b[0], b[1]])) << 16))
16891            .collect()),
16892        BankTensorSrc::Nvfp4 {
16893            codes,
16894            scales,
16895            macros,
16896            ..
16897        } => {
16898            let mut out = Vec::with_capacity(n_expert * out_f * in_f);
16899            let wbytes = out_f * in_f / 2;
16900            let sbytes = out_f * in_f / 16;
16901            for expert in 0..n_expert {
16902                out.extend(memra_gguf::dsv4::dequant_nvfp4_expert(
16903                    &codes[expert * wbytes..(expert + 1) * wbytes],
16904                    &scales[expert * sbytes..(expert + 1) * sbytes],
16905                    macros[expert],
16906                    out_f,
16907                    in_f,
16908                ));
16909            }
16910            Ok(out)
16911        }
16912    }
16913}
16914
16915impl Qwen4ExpGpu {
16916    /// Load a qwen4_exp checkpoint dir (config.json + safetensors; the BF16 export or the
16917    /// per-expert modelopt NVFP4 mint) through the pack/plan/contract into engine-resident
16918    /// weights: trunk f32 on device, n-gram table host-resident bf16, NVFP4 expert banks
16919    /// as-stored on device.
16920    pub fn load_from_dir(e: &Engine, dir: &std::path::Path) -> Res<Self> {
16921        Self::from_loaded_checkpoint(e, read_checkpoint(dir)?)
16922    }
16923
16924    /// `load_from_dir` with real-checkpoint loader knobs (`LoadOptions`).
16925    pub fn load_from_dir_with(e: &Engine, dir: &std::path::Path, opts: LoadOptions) -> Res<Self> {
16926        Self::from_loaded_checkpoint(e, read_checkpoint_with(dir, opts)?)
16927    }
16928
16929    /// Card-1 draft placement (mtp10): the trunk builds on `e` (card 0) and the MTP
16930    /// draft block — weights, ~5 GB DeviceBf16 expert bank, private lm-head copy — on
16931    /// `draft_e` (card 1). Requires `opts.load_mtp` and P2P between the pair
16932    /// (`tp2_enable_p2p`); the spec loop's wide rows cross per round.
16933    pub fn load_from_dir_dev1(
16934        e: &Engine,
16935        draft_e: &Engine,
16936        dir: &std::path::Path,
16937        opts: LoadOptions,
16938    ) -> Res<Self> {
16939        Self::from_loaded_checkpoint_dual(e, Some(draft_e), read_checkpoint_with(dir, opts)?)
16940    }
16941
16942    /// Consume a `LoadedCheckpoint` into the engine-resident model. Banks and n-gram
16943    /// tables MOVE (the real artifact's 102 GB table must not be cloned).
16944    pub fn from_loaded_checkpoint(e: &Engine, checkpoint: LoadedCheckpoint) -> Res<Self> {
16945        Self::from_loaded_checkpoint_dual(e, None, checkpoint)
16946    }
16947
16948    /// `from_loaded_checkpoint` with the optional card-1 draft engine: the MTP bank
16949    /// (layer index >= n_trunk) uploads to `draft_e` when given; the trunk banks stay
16950    /// on `e` either way.
16951    pub fn from_loaded_checkpoint_dual(
16952        e: &Engine,
16953        draft_e: Option<&Engine>,
16954        checkpoint: LoadedCheckpoint,
16955    ) -> Res<Self> {
16956        let LoadedCheckpoint {
16957            plan,
16958            weights,
16959            model,
16960            bank_plans,
16961            tables,
16962        } = checkpoint;
16963        let mut parts = ExternalParts::default();
16964        let n_trunk = plan.layers.len() as u32;
16965        let upload_half = |e: &Engine, src: BankTensorSrc, device_bf16: bool| -> Res<BankHalf> {
16966            Ok(match src {
16967                BankTensorSrc::F32(data) => BankHalf::F32(e.htod(&data)?),
16968                BankTensorSrc::Nvfp4 {
16969                    codes,
16970                    scales,
16971                    macros,
16972                    ..
16973                } => BankHalf::Nvfp4 {
16974                    codes: e.htod_bytes(&codes)?,
16975                    scales: e.htod_bytes(&scales)?,
16976                    macros_dev: e.htod(&macros)?,
16977                    macros,
16978                },
16979                // Residency was decided at read time (LoadOptions::host_bf16_banks /
16980                // load_mtp): trunk bf16 stays host (gate-mode); the MTP draft bank goes
16981                // device-resident bf16 (the draft decode path reads it in place).
16982                BankTensorSrc::Bf16(bytes) if device_bf16 => {
16983                    BankHalf::DeviceBf16(e.htod_bytes(&bytes)?)
16984                }
16985                BankTensorSrc::Bf16(bytes) => BankHalf::HostBf16(bytes),
16986            })
16987        };
16988        // STREAMED: one layer's bank is read off the mmap, uploaded, and dropped before the
16989        // next is read. Peak host cost is ONE layer (~1.5 GB on the real mint) instead of
16990        // the whole ~72 GB stack, which is what let the real gate load on a 180 GB-RAM box
16991        // (receipt: research/qwen4exp-bringup-20260829/loader/LOADER-STREAM.md).
16992        // `upload_half` moves each projection into the device slice, so the host copy is
16993        // freed at the end of every iteration.
16994        for (index, bank_plan) in bank_plans {
16995            let bank = bank_plan.read(&model)?;
16996            let device_bf16 = index >= n_trunk;
16997            // The MTP bank follows the draft's placement (card 1 when dev1 is armed).
16998            let bank_e = if device_bf16 { draft_e.unwrap_or(e) } else { e };
16999            parts.expert_banks.insert(
17000                index,
17001                ExpertBank {
17002                    gate: upload_half(bank_e, bank.gate, device_bf16)?,
17003                    up: upload_half(bank_e, bank.up, device_bf16)?,
17004                    down: upload_half(bank_e, bank.down, device_bf16)?,
17005                },
17006            );
17007        }
17008        // The mmap has no more readers; the model's weights are device-resident and the
17009        // table below is host-owned bytes.
17010        drop(model);
17011        for (index, bytes) in tables {
17012            parts.ngram_tables.insert(index, NgramTable::Bf16(bytes));
17013        }
17014        Self::from_reference_weights_with(e, draft_e, &plan, &weights, parts)
17015    }
17016}
17017
17018// ==================================== TP2 (perf round 3) ====================================
17019//
17020// Two-card tensor-parallel DECODE over PCIe P2P (no NVLink) — the PROFILE-2 §TP2
17021// projection made real. Structure (the tp2-join-diet playbook, step37 lane):
17022//
17023// - The RESIDUAL IS REPLICATED: both cards hold the wide planes and run the entry embed,
17024//   PLE block, hyper-connection read/write gates, and exit mixer with bit-identical
17025//   weights on bit-identical inputs (replicated deterministic compute — kills every
17026//   broadcast except the two joins below). All replicated device math runs deterministic
17027//   kernels (bf16w matvecs, fused gates); TP2 therefore REQUIRES the bf16 trunk twins.
17028// - SPLIT: GDN by key-head blocks (card d owns orig key heads [d·nk/2, (d+1)·nk/2) and
17029//   the value heads mapping to them — compact per-card head order keeps kh = h % nk_h)),
17030//   QSA by head halves (12/12 query heads, 1/1 KV heads), MoE routed experts by expert-id
17031//   halves (card d owns experts [d·E/2, (d+1)·E/2); top-10 splits ~5/5 on average),
17032//   shared expert by ff halves, lm_head by vocab halves (card 0 reads the resident twin's
17033//   row prefix; card 1 holds the suffix copy).
17034// - JOINS: exactly 2 per layer (mixer out-proj partials, MoE+shared partials), each a
17035//   [hidden] f32 row pushed as a P2P kernel store into the peer's resident staging buffer
17036//   (`q4e_push_f32`, the direct-join mechanism) + one cross-device event wait each way;
17037//   BOTH cards then compute out = partial0 + partial1 in the SAME rank order, so the
17038//   replicated residual stays bit-identical across cards.
17039// - HOST twins unchanged: MoE routing (router GEMV + dtoh on card 0, top-k once, filtered
17040//   selection H2D to both), QSA indexer (card 0 projects + host mask, mask H2D to both),
17041//   PLE n-gram hashing (host, gathered rows H2D to both; the 102 GB table stays host-
17042//   resident and SHARED — the card-1 PLE replica carries no table).
17043// - Decode graphs stay OFF in TP2 (eager issue; the joins are the schedule). Prefill
17044//   stays single-card; the first `decode_step_tp2` migrates the mixer state into
17045//   per-card halves (host bounce, one-time) and the state is TP2-latched from then on.
17046//
17047// EXACTNESS CLASS (the gate statement): TP2 output matches single-card to TOLERANCE, not
17048// bit — the split out-projections sum row halves in a different association than the
17049// full GEMV, the expert combine becomes (Σ card-0 slots) + (Σ card-1 slots) instead of
17050// the slot-sequential chain, and the join add reorders those partial sums. Same
17051// accumulation class as every banked seam; gated by `--tp2-gate` per-row envelope +
17052// argmax vs the single-card twin, plus the greedy-divergence battery.
17053
17054/// Per-card compact GDN half (see the head-map comment on `tp2_gdn_head_map`).
17055struct GdnHalfW {
17056    nk_h: usize,
17057    nv_h: usize,
17058    hk: usize,
17059    hv: usize,
17060    kernel: usize,
17061    gate_activation: GdnGateActivation,
17062    /// Row-stacked [qkv; z; beta; alpha] half twin (proj-stack residency: per-mat
17063    /// launches read row-offset views; the seam launches the whole stack).
17064    proj_b16: CudaSlice<u8>,
17065    out_b16: CudaSlice<u8>, // [hidden, nv_h*hv] (compact column block)
17066    conv_w: CudaSlice<f32>, // [conv_dim_h, K]
17067    a: CudaSlice<f32>,      // [nv_h]
17068    dt: CudaSlice<f32>,     // [nv_h]
17069    norm: CudaSlice<f32>,   // [hv] (replicated)
17070}
17071
17072/// Per-card QSA half: query heads [d*nh_h, (d+1)*nh_h), KV heads [d*nkv_h, ...).
17073struct QsaHalfW {
17074    nh_h: usize,
17075    nkv_h: usize,
17076    hd: usize,
17077    n_rot: usize,
17078    rope_base: f32,
17079    scale: f32,
17080    /// Row-stacked [wq; wk; wv] half twin (proj-stack residency; wq rows are the fused
17081    /// [q|gate] block).
17082    proj_b16: CudaSlice<u8>,
17083    wo_b16: CudaSlice<u8>, // [hidden, nh_h*hd] (compact column block)
17084    q_norm: Option<CudaSlice<f32>>,
17085    k_norm: Option<CudaSlice<f32>>,
17086    /// YaRN tables on THIS half's card (long-context lane); `None` on the shipped config.
17087    yarn: Option<YarnRopeW>,
17088}
17089
17090enum MixerHalfW {
17091    Gdn(GdnHalfW),
17092    Qsa(QsaHalfW),
17093}
17094
17095/// Card-1 NVFP4 expert-bank half (experts [E/2, E), local ids 0..E/2).
17096struct Nvfp4Half {
17097    codes: CudaSlice<u8>,
17098    scales: CudaSlice<u8>,
17099    macros_dev: CudaSlice<f32>,
17100}
17101
17102struct MoeHalfW {
17103    /// Card-1 bank halves (card 0 addresses the resident full bank with original ids).
17104    gate1: Nvfp4Half,
17105    up1: Nvfp4Half,
17106    down1: Nvfp4Half,
17107    /// Shared expert: card 0 reads the resident full twins' ROW PREFIX (gate/up) and its
17108    /// own compact down-column block; card 1 holds suffix/compact copies.
17109    shared_down0: CudaSlice<u8>, // card0 [hidden, sff_h]
17110    shared_down1: CudaSlice<u8>,                // card1 [hidden, sff_h]
17111    shared_input_gate1: Option<CudaSlice<f32>>, // card1 [hidden]
17112    /// Row-stacked [gate_half; up_half] twins (proj-stack residency): card 0 stacks the
17113    /// ROW PREFIXES of the full mats (not contiguous in the resident full stack), card 1
17114    /// its suffix copies. Per-mat launches read row-offset views (0 / sff_h).
17115    shared_gu0_b16: CudaSlice<u8>,
17116    shared_gu1_b16: CudaSlice<u8>,
17117}
17118
17119struct Tp2LayerW {
17120    attn_gate1: GateW,
17121    mlp_gate1: GateW,
17122    mixer0: MixerHalfW,
17123    mixer1: MixerHalfW,
17124    moe: MoeHalfW,
17125    ple1: Option<PleW>,
17126    /// This layer's resolved expert placement — the SAME object that chose which expert
17127    /// rows were gathered into `moe`'s card-1 bank. One source of truth for the upload
17128    /// and for the route split is what keeps a placement from being applied to one and
17129    /// not the other (the failure mode that would read as a model bug, not a config bug).
17130    place: LayerPlacement,
17131}
17132
17133/// The TP2 shard: card-1 replicas + both cards' split halves + join plumbing.
17134pub struct Tp2Shard {
17135    layers: Vec<Tp2LayerW>,
17136    exit_gate1: GateW,
17137    lm_head1: CudaSlice<u8>, // card1 bf16 [vocab - vsplit, hidden]
17138    vsplit: usize,
17139    /// Join staging, TWO buffers per direction alternating by join parity. Two is
17140    /// provably enough: the overwrite of buffer (j+2 mod 2) is transitively ordered
17141    /// after the peer's read at join j (the peer's push at j+1 follows its add at j on
17142    /// its in-order stream, and our wait on that push precedes our overwrite).
17143    stage0: [CudaSlice<f32>; 2], // card0 staging (receives card1 partials)
17144    stage1: [CudaSlice<f32>; 2], // card1 staging (receives card0 partials)
17145    stage0_raw: [u64; 2],
17146    stage1_raw: [u64; 2],
17147    ev0: [cudarc::driver::CudaEvent; 2], // card0 push done, by join parity
17148    ev1: [cudarc::driver::CudaEvent; 2], // card1 push done, by join parity
17149}
17150
17151enum MixerHalfState {
17152    Gdn {
17153        conv: CudaSlice<f32>,  // [pad, conv_dim_h]
17154        state: CudaSlice<f32>, // [nv_h, hv, hk]
17155    },
17156    Qsa {
17157        /// This card's KV half [cap, nkv_h*hd] — f32 or the kvq q8_0/q5_1 byte caches
17158        /// (format follows the single-card store; head halves are 32-block aligned at
17159        /// hd % 32 == 0, so quantized migration gathers BYTES verbatim).
17160        kv: QsaKvStore,
17161    },
17162}
17163
17164struct Tp2LayerState {
17165    m0: MixerHalfState,
17166    m1: MixerHalfState,
17167    ple1: Option<PleState>,
17168}
17169
17170struct Tp2State {
17171    ws1: StepPool,
17172    layers: Vec<Tp2LayerState>,
17173    graphs: Tp2Graphs,
17174    /// TP2-PREFILL join staging (chunk-sized [t*hidden] per direction, two buffers per
17175    /// direction by join parity — the decode stage buffers' proof carries over
17176    /// verbatim). Lazily sized at the first `forward_tp2` chunk; `raw` = the peer's
17177    /// UVA pointers baked for `launch_push`.
17178    pf_stage0: Option<[CudaSlice<f32>; 2]>, // on card0 (receives card1 partials)
17179    pf_stage1: Option<[CudaSlice<f32>; 2]>,
17180    pf_stage0_raw: [u64; 2],
17181    pf_stage1_raw: [u64; 2],
17182    pf_rows: usize,
17183}
17184
17185/// Captured TP2 decode segments per card (the single-card StepGraphs pattern applied
17186/// per rank): `a[d][li]` = attn gate_read + GDN half + join push, `b[d][li]` = join add +
17187/// gate_write + mlp gate_read (+ card1 shared-half prestage), `exit[d]` = exit mixer +
17188/// lm_head half. GDN layers without PLE only; QSA/PLE layers, the router boundary,
17189/// the variable-shape MoE tail, and the MoE join stay eager. Event records/waits sit
17190/// BETWEEN segment launches (not capturable) — same choreography in warm and replay
17191/// modes. The first TP2 decode step runs fully eager to park every slot (allocations
17192/// inside a capture become graph mem nodes); captures are lazy on the second step.
17193#[derive(Default)]
17194struct Tp2Graphs {
17195    warm: bool,
17196    a: [Vec<Option<GraphEntry>>; 2],
17197    b: [Vec<Option<GraphEntry>>; 2],
17198    /// Count-gated MoE tail (routed half + shared add + join push) — fixed launch
17199    /// shapes via the pack blob, so the variable expert split still captures.
17200    c: [Vec<Option<GraphEntry>>; 2],
17201    /// MoE join add + gate_write.
17202    d: [Vec<Option<GraphEntry>>; 2],
17203    exit: [Option<GraphEntry>; 2],
17204}
17205
17206/// Compact value-head order for card `d`: heads h with h % nk in [d*nk_h, (d+1)*nk_h),
17207/// ascending. With nv % nk == 0 this is exactly `(j / nk_h) * nk + (j % nk_h) + d*nk_h`,
17208/// and the compact system stays self-consistent with the kernels' kh = h % nk_h mapping.
17209fn tp2_gdn_head_map(d: usize, nk: usize, nv: usize) -> Vec<usize> {
17210    let nk_h = nk / 2;
17211    let nv_h = nv / 2;
17212    (0..nv_h)
17213        .map(|j| (j / nk_h) * nk + (j % nk_h) + d * nk_h)
17214        .collect()
17215}
17216
17217/// Gather whole rows (row-major [rows, in_f]) into a compact copy.
17218fn gather_rows_host(src: &[f32], in_f: usize, rows: &[usize]) -> Vec<f32> {
17219    let mut out = Vec::with_capacity(rows.len() * in_f);
17220    for &r in rows {
17221        out.extend_from_slice(&src[r * in_f..(r + 1) * in_f]);
17222    }
17223    out
17224}
17225
17226/// Gather column blocks per row (row-major [nrows, ncols]) into a compact copy.
17227fn gather_cols_host(
17228    src: &[f32],
17229    nrows: usize,
17230    ncols: usize,
17231    blocks: &[(usize, usize)],
17232) -> Vec<f32> {
17233    let width: usize = blocks.iter().map(|&(_, l)| l).sum();
17234    let mut out = Vec::with_capacity(nrows * width);
17235    for r in 0..nrows {
17236        for &(start, len) in blocks {
17237            out.extend_from_slice(&src[r * ncols + start..r * ncols + start + len]);
17238        }
17239    }
17240    out
17241}
17242
17243fn need_twin(e: &Engine, data: &[f32], in_f: usize, what: &str) -> Res<CudaSlice<u8>> {
17244    bf16_twin(e, data, in_f)?.ok_or_else(|| {
17245        format!("qwen4exp_gpu tp2: {what} has no exact bf16 twin (in_f {in_f})").into()
17246    })
17247}
17248
17249/// Launch `q4e_push_f32`: UVA store of `n` f32 into the PEER address `dst_raw` on `e`'s
17250/// stream (the direct-join push).
17251fn launch_push(e: &Engine, src: &CudaSlice<f32>, dst_raw: u64, n: usize) -> Res<()> {
17252    let f = e.func("q4e_push_f32");
17253    let cfg = LaunchConfig::for_num_elems(n as u32);
17254    let nl = n as i64;
17255    let stream = e.gpu.stream();
17256    let mut b = stream.launch_builder(&f);
17257    b.arg(src).arg(&dst_raw).arg(&nl);
17258    unsafe {
17259        b.launch(cfg)?;
17260    }
17261    Ok(())
17262}
17263
17264/// Enable bidirectional P2P + pool peer access between two engines (the
17265/// `configure_native_p2p` essentials for the qwen4_exp TP2 pair; pool access makes every
17266/// pooled allocation UVA-addressable from the peer, which is what `q4e_push_f32` needs).
17267pub fn tp2_enable_p2p(e0: &Engine, e1: &Engine) -> Res<()> {
17268    use cudarc::driver::sys;
17269    for (src, dst) in [(e0, e1), (e1, e0)] {
17270        let mut can = 0i32;
17271        unsafe {
17272            sys::cuDeviceCanAccessPeer(&mut can, src.ctx().cu_device(), dst.ctx().cu_device())
17273                .result()?;
17274        }
17275        if can == 0 {
17276            return Err(format!(
17277                "qwen4exp_gpu tp2: dev{} cannot access dev{} over P2P",
17278                src.ctx().ordinal(),
17279                dst.ctx().ordinal()
17280            )
17281            .into());
17282        }
17283        src.ctx().bind_to_thread()?;
17284        let rc = unsafe { sys::cuCtxEnablePeerAccess(dst.ctx().cu_ctx(), 0) };
17285        use cudarc::driver::sys::cudaError_enum as E;
17286        if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
17287            return Err(format!("qwen4exp_gpu tp2: cuCtxEnablePeerAccess failed: {rc:?}").into());
17288        }
17289    }
17290    for (owner, accessor) in [(e0, e1), (e1, e0)] {
17291        let device = cudarc::driver::result::device::get(owner.ctx().ordinal() as i32)?;
17292        let mut pool: sys::CUmemoryPool = std::ptr::null_mut();
17293        unsafe {
17294            sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
17295        }
17296        let desc = sys::CUmemAccessDesc {
17297            location: sys::CUmemLocation {
17298                type_: sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
17299                id: accessor.ctx().ordinal() as i32,
17300            },
17301            flags: sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
17302        };
17303        let rc = unsafe { sys::cuMemPoolSetAccess(pool, &desc, 1) };
17304        if rc != sys::cudaError_enum::CUDA_SUCCESS {
17305            return Err(format!("qwen4exp_gpu tp2: cuMemPoolSetAccess failed: {rc:?}").into());
17306        }
17307    }
17308    Ok(())
17309}
17310
17311/// Build the card-1 replica PLE weight set from the checkpoint's host weights (the
17312/// device parts of `PleW` with an EMPTY table — the 102 GB n-gram table stays host-
17313/// resident on the model and is passed to `ple_block` explicitly).
17314fn build_ple_replica(
17315    e: &Engine,
17316    weights: &ReferenceWeights,
17317    prefix: &str,
17318    ple_plan: &PleEmbeddingPlan,
17319    streams: usize,
17320    hidden: usize,
17321) -> Res<PleW> {
17322    let embed_dim = ple_plan.embed_dim as usize;
17323    let key_proj = expect(weights, &family_id(format!("{prefix}ple.key_proj.weight")))?;
17324    let conv_w = expect(weights, &family_id(format!("{prefix}ple.conv1d.weight")))?;
17325    let norm_slices = |name: &str| -> Res<Vec<CudaSlice<f32>>> {
17326        let t = expect(weights, &family_id(format!("{prefix}ple.{name}.weight")))?;
17327        split_rows(&t.data, streams, hidden, 1)
17328            .into_iter()
17329            .map(|v| e.htod(&v))
17330            .collect::<Result<_, _>>()
17331    };
17332    let ints = |name: &str| -> Res<Vec<i64>> {
17333        let t = expect(
17334            weights,
17335            &family_id(format!("{prefix}ple.ple_embedding.{name}")),
17336        )?;
17337        t.ints
17338            .clone()
17339            .ok_or_else(|| "qwen4exp_gpu: n-gram buffer must be I64".into())
17340    };
17341    Ok(PleW {
17342        plan: *ple_plan,
17343        key_proj: split_rows(&key_proj.data, streams, hidden, embed_dim)
17344            .into_iter()
17345            .map(|v| e.htod(&v))
17346            .collect::<Result<_, _>>()?,
17347        value_proj: upload(
17348            e,
17349            &expect(
17350                weights,
17351                &family_id(format!("{prefix}ple.value_proj.weight")),
17352            )?,
17353        )?,
17354        norm_key: norm_slices("norm_key")?,
17355        norm_query: norm_slices("norm_query")?,
17356        norm_conv: norm_slices("norm_conv")?,
17357        conv_w: split_rows(&conv_w.data, streams, hidden, ple_plan.conv_kernel as usize)
17358            .into_iter()
17359            .map(|v| e.htod(&v))
17360            .collect::<Result<_, _>>()?,
17361        multipliers: ints("layer_multipliers")?,
17362        sizes: ints("ngram_heads_vocab_sizes")?,
17363        offsets: ints("ngram_heads_offsets")?,
17364        table: NgramTable::F32(Vec::new()), // never gathered; the model's table is passed in
17365    })
17366}
17367
17368/// Build one card's compact GDN half from host weights.
17369#[allow(clippy::too_many_arguments)]
17370fn build_gdn_half(
17371    e: &Engine,
17372    weights: &ReferenceWeights,
17373    index: u32,
17374    gdn: &GatedDeltaNetPlan,
17375    hidden: usize,
17376    d: usize,
17377) -> Res<GdnHalfW> {
17378    let (nk, nv) = (gdn.key_heads as usize, gdn.value_heads as usize);
17379    let (hk, hv) = (gdn.key_head_dim as usize, gdn.value_head_dim as usize);
17380    if nk % 2 != 0 || nv % nk != 0 {
17381        return Err(format!(
17382            "qwen4exp_gpu tp2: GDN layer {index} nk {nk} / nv {nv} does not split by key-head halves"
17383        )
17384        .into());
17385    }
17386    let (nk_h, nv_h) = (nk / 2, nv / 2);
17387    let head_map = tp2_gdn_head_map(d, nk, nv);
17388    let qkv = expect(weights, &layer_id(index, LayerTensor::GdnQkv))?;
17389    let z = expect(weights, &layer_id(index, LayerTensor::GdnGate))?;
17390    let beta = expect(weights, &layer_id(index, LayerTensor::GdnBeta))?;
17391    let alpha = expect(weights, &layer_id(index, LayerTensor::GdnAlpha))?;
17392    let out = expect(weights, &layer_id(index, LayerTensor::GdnOutput))?;
17393    let conv_w = expect(weights, &layer_id(index, LayerTensor::GdnConv1d))?;
17394    let a = expect(weights, &layer_id(index, LayerTensor::GdnA))?;
17395    let dt = expect(weights, &layer_id(index, LayerTensor::GdnDtBias))?;
17396    let norm = expect(weights, &layer_id(index, LayerTensor::GdnNorm))?;
17397    let kernel = gdn.conv_kernel as usize;
17398    // Row lists for the fused qkv/conv (q block, k block, v per compact head).
17399    let mut qkv_rows: Vec<usize> = Vec::with_capacity(2 * nk_h * hk + nv_h * hv);
17400    qkv_rows.extend(d * nk_h * hk..(d + 1) * nk_h * hk);
17401    qkv_rows.extend(nk * hk + d * nk_h * hk..nk * hk + (d + 1) * nk_h * hk);
17402    for &hm in &head_map {
17403        qkv_rows.extend(2 * nk * hk + hm * hv..2 * nk * hk + (hm + 1) * hv);
17404    }
17405    let mut z_rows: Vec<usize> = Vec::with_capacity(nv_h * hv);
17406    for &hm in &head_map {
17407        z_rows.extend(hm * hv..(hm + 1) * hv);
17408    }
17409    let out_blocks: Vec<(usize, usize)> = head_map.iter().map(|&hm| (hm * hv, hv)).collect();
17410    let qkv_c = gather_rows_host(&qkv.data, hidden, &qkv_rows);
17411    let z_c = gather_rows_host(&z.data, hidden, &z_rows);
17412    let beta_c = gather_rows_host(&beta.data, hidden, &head_map);
17413    let alpha_c = gather_rows_host(&alpha.data, hidden, &head_map);
17414    let out_c = gather_cols_host(&out.data, hidden, nv * hv, &out_blocks);
17415    let conv_c = gather_rows_host(&conv_w.data, kernel, &qkv_rows);
17416    let a_c: Vec<f32> = head_map.iter().map(|&hm| a.data[hm]).collect();
17417    let dt_c: Vec<f32> = head_map.iter().map(|&hm| dt.data[hm]).collect();
17418    Ok(GdnHalfW {
17419        nk_h,
17420        nv_h,
17421        hk,
17422        hv,
17423        kernel,
17424        gate_activation: gdn.gate_activation,
17425        proj_b16: need_stack_twin(
17426            e,
17427            &[&qkv_c, &z_c, &beta_c, &alpha_c],
17428            hidden,
17429            "tp2 gdn proj half",
17430        )?,
17431        out_b16: need_twin(e, &out_c, nv_h * hv, "tp2 gdn out half")?,
17432        conv_w: e.htod(&conv_c)?,
17433        a: e.htod(&a_c)?,
17434        dt: e.htod(&dt_c)?,
17435        norm: e.htod(&norm.data)?,
17436    })
17437}
17438
17439/// Build one card's QSA half from host weights (query heads d*nh_h.., KV heads d*nkv_h..).
17440#[allow(clippy::too_many_arguments)]
17441fn build_qsa_half(
17442    e: &Engine,
17443    weights: &ReferenceWeights,
17444    index: u32,
17445    attn: &FullAttentionPlan,
17446    hidden: usize,
17447    d: usize,
17448) -> Res<QsaHalfW> {
17449    let nh = attn.query_heads as usize;
17450    let nkv = attn.kv_heads as usize;
17451    let hd = attn.key_head_dim as usize;
17452    if nh % 2 != 0 || nkv % 2 != 0 || nh % nkv != 0 {
17453        return Err(format!(
17454            "qwen4exp_gpu tp2: QSA layer {index} heads {nh}/{nkv} do not split in halves"
17455        )
17456        .into());
17457    }
17458    let (nh_h, nkv_h) = (nh / 2, nkv / 2);
17459    let wq = expect(weights, &layer_id(index, LayerTensor::Query))?;
17460    let wk = expect(weights, &layer_id(index, LayerTensor::Key))?;
17461    let wv = expect(weights, &layer_id(index, LayerTensor::Value))?;
17462    let wo = expect(weights, &layer_id(index, LayerTensor::AttentionOutput))?;
17463    // Fused [q|gate] per head: card d's heads are a contiguous row block.
17464    let q_rows: Vec<usize> = (d * nh_h * 2 * hd..(d + 1) * nh_h * 2 * hd).collect();
17465    let kv_rows: Vec<usize> = (d * nkv_h * hd..(d + 1) * nkv_h * hd).collect();
17466    let wq_c = gather_rows_host(&wq.data, hidden, &q_rows);
17467    let wk_c = gather_rows_host(&wk.data, hidden, &kv_rows);
17468    let wv_c = gather_rows_host(&wv.data, hidden, &kv_rows);
17469    let wo_c = gather_cols_host(&wo.data, hidden, nh * hd, &[(d * nh_h * hd, nh_h * hd)]);
17470    let opt_norm = |tensor: LayerTensor| -> Res<Option<CudaSlice<f32>>> {
17471        match weights.get(&layer_id(index, tensor)) {
17472            Some(t) => Ok(Some(e.htod(&t.data)?)),
17473            None => Ok(None),
17474        }
17475    };
17476    let scale = match attn.scale {
17477        memra_gguf::model_plan::AttentionScale::InverseSqrtKeyDim => 1.0 / (hd as f32).sqrt(),
17478        memra_gguf::model_plan::AttentionScale::Fixed(scale) => scale,
17479    };
17480    Ok(QsaHalfW {
17481        nh_h,
17482        nkv_h,
17483        hd,
17484        n_rot: attn.rope.dimensions as usize,
17485        rope_base: attn.rope.base,
17486        scale,
17487        proj_b16: need_stack_twin(e, &[&wq_c, &wk_c, &wv_c], hidden, "tp2 qsa proj half")?,
17488        wo_b16: need_twin(e, &wo_c, nh_h * hd, "tp2 qsa o half")?,
17489        q_norm: opt_norm(LayerTensor::QueryNorm)?,
17490        k_norm: opt_norm(LayerTensor::KeyNorm)?,
17491        // Device table on THIS half's card; the width check ran at single-card load.
17492        yarn: build_yarn(e, &attn.rope, None, index)?,
17493    })
17494}
17495
17496/// Build the TP2 shard from a loaded checkpoint (host data), before the single-card
17497/// model consumes it. Card 0 gets its compact split copies on `e0`; card 1 gets its
17498/// replicas + halves on `e1`.
17499pub fn build_tp2_shard(e0: &Engine, e1: &Engine, ckpt: &LoadedCheckpoint) -> Res<Tp2Shard> {
17500    let plan = &ckpt.plan;
17501    let weights = &ckpt.weights;
17502    let hidden = plan.hidden_size as usize;
17503    let vocab = plan.vocab_size as usize;
17504    if vocab % 2 != 0 {
17505        return Err("qwen4exp_gpu tp2: odd vocab".into());
17506    }
17507    let mixer_plan = plan
17508        .exit_mixer
17509        .ok_or("qwen4exp_gpu tp2: missing exit mixer")?;
17510    let streams = mixer_plan.streams as usize;
17511    let rank = mixer_plan.bottleneck_rank as usize;
17512    // Expert placement, read ONCE per shard build (MEMRA_Q4E_EP_MAP; unset = the even
17513    // split control arm). Refusals are load-time, before a single byte is uploaded.
17514    let plan_experts = plan
17515        .layers
17516        .iter()
17517        .find_map(|l| match &l.mlp {
17518            MlpPlan::Moe(m) => Some(m.expert_count as usize),
17519            _ => None,
17520        })
17521        .ok_or("qwen4exp_gpu tp2: no MoE layer in the plan")?;
17522    let placement = match Tp2Placement::from_env(plan_experts)? {
17523        Some(p) => p,
17524        None => Tp2Placement::even(plan_experts),
17525    };
17526    println!(
17527        "# tp2-placement\tstrategy={}\tentry_rank={}\texperts={plan_experts}\tsource={}",
17528        placement.strategy(),
17529        placement.entry_rank(),
17530        placement.source()
17531    );
17532    let mut layers = Vec::with_capacity(plan.layers.len());
17533    for layer in &plan.layers {
17534        let prefix = format!("trunk.layers.{}.", layer.index);
17535        let _g1 = e1.gpu.enter_main()?;
17536        let attn_gate1 = load_gate(
17537            e1,
17538            weights,
17539            &prefix,
17540            "attn_hyper_connection.",
17541            streams,
17542            hidden,
17543            rank,
17544            true,
17545        )?;
17546        let mlp_gate1 = load_gate(
17547            e1,
17548            weights,
17549            &prefix,
17550            "mlp_hyper_connection.",
17551            streams,
17552            hidden,
17553            rank,
17554            true,
17555        )?;
17556        let ple1 = match layer.ple.as_ref() {
17557            None => None,
17558            Some(ple_plan) => Some(build_ple_replica(
17559                e1, weights, &prefix, ple_plan, streams, hidden,
17560            )?),
17561        };
17562        drop(_g1);
17563        let (mixer0, mixer1) = match &layer.attention {
17564            AttentionPlan::GatedDeltaNet(gdn) => {
17565                let _g0 = e0.gpu.enter_main()?;
17566                let m0 = MixerHalfW::Gdn(build_gdn_half(e0, weights, layer.index, gdn, hidden, 0)?);
17567                drop(_g0);
17568                let _g1 = e1.gpu.enter_main()?;
17569                let m1 = MixerHalfW::Gdn(build_gdn_half(e1, weights, layer.index, gdn, hidden, 1)?);
17570                (m0, m1)
17571            }
17572            AttentionPlan::Full(attn) => {
17573                let _g0 = e0.gpu.enter_main()?;
17574                let m0 =
17575                    MixerHalfW::Qsa(build_qsa_half(e0, weights, layer.index, attn, hidden, 0)?);
17576                drop(_g0);
17577                let _g1 = e1.gpu.enter_main()?;
17578                let m1 =
17579                    MixerHalfW::Qsa(build_qsa_half(e1, weights, layer.index, attn, hidden, 1)?);
17580                (m0, m1)
17581            }
17582            other => {
17583                return Err(format!("qwen4exp_gpu tp2: unsupported mixer {other:?}").into());
17584            }
17585        };
17586        // MoE: card1 bank halves from the HOST bank sources; NVFP4 required.
17587        let MlpPlan::Moe(moe_plan) = &layer.mlp else {
17588            return Err("qwen4exp_gpu tp2: non-MoE layer".into());
17589        };
17590        let experts = moe_plan.expert_count as usize;
17591        let ff = moe_plan.expert_intermediate_size as usize;
17592        if experts % 2 != 0 {
17593            return Err("qwen4exp_gpu tp2: odd expert count".into());
17594        }
17595        // Streamed like every other bank consumer: this layer's source is read off the
17596        // mmap here and dropped at the end of the iteration. TP2 therefore reads the bank
17597        // bytes TWICE per load (once here for the card-1 gather, once in
17598        // `from_loaded_checkpoint` for card 0) — a load-time disk/page-cache cost, not a
17599        // numerics or steady-state one, and the price of not holding 72 GB of banks on a
17600        // host that has 180 GB total. Single-pass shard+model build is a named follow-up.
17601        let bank = ckpt.read_bank(layer.index)?;
17602        let bank = &bank;
17603        // The layer's expert placement, resolved ONCE here and carried on the shard so
17604        // the route split at decode/prefill cannot disagree with what was uploaded.
17605        let place = placement.layer(layer.index, experts)?;
17606        // Card 1's bank is a GATHER of the placed expert rows in local-slot order, not a
17607        // contiguous suffix slice. For the even control arm `card1` is exactly
17608        // `e_half..experts` ascending, so the gather concatenates the same bytes the old
17609        // slice handed over, in the same order — bit-identical by construction, which is
17610        // what makes "even split = control arm" a statement about bytes and not a hope.
17611        let upper =
17612            |src: &BankTensorSrc, out_f: usize, in_f: usize, what: &str| -> Res<Nvfp4Half> {
17613                let BankTensorSrc::Nvfp4 {
17614                    codes,
17615                    scales,
17616                    macros,
17617                    ..
17618                } = src
17619                else {
17620                    return Err(format!("qwen4exp_gpu tp2: {what} bank is not NVFP4").into());
17621                };
17622                let wbytes = out_f * in_f / 2;
17623                let sbytes = out_f * in_f / 16;
17624                let need_codes = place.card1.len() * wbytes;
17625                let need_scales = place.card1.len() * sbytes;
17626                if codes.len() < experts * wbytes || scales.len() < experts * sbytes {
17627                    return Err(format!(
17628                        "qwen4exp_gpu tp2: {what} bank is {} code / {} scale bytes, too \
17629                         small for {experts} experts x ({wbytes}, {sbytes})",
17630                        codes.len(),
17631                        scales.len()
17632                    )
17633                    .into());
17634                }
17635                let mut gcodes = Vec::with_capacity(need_codes);
17636                let mut gscales = Vec::with_capacity(need_scales);
17637                let mut gmacros = Vec::with_capacity(place.card1.len());
17638                for &eid in &place.card1 {
17639                    let e = eid as usize;
17640                    gcodes.extend_from_slice(&codes[e * wbytes..(e + 1) * wbytes]);
17641                    gscales.extend_from_slice(&scales[e * sbytes..(e + 1) * sbytes]);
17642                    gmacros.push(macros[e]);
17643                }
17644                Ok(Nvfp4Half {
17645                    codes: e1.htod_bytes(&gcodes)?,
17646                    scales: e1.htod_bytes(&gscales)?,
17647                    macros_dev: e1.htod(&gmacros)?,
17648                })
17649            };
17650        let shared = moe_plan
17651            .shared
17652            .as_ref()
17653            .ok_or("qwen4exp_gpu tp2: missing shared expert")?;
17654        let sff = shared.intermediate_size as usize;
17655        if sff % 2 != 0 {
17656            return Err("qwen4exp_gpu tp2: odd shared ff".into());
17657        }
17658        let sffh = sff / 2;
17659        let sh_gate = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpGate))?;
17660        let sh_up = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpUp))?;
17661        let sh_down = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpDown))?;
17662        let sh_ig = if shared.gated {
17663            Some(expect(
17664                weights,
17665                &layer_id(layer.index, LayerTensor::SharedMlpInputGate),
17666            )?)
17667        } else {
17668            None
17669        };
17670        let moe = {
17671            let _g1 = e1.gpu.enter_main()?;
17672            let gate1 = upper(&bank.gate, ff, hidden, "gate")?;
17673            let up1 = upper(&bank.up, ff, hidden, "up")?;
17674            let down1 = upper(&bank.down, hidden, ff, "down")?;
17675            let shared_gu1_b16 = need_stack_twin(
17676                e1,
17677                &[&sh_gate.data[sffh * hidden..], &sh_up.data[sffh * hidden..]],
17678                hidden,
17679                "tp2 shared gate/up (card1)",
17680            )?;
17681            let down1_c = gather_cols_host(&sh_down.data, hidden, sff, &[(sffh, sffh)]);
17682            let shared_down1 = need_twin(e1, &down1_c, sffh, "tp2 shared down (card1)")?;
17683            let shared_input_gate1 = match sh_ig.as_ref() {
17684                Some(t) => Some(e1.htod(&t.data)?),
17685                None => None,
17686            };
17687            drop(_g1);
17688            let _g0 = e0.gpu.enter_main()?;
17689            let down0_c = gather_cols_host(&sh_down.data, hidden, sff, &[(0, sffh)]);
17690            let shared_down0 = need_twin(e0, &down0_c, sffh, "tp2 shared down (card0)")?;
17691            let shared_gu0_b16 = need_stack_twin(
17692                e0,
17693                &[&sh_gate.data[..sffh * hidden], &sh_up.data[..sffh * hidden]],
17694                hidden,
17695                "tp2 shared gate/up (card0)",
17696            )?;
17697            MoeHalfW {
17698                gate1,
17699                up1,
17700                down1,
17701                shared_down0,
17702                shared_down1,
17703                shared_input_gate1,
17704                shared_gu0_b16,
17705                shared_gu1_b16,
17706            }
17707        };
17708        layers.push(Tp2LayerW {
17709            attn_gate1,
17710            mlp_gate1,
17711            mixer0,
17712            mixer1,
17713            moe,
17714            ple1,
17715            place,
17716        });
17717    }
17718    let _g1 = e1.gpu.enter_main()?;
17719    let exit_gate1 = load_gate(
17720        e1,
17721        weights,
17722        "trunk.hyper_connection_mixer.",
17723        "",
17724        streams,
17725        hidden,
17726        rank,
17727        false,
17728    )?;
17729    let vsplit = vocab / 2;
17730    let head = match weights.get(&TensorId::OutputProjection) {
17731        Some(t) => &t.data,
17732        None => &expect(weights, &TensorId::TokenEmbedding)?.data.clone(),
17733    };
17734    let lm_head1 = need_twin(
17735        e1,
17736        &head[vsplit * hidden..],
17737        hidden,
17738        "tp2 lm_head upper half",
17739    )?;
17740    let stage1 = [e1.zeros(hidden)?, e1.zeros(hidden)?];
17741    let ev1 = [e1.ctx().new_event(None)?, e1.ctx().new_event(None)?];
17742    let stage1_raw = {
17743        let s = e1.gpu.stream();
17744        [stage1[0].device_ptr(&s).0, stage1[1].device_ptr(&s).0]
17745    };
17746    drop(_g1);
17747    let _g0 = e0.gpu.enter_main()?;
17748    let stage0 = [e0.zeros(hidden)?, e0.zeros(hidden)?];
17749    let ev0 = [e0.ctx().new_event(None)?, e0.ctx().new_event(None)?];
17750    let stage0_raw = {
17751        let s = e0.gpu.stream();
17752        [stage0[0].device_ptr(&s).0, stage0[1].device_ptr(&s).0]
17753    };
17754    Ok(Tp2Shard {
17755        layers,
17756        exit_gate1,
17757        lm_head1,
17758        vsplit,
17759        stage0,
17760        stage1,
17761        stage0_raw,
17762        stage1_raw,
17763        ev0,
17764        ev1,
17765    })
17766}
17767
17768impl Qwen4ExpGpu {
17769    /// Load a checkpoint dir for TP2: P2P is enabled, the shard is built from the host
17770    /// checkpoint data (before the single-card model consumes it), then the single-card
17771    /// model loads onto `e0` exactly as `load_from_dir_with`.
17772    pub fn load_from_dir_tp2(
17773        e0: &Engine,
17774        e1: &Engine,
17775        dir: &std::path::Path,
17776        opts: LoadOptions,
17777    ) -> Res<(Self, Tp2Shard)> {
17778        tp2_enable_p2p(e0, e1)?;
17779        let checkpoint = read_checkpoint_with(dir, opts)?;
17780        let shard = build_tp2_shard(e0, e1, &checkpoint)?;
17781        let model = Self::from_loaded_checkpoint(e0, checkpoint)?;
17782        Ok((model, shard))
17783    }
17784
17785    /// One-time single-card -> TP2 half-state migration (host bounce; the state is
17786    /// TP2-latched afterwards). Card 0 keeps the host-side indexer raw-key cache and
17787    /// the single-card PLE history (replicated path); mixer device state splits.
17788    fn tp2_migrate(
17789        &self,
17790        e0: &Engine,
17791        e1: &Engine,
17792        _shard: &Tp2Shard,
17793        state: &mut Qwen4ExpState,
17794    ) -> Res<()> {
17795        let cap = state.capacity;
17796        let pos = state.pos;
17797        let mut tlayers = Vec::with_capacity(self.layers.len());
17798        for (layer, lstate) in self.layers.iter().zip(state.layers.iter_mut()) {
17799            let (m0, m1) = match (&layer.mixer, &mut lstate.mixer) {
17800                (
17801                    MixerW::Gdn(gdn),
17802                    MixerState::Gdn {
17803                        conv,
17804                        state: gstate,
17805                    },
17806                ) => {
17807                    let p = &gdn.plan;
17808                    let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
17809                    let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
17810                    let (nk_h, nv_h) = (nk / 2, nv / 2);
17811                    let pad = p.conv_kernel as usize - 1;
17812                    let conv_dim = 2 * nk * hk + nv * hv;
17813                    let conv_dim_h = 2 * nk_h * hk + nv_h * hv;
17814                    let state_host = {
17815                        let _g = e0.gpu.enter_main()?;
17816                        e0.dtoh(gstate)?
17817                    };
17818                    let conv_host = {
17819                        let _g = e0.gpu.enter_main()?;
17820                        e0.dtoh(conv)?
17821                    };
17822                    let mut halves = Vec::with_capacity(2);
17823                    for d in 0..2 {
17824                        let head_map = tp2_gdn_head_map(d, nk, nv);
17825                        let state_c = gather_rows_host(&state_host, hv * hk, &head_map);
17826                        let mut blocks: Vec<(usize, usize)> = vec![
17827                            (d * nk_h * hk, nk_h * hk),
17828                            (nk * hk + d * nk_h * hk, nk_h * hk),
17829                        ];
17830                        blocks.extend(head_map.iter().map(|&hm| (2 * nk * hk + hm * hv, hv)));
17831                        let conv_c = gather_cols_host(&conv_host, pad, conv_dim, &blocks);
17832                        let e = if d == 0 { e0 } else { e1 };
17833                        let _g = e.gpu.enter_main()?;
17834                        let state_dev = e.htod(&state_c)?;
17835                        let conv_dev = e.htod(&conv_c)?;
17836                        debug_assert_eq!(conv_c.len(), pad * conv_dim_h);
17837                        halves.push(MixerHalfState::Gdn {
17838                            conv: conv_dev,
17839                            state: state_dev,
17840                        });
17841                    }
17842                    let m1 = halves.pop().expect("two halves");
17843                    let m0 = halves.pop().expect("two halves");
17844                    (m0, m1)
17845                }
17846                (MixerW::Qsa(qsa), MixerState::Qsa { kv, .. }) => {
17847                    let nkv = qsa.attn.kv_heads as usize;
17848                    let hd = qsa.attn.key_head_dim as usize;
17849                    let nkv_h = nkv / 2;
17850                    let mut halves = Vec::with_capacity(2);
17851                    match &*kv {
17852                        QsaKvStore::F32 { k, v } => {
17853                            let (k_host, v_host) = {
17854                                let _g = e0.gpu.enter_main()?;
17855                                (
17856                                    e0.dtoh_view(&k.slice(0..pos * nkv * hd))?,
17857                                    e0.dtoh_view(&v.slice(0..pos * nkv * hd))?,
17858                                )
17859                            };
17860                            for d in 0..2 {
17861                                let block = [(d * nkv_h * hd, nkv_h * hd)];
17862                                let k_c = gather_cols_host(&k_host, pos, nkv * hd, &block);
17863                                let v_c = gather_cols_host(&v_host, pos, nkv * hd, &block);
17864                                let e = if d == 0 { e0 } else { e1 };
17865                                let _g = e.gpu.enter_main()?;
17866                                let mut k_dev = e.zeros(cap * nkv_h * hd)?;
17867                                let mut v_dev = e.zeros(cap * nkv_h * hd)?;
17868                                if pos > 0 {
17869                                    let mut kv_view = k_dev.slice_mut(0..pos * nkv_h * hd);
17870                                    e.gpu.stream().memcpy_htod(&k_c, &mut kv_view)?;
17871                                    let mut vv_view = v_dev.slice_mut(0..pos * nkv_h * hd);
17872                                    e.gpu.stream().memcpy_htod(&v_c, &mut vv_view)?;
17873                                }
17874                                halves.push(MixerHalfState::Qsa {
17875                                    kv: QsaKvStore::F32 { k: k_dev, v: v_dev },
17876                                });
17877                            }
17878                        }
17879                        QsaKvStore::Q8Q5 { k, v } => {
17880                            // Quantized halves: each head's hd elems are whole q8/q5
17881                            // 32-blocks (hd % 32 == 0 on real geometry), so the half
17882                            // rows gather BYTES verbatim — no dequant, no requant, the
17883                            // half caches are bit-slices of the single-card cache.
17884                            if hd % 32 != 0 {
17885                                return Err("qwen4exp_gpu tp2: quantized halves need \
17886                                            hd % 32 == 0 (byte-aligned head blocks)"
17887                                    .into());
17888                            }
17889                            let (krb, vrb) = (q8_row_bytes(nkv * hd), q5_row_bytes(nkv * hd));
17890                            let (krb_h, vrb_h) =
17891                                (q8_row_bytes(nkv_h * hd), q5_row_bytes(nkv_h * hd));
17892                            let (k_host, v_host) = {
17893                                let _g = e0.gpu.enter_main()?;
17894                                (
17895                                    e0.dtoh_u8_view(&k.slice(0..pos * krb))?,
17896                                    e0.dtoh_u8_view(&v.slice(0..pos * vrb))?,
17897                                )
17898                            };
17899                            for d in 0..2 {
17900                                let mut k_c = Vec::with_capacity(pos * krb_h);
17901                                let mut v_c = Vec::with_capacity(pos * vrb_h);
17902                                for r in 0..pos {
17903                                    let ko = r * krb + d * krb_h;
17904                                    k_c.extend_from_slice(&k_host[ko..ko + krb_h]);
17905                                    let vo = r * vrb + d * vrb_h;
17906                                    v_c.extend_from_slice(&v_host[vo..vo + vrb_h]);
17907                                }
17908                                let e = if d == 0 { e0 } else { e1 };
17909                                let _g = e.gpu.enter_main()?;
17910                                let mut k_dev = e.alloc_u8(cap * krb_h)?;
17911                                let mut v_dev = e.alloc_u8(cap * vrb_h)?;
17912                                if pos > 0 {
17913                                    let mut kv_view = k_dev.slice_mut(0..pos * krb_h);
17914                                    e.gpu.stream().memcpy_htod(&k_c, &mut kv_view)?;
17915                                    let mut vv_view = v_dev.slice_mut(0..pos * vrb_h);
17916                                    e.gpu.stream().memcpy_htod(&v_c, &mut vv_view)?;
17917                                }
17918                                halves.push(MixerHalfState::Qsa {
17919                                    kv: QsaKvStore::Q8Q5 { k: k_dev, v: v_dev },
17920                                });
17921                            }
17922                        }
17923                    }
17924                    // The single-card cache is DEAD after migration (a TP2-touched
17925                    // state refuses single-card forwards), and at long-context
17926                    // capacities it is the largest allocation on card 0 — stub it.
17927                    {
17928                        let _g = e0.gpu.enter_main()?;
17929                        *kv = match &*kv {
17930                            QsaKvStore::F32 { .. } => QsaKvStore::F32 {
17931                                k: e0.zeros(1)?,
17932                                v: e0.zeros(1)?,
17933                            },
17934                            QsaKvStore::Q8Q5 { .. } => QsaKvStore::Q8Q5 {
17935                                k: e0.alloc_u8(34)?,
17936                                v: e0.alloc_u8(24)?,
17937                            },
17938                        };
17939                    }
17940                    let m1 = halves.pop().expect("two halves");
17941                    let m0 = halves.pop().expect("two halves");
17942                    (m0, m1)
17943                }
17944                _ => return Err("qwen4exp_gpu tp2: layer/state mixer mismatch".into()),
17945            };
17946            // Card-1 PLE history replica (replicated path): copy card0's normed-conv rows.
17947            let ple1 = match lstate.ple.as_ref() {
17948                None => None,
17949                Some(ps) => {
17950                    let mut conv_hist = Vec::with_capacity(ps.conv_hist.len());
17951                    for h in &ps.conv_hist {
17952                        let host = {
17953                            let _g = e0.gpu.enter_main()?;
17954                            e0.dtoh(h)?
17955                        };
17956                        let _g = e1.gpu.enter_main()?;
17957                        conv_hist.push(e1.htod(&host)?);
17958                    }
17959                    Some(PleState {
17960                        conv_hist,
17961                        ngram_ids: Vec::new(),
17962                        ngram_history: Vec::new(),
17963                        ngram_last_eos: -1,
17964                    })
17965                }
17966            };
17967            tlayers.push(Tp2LayerState { m0, m1, ple1 });
17968        }
17969        state.tp2 = Some(Tp2State {
17970            ws1: StepPool::default(),
17971            layers: tlayers,
17972            graphs: Tp2Graphs::default(),
17973            pf_stage0: None,
17974            pf_stage1: None,
17975            pf_stage0_raw: [0; 2],
17976            pf_stage1_raw: [0; 2],
17977            pf_rows: 0,
17978        });
17979        Ok(())
17980    }
17981
17982    /// Per-card GDN split half (t-generic — TP2 prefill runs chunk-sized t):
17983    /// projections, conv, scan, norm+gate, and the compact out-projection PARTIAL
17984    /// (joined by the driver). Mirrors `gdn_forward`.
17985    #[allow(clippy::too_many_arguments)]
17986    fn gdn_forward_half(
17987        &self,
17988        e: &Engine,
17989        ws: &mut StepPool,
17990        eps: f32,
17991        h: &GdnHalfW,
17992        mixed: &CudaSlice<f32>,
17993        hstate: &mut MixerHalfState,
17994        t: usize,
17995    ) -> Res<CudaSlice<f32>> {
17996        let MixerHalfState::Gdn { conv, state } = hstate else {
17997            return Err("qwen4exp_gpu tp2: GDN half bound to non-GDN state".into());
17998        };
17999        let hidden = self.hidden;
18000        let (nk, nv, hk, hv) = (h.nk_h, h.nv_h, h.hk, h.hv);
18001        let kernel = h.kernel;
18002        let pad = kernel - 1;
18003        let conv_dim = 2 * nk * hk + nv * hv;
18004        let mut qkv = ws.take_f32(e, "gdn.qkv", t * conv_dim, 0)?;
18005        let mut z = ws.take_f32(e, "gdn.z", t * nv * hv, 0)?;
18006        let mut beta_raw = ws.take_f32(e, "gdn.beta", t * nv, 0)?;
18007        let mut alpha = ws.take_f32(e, "gdn.alpha", t * nv, 0)?;
18008        // Proj stack (round 4): the 4 half projections in ONE launch (bit-identical
18009        // rows; OFF arm = row-offset views of the same required stack). t == 1 only
18010        // (decode form); chunks run the per-mat row-offset launches.
18011        if t == 1 && proj_stack_on() {
18012            launch_qmatvec_bf16w_multi4(
18013                e,
18014                &h.proj_b16,
18015                mixed,
18016                &[
18017                    (&qkv, conv_dim),
18018                    (&z, nv * hv),
18019                    (&beta_raw, nv),
18020                    (&alpha, nv),
18021                ],
18022                hidden,
18023            )?;
18024        } else {
18025            launch_qmatvec_bf16w_off(e, &h.proj_b16, 0, mixed, &mut qkv, hidden, conv_dim, t)?;
18026            launch_qmatvec_bf16w_off(e, &h.proj_b16, conv_dim, mixed, &mut z, hidden, nv * hv, t)?;
18027            launch_qmatvec_bf16w_off(
18028                e,
18029                &h.proj_b16,
18030                conv_dim + nv * hv,
18031                mixed,
18032                &mut beta_raw,
18033                hidden,
18034                nv,
18035                t,
18036            )?;
18037            launch_qmatvec_bf16w_off(
18038                e,
18039                &h.proj_b16,
18040                conv_dim + nv * hv + nv,
18041                mixed,
18042                &mut alpha,
18043                hidden,
18044                nv,
18045                t,
18046            )?;
18047        }
18048        let mut g_log = ws.take_f32(e, "gdn.glog", t * nv, 0)?;
18049        e.gdn_glog_v(&alpha.slice(0..t * nv), &h.dt, &h.a, &mut g_log, nv, t)?;
18050        ws.put_f32("gdn.alpha", alpha);
18051        let mut conv_out = ws.take_f32(e, "gdn.conv_out", t * conv_dim, 0)?;
18052        launch_dwconv(
18053            e,
18054            &qkv,
18055            conv,
18056            &h.conv_w,
18057            &mut conv_out,
18058            t,
18059            pad,
18060            conv_dim,
18061            kernel,
18062            1,
18063            1,
18064        )?;
18065        let mut o = ws.take_f32(e, "gdn.o", t * nv * hv, 0)?;
18066        let scale = 1.0 / (hk as f32).sqrt();
18067        if t == 1 && gdn_step_on() && hk % 32 == 0 && hk <= 1024 {
18068            launch_gdn_scan_step(
18069                e, &conv_out, &g_log, &beta_raw, state, &mut o, nk, nv, hk, hv, scale, eps,
18070            )?;
18071        } else {
18072            launch_gdn_scan(
18073                e, &conv_out, &g_log, &beta_raw, state, &mut o, nk, nv, hk, hv, t, scale, eps,
18074            )?;
18075        }
18076        ws.put_f32("gdn.conv_out", conv_out);
18077        // conv history <- last `pad` raw qkv rows (zeros keep their place when t < pad).
18078        if t >= pad {
18079            e.copy_range_into(conv, 0, &qkv, (t - pad) * conv_dim, pad * conv_dim)?;
18080        } else {
18081            let keep = pad - t;
18082            let mut tmp = ws.take_f32(e, "gdn.tmp", keep * conv_dim, 0)?;
18083            e.copy_range_into(&mut tmp, 0, conv, t * conv_dim, keep * conv_dim)?;
18084            e.copy_range_into(conv, 0, &tmp, 0, keep * conv_dim)?;
18085            e.copy_range_into(conv, keep * conv_dim, &qkv, 0, t * conv_dim)?;
18086            ws.put_f32("gdn.tmp", tmp);
18087        }
18088        ws.put_f32("gdn.qkv", qkv);
18089        ws.put_f32("gdn.beta", beta_raw);
18090        ws.put_f32("gdn.glog", g_log);
18091        let mut gated = ws.take_f32(e, "gdn.gated", t * nv * hv, 0)?;
18092        match h.gate_activation {
18093            GdnGateActivation::Sigmoid if gdn_fuse_on() => {
18094                launch_rms_sigmul(e, &o, &h.norm, &z, &mut gated, hv, t * nv, eps)?;
18095            }
18096            GdnGateActivation::Sigmoid => {
18097                let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
18098                e.rms_norm(&o, &h.norm, &mut normed, hv, t * nv, eps)?;
18099                let mut sg = ws.take_f32(e, "gdn.sg", t * nv * hv, 0)?;
18100                e.sigmoid(&z, &mut sg, t * nv * hv)?;
18101                e.mul(&normed, &sg, &mut gated, t * nv * hv)?;
18102                ws.put_f32("gdn.sg", sg);
18103                ws.put_f32("gdn.normed", normed);
18104            }
18105            GdnGateActivation::Silu => {
18106                let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
18107                e.rms_norm(&o, &h.norm, &mut normed, hv, t * nv, eps)?;
18108                e.silu_mul(&z, &normed, &mut gated, t * nv * hv)?;
18109                ws.put_f32("gdn.normed", normed);
18110            }
18111        }
18112        let mut partial = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
18113        launch_qmatvec_bf16w(
18114            e,
18115            &h.out_b16,
18116            &gated,
18117            &mut partial,
18118            nv * hv,
18119            hidden,
18120            t,
18121            1,
18122            0,
18123            0,
18124            nv * hv,
18125            0,
18126        )?;
18127        ws.put_f32("gdn.gated", gated);
18128        ws.put_f32("gdn.z", z);
18129        ws.put_f32("gdn.o", o);
18130        Ok(partial)
18131    }
18132
18133    /// Per-card QSA split half UP TO the cache append (t-generic — TP2 prefill runs
18134    /// chunk-sized t); returns (q, gate) for the post-selection half
18135    /// (`qsa_half_attend`). The indexer selection is built once on card 0.
18136    #[allow(clippy::too_many_arguments)]
18137    fn qsa_half_proj(
18138        &self,
18139        e: &Engine,
18140        ws: &mut StepPool,
18141        eps: f32,
18142        h: &QsaHalfW,
18143        mixed: &CudaSlice<f32>,
18144        hstate: &mut MixerHalfState,
18145        base_pos: usize,
18146        t: usize,
18147    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
18148        let MixerHalfState::Qsa { kv } = hstate else {
18149            return Err("qwen4exp_gpu tp2: QSA half bound to non-QSA state".into());
18150        };
18151        let hidden = self.hidden;
18152        let (nh, nkv, hd) = (h.nh_h, h.nkv_h, h.hd);
18153        let mut q_fused = ws.take_f32(e, "qsa.qf", t * 2 * nh * hd, 0)?;
18154        let mut k_new = ws.take_f32(e, "qsa.k", t * nkv * hd, 0)?;
18155        let mut v_new = ws.take_f32(e, "qsa.v", t * nkv * hd, 0)?;
18156        // Proj stack (round 4): wq/wk/wv halves in ONE launch (bit-identical rows; OFF
18157        // arm = row-offset views of the same required stack). t == 1 only (the multi4
18158        // kernel is a decode form); chunks run the per-mat row-offset launches.
18159        if t == 1 && proj_stack_on() {
18160            launch_qmatvec_bf16w_multi4(
18161                e,
18162                &h.proj_b16,
18163                mixed,
18164                &[
18165                    (&q_fused, 2 * nh * hd),
18166                    (&k_new, nkv * hd),
18167                    (&v_new, nkv * hd),
18168                ],
18169                hidden,
18170            )?;
18171        } else {
18172            launch_qmatvec_bf16w_off(
18173                e,
18174                &h.proj_b16,
18175                0,
18176                mixed,
18177                &mut q_fused,
18178                hidden,
18179                2 * nh * hd,
18180                t,
18181            )?;
18182            launch_qmatvec_bf16w_off(
18183                e,
18184                &h.proj_b16,
18185                2 * nh * hd,
18186                mixed,
18187                &mut k_new,
18188                hidden,
18189                nkv * hd,
18190                t,
18191            )?;
18192            launch_qmatvec_bf16w_off(
18193                e,
18194                &h.proj_b16,
18195                2 * nh * hd + nkv * hd,
18196                mixed,
18197                &mut v_new,
18198                hidden,
18199                nkv * hd,
18200                t,
18201            )?;
18202        }
18203        let mut q = ws.take_f32(e, "qsa.q", t * nh * hd, 0)?;
18204        let mut gate = ws.take_f32(e, "qsa.gate", t * nh * hd, 0)?;
18205        e.q_gate_split(&q_fused, &mut q, &mut gate, hd, nh, t)?;
18206        ws.put_f32("qsa.qf", q_fused);
18207        let mut q = if let Some(norm) = h.q_norm.as_ref() {
18208            let mut dst = ws.take_f32(e, "qsa.qn", t * nh * hd, 0)?;
18209            e.rms_norm(&q, norm, &mut dst, hd, t * nh, eps)?;
18210            ws.put_f32("qsa.q", q);
18211            dst
18212        } else {
18213            q
18214        };
18215        let mut k_new = if let Some(norm) = h.k_norm.as_ref() {
18216            let mut dst = ws.take_f32(e, "qsa.kn", t * nkv * hd, 0)?;
18217            e.rms_norm(&k_new, norm, &mut dst, hd, t * nkv, eps)?;
18218            ws.put_f32("qsa.k", k_new);
18219            dst
18220        } else {
18221            k_new
18222        };
18223        let positions: Vec<i32> = (0..t).map(|i| (base_pos + i) as i32).collect();
18224        let pos_dev = ws.take_i32(e, "qsa.pos", &positions, 0)?;
18225        if let Some(yarn) = h.yarn.as_ref() {
18226            e.rope_neox_ffm(
18227                &mut q,
18228                &pos_dev,
18229                hd,
18230                h.n_rot,
18231                nh,
18232                t,
18233                h.rope_base,
18234                1.0,
18235                &yarn.ff,
18236                yarn.mscale,
18237            )?;
18238            e.rope_neox_ffm(
18239                &mut k_new,
18240                &pos_dev,
18241                hd,
18242                h.n_rot,
18243                nkv,
18244                t,
18245                h.rope_base,
18246                1.0,
18247                &yarn.ff,
18248                yarn.mscale,
18249            )?;
18250        } else {
18251            e.rope_neox(&mut q, &pos_dev, hd, h.n_rot, nh, t, h.rope_base, 1.0)?;
18252            e.rope_neox(&mut k_new, &pos_dev, hd, h.n_rot, nkv, t, h.rope_base, 1.0)?;
18253        }
18254        ws.put_i32("qsa.pos", pos_dev);
18255        match kv {
18256            QsaKvStore::F32 { k, v } => {
18257                e.copy_range_into(k, base_pos * nkv * hd, &k_new, 0, t * nkv * hd)?;
18258                e.copy_range_into(v, base_pos * nkv * hd, &v_new, 0, t * nkv * hd)?;
18259            }
18260            QsaKvStore::Q8Q5 { k, v } => {
18261                launch_q4e_kv_append(e, &k_new, &v_new, k, v, base_pos, t, nkv * hd)?;
18262            }
18263        }
18264        ws.put_f32(
18265            if h.k_norm.is_some() {
18266                "qsa.kn"
18267            } else {
18268                "qsa.k"
18269            },
18270            k_new,
18271        );
18272        ws.put_f32("qsa.v", v_new);
18273        Ok((q, gate))
18274    }
18275
18276    /// Post-selection QSA half: BLOCK-LIST SDPA over this card's KV half (bit-identical
18277    /// to the historical masked form on the same selection — the fixture-longatt /
18278    /// arm-0f pedigree — and the only form the quantized halves have), sigmoid gate,
18279    /// and the compact out-projection PARTIAL. t-generic.
18280    #[allow(clippy::too_many_arguments)]
18281    fn qsa_half_attend(
18282        &self,
18283        e: &Engine,
18284        ws: &mut StepPool,
18285        h: &QsaHalfW,
18286        hstate: &MixerHalfState,
18287        q: CudaSlice<f32>,
18288        gate: CudaSlice<f32>,
18289        pos_dev: &CudaSlice<i32>,
18290        meta_dev: &CudaSlice<i32>,
18291        max_count: usize,
18292        t: usize,
18293        t_kv: usize,
18294    ) -> Res<CudaSlice<f32>> {
18295        let MixerHalfState::Qsa { kv } = hstate else {
18296            return Err("qwen4exp_gpu tp2: QSA half bound to non-QSA state".into());
18297        };
18298        let hidden = self.hidden;
18299        let (nh, nkv, hd) = (h.nh_h, h.nkv_h, h.hd);
18300        let mut attended = ws.take_f32(e, "qsa.att", t * nh * hd, 0)?;
18301        match kv {
18302            QsaKvStore::F32 { k, v } => {
18303                let k_view = k.slice(0..t_kv * nkv * hd);
18304                let v_view = v.slice(0..t_kv * nkv * hd);
18305                launch_sdpa_blocklist(
18306                    e,
18307                    &q,
18308                    &k_view,
18309                    &v_view,
18310                    &mut attended,
18311                    pos_dev,
18312                    meta_dev,
18313                    hd,
18314                    nh,
18315                    nkv,
18316                    t,
18317                    max_count,
18318                    h.scale,
18319                )?;
18320            }
18321            QsaKvStore::Q8Q5 { k, v } => {
18322                launch_q4e_sdpa_blocklist_q8q5(
18323                    e,
18324                    &q,
18325                    k,
18326                    v,
18327                    &mut attended,
18328                    pos_dev,
18329                    meta_dev,
18330                    hd,
18331                    nh,
18332                    nkv,
18333                    t,
18334                    max_count,
18335                    h.scale,
18336                )?;
18337            }
18338        }
18339        ws.put_f32(
18340            if h.q_norm.is_some() {
18341                "qsa.qn"
18342            } else {
18343                "qsa.q"
18344            },
18345            q,
18346        );
18347        let mut sg = ws.take_f32(e, "qsa.sg", t * nh * hd, 0)?;
18348        e.sigmoid(&gate, &mut sg, t * nh * hd)?;
18349        let mut gated = ws.take_f32(e, "qsa.gated", t * nh * hd, 0)?;
18350        e.mul(&attended, &sg, &mut gated, t * nh * hd)?;
18351        let mut partial = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
18352        launch_qmatvec_bf16w(
18353            e,
18354            &h.wo_b16,
18355            &gated,
18356            &mut partial,
18357            nh * hd,
18358            hidden,
18359            t,
18360            1,
18361            0,
18362            0,
18363            nh * hd,
18364            0,
18365        )?;
18366        ws.put_f32("qsa.sg", sg);
18367        ws.put_f32("qsa.gated", gated);
18368        ws.put_f32("qsa.att", attended);
18369        ws.put_f32("qsa.gate", gate);
18370        Ok(partial)
18371    }
18372
18373    /// The QSA indexer host twin factored for TP2 (runs on card 0's projection; the mask
18374    /// bytes feed BOTH cards' masked SDPA halves).
18375    // dead_code: bring-up scaffolding the in-flight qwen4exp lanes still call; not deleted in
18376    // the clippy-zero lane (bit-neutral by construction).
18377    #[allow(dead_code)]
18378    #[allow(clippy::too_many_arguments)]
18379    fn qsa_indexer_mask(
18380        &self,
18381        e: &Engine,
18382        ws: &mut StepPool,
18383        qsa: &QsaW,
18384        eps: f32,
18385        mixed: &CudaSlice<f32>,
18386        raw_keys: &mut IdxRawCache,
18387        pooled_keys: &mut Vec<f32>,
18388        base_pos: usize,
18389    ) -> Res<Vec<u8>> {
18390        let overlay = &qsa.overlay;
18391        let idx_dim = overlay.head_dim as usize;
18392        let qk_width = (overlay.query_heads as usize + overlay.kv_heads as usize) * idx_dim;
18393        let hidden = self.hidden;
18394        let mut idx_proj = ws.take_f32(e, "qsa.idxp", qk_width, 0)?;
18395        e.linear_device_into(mixed, &qsa.idx_proj, &mut idx_proj, 1, hidden, qk_width)?;
18396        let rows = e.dtoh_view(&idx_proj.slice(0..qk_width))?;
18397        ws.put_f32("qsa.idxp", idx_proj);
18398        raw_keys.append_rows_f32(
18399            &rows[overlay.query_heads as usize * idx_dim..qk_width],
18400            1,
18401            idx_dim,
18402        );
18403        indexer_mask_rows(
18404            overlay,
18405            qsa.attn.rope.base,
18406            qsa.yarn.as_ref().map(|y| (y.ff_host.as_slice(), y.mscale)),
18407            eps,
18408            &qsa.idx_q_norm,
18409            &qsa.idx_k_norm,
18410            &rows,
18411            raw_keys,
18412            pooled_keys,
18413            base_pos,
18414            1,
18415            base_pos + 1,
18416            0,
18417        )
18418    }
18419
18420    /// Shared-expert half on one card: gate/up rows (card 0 = the resident full twins'
18421    /// row prefix; card 1 = its suffix copies), silu, compact down columns. Returns the
18422    /// down PARTIAL and the (replicated-deterministic) input-gate scalar buffer.
18423    #[allow(clippy::too_many_arguments)]
18424    fn tp2_shared_half(
18425        &self,
18426        e: &Engine,
18427        ws: &mut StepPool,
18428        gu_b16: &CudaSlice<u8>,
18429        down_b16: &CudaSlice<u8>,
18430        input_gate: Option<&CudaSlice<f32>>,
18431        mixed: &CudaSlice<f32>,
18432        sffh: usize,
18433        t: usize,
18434    ) -> Res<(CudaSlice<f32>, Option<CudaSlice<f32>>)> {
18435        let hidden = self.hidden;
18436        let mut sh_gate = ws.take_f32(e, "moe.sh_gate", t * sffh, 0)?;
18437        let mut sh_up = ws.take_f32(e, "moe.sh_up", t * sffh, 0)?;
18438        // Proj stack (round 4): shared gate/up halves in ONE launch (bit-identical rows;
18439        // OFF arm = row-offset views of the same required stack). t == 1 only.
18440        if t == 1 && proj_stack_on() {
18441            launch_qmatvec_bf16w_multi4(
18442                e,
18443                gu_b16,
18444                mixed,
18445                &[(&sh_gate, sffh), (&sh_up, sffh)],
18446                hidden,
18447            )?;
18448        } else {
18449            launch_qmatvec_bf16w_off(e, gu_b16, 0, mixed, &mut sh_gate, hidden, sffh, t)?;
18450            launch_qmatvec_bf16w_off(e, gu_b16, sffh, mixed, &mut sh_up, hidden, sffh, t)?;
18451        }
18452        let mut act = ws.take_f32(e, "moe.sh_act", t * sffh, 0)?;
18453        e.silu_mul(&sh_gate, &sh_up, &mut act, t * sffh)?;
18454        let mut shared = ws.take_f32(e, "moe.sh_down", t * hidden, 0)?;
18455        launch_qmatvec_bf16w(
18456            e,
18457            down_b16,
18458            &act,
18459            &mut shared,
18460            sffh,
18461            hidden,
18462            t,
18463            1,
18464            0,
18465            0,
18466            sffh,
18467            0,
18468        )?;
18469        let g = match input_gate {
18470            Some(w) => {
18471                let mut g = ws.take_f32(e, "moe.g", t, 0)?;
18472                e.sigmoid_dot_rows_into(mixed, w, &mut g, hidden, t)?;
18473                Some(g)
18474            }
18475            None => None,
18476        };
18477        ws.put_f32("moe.sh_gate", sh_gate);
18478        ws.put_f32("moe.sh_up", sh_up);
18479        ws.put_f32("moe.sh_act", act);
18480        Ok((shared, g))
18481    }
18482}
18483
18484impl Qwen4ExpGpu {
18485    /// One TP2 decode step (t == 1, eager issue — decode graphs stay off in TP2; the
18486    /// joins are the schedule). Prefill stays single-card; the first call migrates the
18487    /// state (one-way latch). Requires the bf16-trunk + fused-gate seams ON (replicated
18488    /// compute must be deterministic-kernel-only).
18489    pub fn decode_step_tp2(
18490        &self,
18491        e0: &Engine,
18492        e1: &Engine,
18493        shard: &Tp2Shard,
18494        token: u32,
18495        state: &mut Qwen4ExpState,
18496    ) -> Res<Vec<f32>> {
18497        if !trunk_bf16_on() || !hc_fused_gate_on() {
18498            return Err(
18499                "qwen4exp_gpu tp2: requires set_trunk_bf16(true) and set_hc_fused_gate(true) \
18500                 (replicated compute must run deterministic kernels)"
18501                    .into(),
18502            );
18503        }
18504        if state.pos + 1 > state.capacity {
18505            return Err("qwen4exp_gpu: state capacity exceeded".into());
18506        }
18507        if state.tp2.is_none() {
18508            self.tp2_migrate(e0, e1, shard, state)?;
18509            state.graphs = StepGraphs::default();
18510        }
18511        let hidden = self.hidden;
18512        let vocab = self.vocab;
18513        let vsplit = shard.vsplit;
18514        let base_pos = state.pos;
18515        let reserve = state.reserve;
18516        state.tokens.push(token);
18517        let Qwen4ExpState {
18518            ref tokens,
18519            ws: ref mut ws0,
18520            ref mut tp2,
18521            layers: ref mut lstates,
18522            ..
18523        } = *state;
18524        let Tp2State {
18525            ws1,
18526            layers: tlayers,
18527            graphs: tgraphs,
18528            ..
18529        } = tp2.as_mut().expect("migrated above");
18530        // Slot RESERVE unit: reserve-derived, NOT capacity — a long-context TP2 state
18531        // (1M rows) must not reserve capacity-sized plane slots (~10 GB each).
18532        let cap = reserve.max(1);
18533
18534        // Entry: one embed row, H2D to both cards' plane slots (replicated planes).
18535        let token_us = token as usize;
18536        if token_us >= vocab {
18537            return Err(format!("qwen4exp_gpu: token {token_us} out of range").into());
18538        }
18539        let embedded = &self.embed_host[token_us * hidden..(token_us + 1) * hidden];
18540        let mut planes1: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
18541        let ptrs1 = {
18542            let _g = e1.gpu.enter_main()?;
18543            let embedded_dev = ws1.take_f32_h2d(e1, "entry.embed", embedded, cap * hidden)?;
18544            for s in 0..self.streams {
18545                let mut plane = ws1.take_f32(e1, PLANE_SLOTS[s], hidden, cap * hidden)?;
18546                e1.copy_into(&mut plane, 0, &embedded_dev, hidden)?;
18547                planes1.push(plane);
18548            }
18549            ws1.put_f32("entry.embed", embedded_dev);
18550            let ptr_vals: Vec<u64> = {
18551                let stream = e1.gpu.stream();
18552                planes1.iter().map(|p| p.device_ptr(&stream).0).collect()
18553            };
18554            ws1.take_u64_h2d(e1, "hc.ptrs", &ptr_vals, 0)?
18555        };
18556        let mut planes0: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
18557        let ptrs0 = {
18558            let _g = e0.gpu.enter_main()?;
18559            let embedded_dev = ws0.take_f32_h2d(e0, "entry.embed", embedded, cap * hidden)?;
18560            for s in 0..self.streams {
18561                let mut plane = ws0.take_f32(e0, PLANE_SLOTS[s], hidden, cap * hidden)?;
18562                e0.copy_into(&mut plane, 0, &embedded_dev, hidden)?;
18563                planes0.push(plane);
18564            }
18565            ws0.put_f32("entry.embed", embedded_dev);
18566            let ptr_vals: Vec<u64> = {
18567                let stream = e0.gpu.stream();
18568                planes0.iter().map(|p| p.device_ptr(&stream).0).collect()
18569            };
18570            ws0.take_u64_h2d(e0, "hc.ptrs", &ptr_vals, 0)?
18571        };
18572
18573        // Segment-graph mode (the single-card StepGraphs pattern per rank): first TP2
18574        // step runs fully eager to park every slot; captures are lazy on the next step.
18575        let use_graphs = decode_graphs_on() && step_ws_on();
18576        let graphs_live = use_graphs && tgraphs.warm;
18577        if use_graphs && !tgraphs.warm {
18578            tgraphs.warm = true;
18579        }
18580        if graphs_live && tgraphs.a[0].len() != self.layers.len() {
18581            for d in 0..2 {
18582                tgraphs.a[d] = (0..self.layers.len()).map(|_| None).collect();
18583                tgraphs.b[d] = (0..self.layers.len()).map(|_| None).collect();
18584                tgraphs.c[d] = (0..self.layers.len()).map(|_| None).collect();
18585                tgraphs.d[d] = (0..self.layers.len()).map(|_| None).collect();
18586            }
18587        }
18588        for (li, layer) in self.layers.iter().enumerate() {
18589            let lstate = &mut lstates[li];
18590            let tw = &shard.layers[li];
18591            let ts = &mut tlayers[li];
18592            let eps_a = layer.eps_attn;
18593            let eps_m = layer.eps_mlp;
18594            let moe = &layer.moe;
18595            let ff = moe.plan.expert_intermediate_size as usize;
18596            let experts = moe.plan.expert_count as usize;
18597            let selected = moe.plan.experts_per_token as usize;
18598            let sff = moe
18599                .plan
18600                .shared
18601                .as_ref()
18602                .map(|s| s.intermediate_size as usize)
18603                .unwrap_or(0);
18604            let sffh = sff / 2;
18605
18606            // ---- phase 1: attn gate + mixer half + join push (parity 0), per card ----
18607            match (&layer.mixer, &tw.mixer0, &tw.mixer1) {
18608                (MixerW::Gdn(_), MixerHalfW::Gdn(h0), MixerHalfW::Gdn(h1)) => {
18609                    {
18610                        let _g = e1.gpu.enter_main()?;
18611                        if let (Some(ple1), Some(ps1)) = (tw.ple1.as_ref(), ts.ple1.as_mut()) {
18612                            let table = &layer.ple.as_ref().expect("ple plan").table;
18613                            self.ple_block(
18614                                e1,
18615                                layer,
18616                                ple1,
18617                                table,
18618                                ps1,
18619                                &mut planes1,
18620                                tokens,
18621                                1,
18622                                false,
18623                                None,
18624                            )?;
18625                        }
18626                        if graphs_live && layer.ple.is_none() {
18627                            if tgraphs.a[1][li].is_none() {
18628                                tgraphs.a[1][li] =
18629                                    Some(e1.capture_graph_retained_nowarm(|eng| {
18630                                        self.tp2_gdn_seg_a(
18631                                            eng,
18632                                            ws1,
18633                                            &ptrs1,
18634                                            &tw.attn_gate1,
18635                                            h1,
18636                                            &mut ts.m1,
18637                                            &planes1,
18638                                            eps_a,
18639                                            shard.stage0_raw[0],
18640                                        )
18641                                    })?);
18642                            }
18643                            tgraphs.a[1][li].as_ref().unwrap().0.launch()?;
18644                        } else {
18645                            self.tp2_gdn_seg_a(
18646                                e1,
18647                                ws1,
18648                                &ptrs1,
18649                                &tw.attn_gate1,
18650                                h1,
18651                                &mut ts.m1,
18652                                &planes1,
18653                                eps_a,
18654                                shard.stage0_raw[0],
18655                            )?;
18656                        }
18657                        shard.ev1[0].record(&e1.gpu.stream())?;
18658                    }
18659                    {
18660                        let _g = e0.gpu.enter_main()?;
18661                        if let (Some(ple), Some(ps)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
18662                            self.ple_block(
18663                                e0,
18664                                layer,
18665                                ple,
18666                                &ple.table,
18667                                ps,
18668                                &mut planes0,
18669                                tokens,
18670                                1,
18671                                false,
18672                                None,
18673                            )?;
18674                        }
18675                        if graphs_live && layer.ple.is_none() {
18676                            if tgraphs.a[0][li].is_none() {
18677                                tgraphs.a[0][li] =
18678                                    Some(e0.capture_graph_retained_nowarm(|eng| {
18679                                        self.tp2_gdn_seg_a(
18680                                            eng,
18681                                            ws0,
18682                                            &ptrs0,
18683                                            &layer.attn_gate,
18684                                            h0,
18685                                            &mut ts.m0,
18686                                            &planes0,
18687                                            eps_a,
18688                                            shard.stage1_raw[0],
18689                                        )
18690                                    })?);
18691                            }
18692                            tgraphs.a[0][li].as_ref().unwrap().0.launch()?;
18693                        } else {
18694                            self.tp2_gdn_seg_a(
18695                                e0,
18696                                ws0,
18697                                &ptrs0,
18698                                &layer.attn_gate,
18699                                h0,
18700                                &mut ts.m0,
18701                                &planes0,
18702                                eps_a,
18703                                shard.stage1_raw[0],
18704                            )?;
18705                        }
18706                        shard.ev0[0].record(&e0.gpu.stream())?;
18707                    }
18708                }
18709                (MixerW::Qsa(qsa), MixerHalfW::Qsa(h0), MixerHalfW::Qsa(h1)) => {
18710                    // QSA stays eager: the indexer selection and the per-step t_kv
18711                    // launch shape are not capturable (single-card precedent).
18712                    let (q1, g1, inj1) = {
18713                        let _g = e1.gpu.enter_main()?;
18714                        let (mixed1, inj1) = self.gate_read(
18715                            e1,
18716                            ws1,
18717                            &ptrs1,
18718                            &tw.attn_gate1,
18719                            &planes1,
18720                            1,
18721                            eps_a,
18722                            false,
18723                        )?;
18724                        let (q1, g1) = self
18725                            .qsa_half_proj(e1, ws1, eps_a, h1, &mixed1, &mut ts.m1, base_pos, 1)?;
18726                        ws1.put_f32("hc.mixed", mixed1);
18727                        (q1, g1, inj1)
18728                    };
18729                    // The selection runs ONCE on card 0 (the single-card machinery:
18730                    // idxcache device raw cache, device scorer, audit twin) and its
18731                    // position lists feed BOTH cards' block-list halves — bit-identical
18732                    // to the historical masked form on the same selection.
18733                    let (sels, q0, g0, inj0) = {
18734                        let _g = e0.gpu.enter_main()?;
18735                        let (mixed0, inj0) = self.gate_read(
18736                            e0,
18737                            ws0,
18738                            &ptrs0,
18739                            &layer.attn_gate,
18740                            &planes0,
18741                            1,
18742                            eps_a,
18743                            false,
18744                        )?;
18745                        let (q0, g0) = self
18746                            .qsa_half_proj(e0, ws0, eps_a, h0, &mixed0, &mut ts.m0, base_pos, 1)?;
18747                        let MixerState::Qsa {
18748                            raw_keys,
18749                            pooled_keys,
18750                            pooled_dev,
18751                            pooled_dev_rows,
18752                            raw_dev,
18753                            raw_dev_rows,
18754                            idx_audit,
18755                            ..
18756                        } = &mut lstate.mixer
18757                        else {
18758                            return Err("qwen4exp_gpu tp2: QSA layer without raw-key cache".into());
18759                        };
18760                        let sels = self.qsa_update_select(
18761                            e0,
18762                            ws0,
18763                            qsa,
18764                            eps_a,
18765                            &mixed0,
18766                            raw_keys,
18767                            pooled_keys,
18768                            pooled_dev,
18769                            pooled_dev_rows,
18770                            raw_dev,
18771                            raw_dev_rows,
18772                            idx_audit.as_mut(),
18773                            base_pos,
18774                            1,
18775                            0,
18776                            false,
18777                        )?;
18778                        ws0.put_f32("hc.mixed", mixed0);
18779                        (sels, q0, g0, inj0)
18780                    };
18781                    let t_kv = base_pos + 1;
18782                    let block_size = qsa.overlay.block_size as usize;
18783                    let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
18784                    {
18785                        let _g = e1.gpu.enter_main()?;
18786                        let pos_dev = ws1.take_i32(e1, "qsa.selpos", &pos_flat, 0)?;
18787                        let meta_dev = ws1.take_i32(e1, "qsa.selmeta", &meta, 0)?;
18788                        let p1 = self.qsa_half_attend(
18789                            e1, ws1, h1, &ts.m1, q1, g1, &pos_dev, &meta_dev, max_count, 1, t_kv,
18790                        )?;
18791                        ws1.put_i32("qsa.selpos", pos_dev);
18792                        ws1.put_i32("qsa.selmeta", meta_dev);
18793                        launch_push(e1, &p1, shard.stage0_raw[0], hidden)?;
18794                        ws1.put_f32("mixer.out", p1);
18795                        put_inject(ws1, inj1);
18796                        shard.ev1[0].record(&e1.gpu.stream())?;
18797                    }
18798                    {
18799                        let _g = e0.gpu.enter_main()?;
18800                        let pos_dev = ws0.take_i32(e0, "qsa.selpos", &pos_flat, 0)?;
18801                        let meta_dev = ws0.take_i32(e0, "qsa.selmeta", &meta, 0)?;
18802                        let p0 = self.qsa_half_attend(
18803                            e0, ws0, h0, &ts.m0, q0, g0, &pos_dev, &meta_dev, max_count, 1, t_kv,
18804                        )?;
18805                        ws0.put_i32("qsa.selpos", pos_dev);
18806                        ws0.put_i32("qsa.selmeta", meta_dev);
18807                        launch_push(e0, &p0, shard.stage1_raw[0], hidden)?;
18808                        ws0.put_f32("mixer.out", p0);
18809                        put_inject(ws0, inj0);
18810                        shard.ev0[0].record(&e0.gpu.stream())?;
18811                    }
18812                }
18813                _ => return Err("qwen4exp_gpu tp2: mixer/shard shape mismatch".into()),
18814            }
18815            {
18816                let _g = e0.gpu.enter_main()?;
18817                e0.gpu.stream().wait(&shard.ev1[0])?;
18818            }
18819            {
18820                let _g = e1.gpu.enter_main()?;
18821                e1.gpu.stream().wait(&shard.ev0[0])?;
18822            }
18823
18824            // ---- phase 2: join add + write + mlp gate (+ card1 shared prestage) ----
18825            {
18826                let _g = e1.gpu.enter_main()?;
18827                if graphs_live {
18828                    if tgraphs.b[1][li].is_none() {
18829                        tgraphs.b[1][li] = Some(e1.capture_graph_retained_nowarm(|eng| {
18830                            self.tp2_seg_b(
18831                                eng,
18832                                ws1,
18833                                &ptrs1,
18834                                &tw.mlp_gate1,
18835                                &mut planes1,
18836                                &shard.stage1[0],
18837                                false,
18838                                eps_m,
18839                                Some((
18840                                    &tw.moe.shared_gu1_b16,
18841                                    &tw.moe.shared_down1,
18842                                    tw.moe.shared_input_gate1.as_ref(),
18843                                    sffh,
18844                                )),
18845                            )
18846                        })?);
18847                    }
18848                    tgraphs.b[1][li].as_ref().unwrap().0.launch()?;
18849                } else {
18850                    self.tp2_seg_b(
18851                        e1,
18852                        ws1,
18853                        &ptrs1,
18854                        &tw.mlp_gate1,
18855                        &mut planes1,
18856                        &shard.stage1[0],
18857                        false,
18858                        eps_m,
18859                        Some((
18860                            &tw.moe.shared_gu1_b16,
18861                            &tw.moe.shared_down1,
18862                            tw.moe.shared_input_gate1.as_ref(),
18863                            sffh,
18864                        )),
18865                    )?;
18866                }
18867            }
18868            {
18869                let _g = e0.gpu.enter_main()?;
18870                if graphs_live {
18871                    if tgraphs.b[0][li].is_none() {
18872                        tgraphs.b[0][li] = Some(e0.capture_graph_retained_nowarm(|eng| {
18873                            self.tp2_seg_b(
18874                                eng,
18875                                ws0,
18876                                &ptrs0,
18877                                &layer.mlp_gate,
18878                                &mut planes0,
18879                                &shard.stage0[0],
18880                                true,
18881                                eps_m,
18882                                None,
18883                            )
18884                        })?);
18885                    }
18886                    tgraphs.b[0][li].as_ref().unwrap().0.launch()?;
18887                } else {
18888                    self.tp2_seg_b(
18889                        e0,
18890                        ws0,
18891                        &ptrs0,
18892                        &layer.mlp_gate,
18893                        &mut planes0,
18894                        &shard.stage0[0],
18895                        true,
18896                        eps_m,
18897                        None,
18898                    )?;
18899                }
18900            }
18901
18902            // ---- phase 3: router host boundary + count-gated MoE tail (graphable via the
18903            // pack blob: fixed launch shapes, live slot count on device) + join (parity 1) ----
18904            let route = {
18905                let _g = e0.gpu.enter_main()?;
18906                let mixed0 = ws0.take_f32(e0, "hc.mixed", hidden, 0)?;
18907                let mut router_out = ws0.take_f32(e0, "moe.router", experts, 0)?;
18908                let none: Option<CudaSlice<u8>> = None;
18909                let rb = if router_bf16_on() {
18910                    &moe.router_b16
18911                } else {
18912                    &none
18913                };
18914                linear_trunk_into(
18915                    e0,
18916                    &moe.router,
18917                    rb,
18918                    &mixed0,
18919                    &mut router_out,
18920                    1,
18921                    hidden,
18922                    experts,
18923                )?;
18924                let logits = e0.dtoh_view(&router_out.slice(0..experts))?;
18925                ws0.put_f32("moe.router", router_out);
18926                ws0.put_f32("hc.mixed", mixed0);
18927                host_route_softmax_topk(&logits, selected)
18928            };
18929            // Split by PLACEMENT (even split when no map is loaded — then rank() is
18930            // `expert >= experts/2` and local() is `expert - experts/2`, i.e. exactly the
18931            // arithmetic this site used before the seam existed).
18932            let place = &tw.place;
18933            let mut sel0: Vec<i32> = Vec::with_capacity(selected);
18934            let mut w0: Vec<f32> = Vec::with_capacity(selected);
18935            let mut sel1: Vec<i32> = Vec::with_capacity(selected);
18936            let mut w1: Vec<f32> = Vec::with_capacity(selected);
18937            for &(expert, weight) in &route {
18938                if place.rank(expert) == 0 {
18939                    sel0.push(place.local(expert) as i32);
18940                    w0.push(weight);
18941                } else {
18942                    sel1.push(place.local(expert) as i32);
18943                    w1.push(weight);
18944                }
18945            }
18946            {
18947                // Route trace + per-rank engagement, in the decode shape (t == 1). The
18948                // trace rides the readback the host router twin already did.
18949                let r0: Vec<Vec<(usize, f32)>> = vec![
18950                    sel0.iter()
18951                        .zip(&w0)
18952                        .map(|(&s, &w)| (s as usize, w))
18953                        .collect(),
18954                ];
18955                let r1: Vec<Vec<(usize, f32)>> = vec![
18956                    sel1.iter()
18957                        .zip(&w1)
18958                        .map(|(&s, &w)| (s as usize, w))
18959                        .collect(),
18960                ];
18961                tp2_count_split(&r0, &r1);
18962                trace_moe_routes(layer.index, 1, std::slice::from_ref(&route));
18963            }
18964            match tp2_gate_red()? {
18965                Tp2GateRed::None => {}
18966                // Drop the peer's routed contribution entirely.
18967                Tp2GateRed::SkipPeerMoe => {
18968                    sel1.clear();
18969                    w1.clear();
18970                }
18971                // Send peer-owned experts to card 0's bank at their peer LOCAL slot: the
18972                // plausible off-by-remap bug — right magnitudes, wrong experts.
18973                Tp2GateRed::PeerLocalIds => {
18974                    sel0.extend(sel1.drain(..));
18975                    w0.extend(w1.drain(..));
18976                }
18977                Tp2GateRed::ReverseePeerWeights => w1.reverse(),
18978            }
18979            let max_sel = selected;
18980            {
18981                let _g = e1.gpu.enter_main()?;
18982                ws1.upsert_u8(e1, "moe.pack", &tp2_pack_bytes(&sel1, &w1, max_sel), 0)?;
18983                if graphs_live {
18984                    if tgraphs.c[1][li].is_none() {
18985                        tgraphs.c[1][li] = Some(e1.capture_graph_retained_nowarm(|eng| {
18986                            self.tp2_seg_c(
18987                                eng,
18988                                ws1,
18989                                (
18990                                    &tw.moe.gate1.codes,
18991                                    &tw.moe.gate1.scales,
18992                                    &tw.moe.gate1.macros_dev,
18993                                ),
18994                                (
18995                                    &tw.moe.up1.codes,
18996                                    &tw.moe.up1.scales,
18997                                    &tw.moe.up1.macros_dev,
18998                                ),
18999                                (
19000                                    &tw.moe.down1.codes,
19001                                    &tw.moe.down1.scales,
19002                                    &tw.moe.down1.macros_dev,
19003                                ),
19004                                ff,
19005                                max_sel,
19006                                None,
19007                                tw.moe.shared_input_gate1.is_some(),
19008                                shard.stage0_raw[1],
19009                            )
19010                        })?);
19011                    }
19012                    tgraphs.c[1][li].as_ref().unwrap().0.launch()?;
19013                } else {
19014                    self.tp2_seg_c(
19015                        e1,
19016                        ws1,
19017                        (
19018                            &tw.moe.gate1.codes,
19019                            &tw.moe.gate1.scales,
19020                            &tw.moe.gate1.macros_dev,
19021                        ),
19022                        (
19023                            &tw.moe.up1.codes,
19024                            &tw.moe.up1.scales,
19025                            &tw.moe.up1.macros_dev,
19026                        ),
19027                        (
19028                            &tw.moe.down1.codes,
19029                            &tw.moe.down1.scales,
19030                            &tw.moe.down1.macros_dev,
19031                        ),
19032                        ff,
19033                        max_sel,
19034                        None,
19035                        tw.moe.shared_input_gate1.is_some(),
19036                        shard.stage0_raw[1],
19037                    )?;
19038                }
19039                shard.ev1[1].record(&e1.gpu.stream())?;
19040            }
19041            {
19042                let _g = e0.gpu.enter_main()?;
19043                let (
19044                    BankHalf::Nvfp4 {
19045                        codes: gc,
19046                        scales: gs,
19047                        macros_dev: gm,
19048                        ..
19049                    },
19050                    BankHalf::Nvfp4 {
19051                        codes: uc,
19052                        scales: us,
19053                        macros_dev: um,
19054                        ..
19055                    },
19056                    BankHalf::Nvfp4 {
19057                        codes: dc,
19058                        scales: ds,
19059                        macros_dev: dm,
19060                        ..
19061                    },
19062                ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
19063                else {
19064                    return Err("qwen4exp_gpu tp2: card0 bank is not NVFP4".into());
19065                };
19066                ws0.upsert_u8(e0, "moe.pack", &tp2_pack_bytes(&sel0, &w0, max_sel), 0)?;
19067                if graphs_live {
19068                    if tgraphs.c[0][li].is_none() {
19069                        tgraphs.c[0][li] = Some(e0.capture_graph_retained_nowarm(|eng| {
19070                            self.tp2_seg_c(
19071                                eng,
19072                                ws0,
19073                                (gc, gs, gm),
19074                                (uc, us, um),
19075                                (dc, ds, dm),
19076                                ff,
19077                                max_sel,
19078                                Some((
19079                                    &tw.moe.shared_gu0_b16,
19080                                    &tw.moe.shared_down0,
19081                                    moe.shared_input_gate.as_ref(),
19082                                    sffh,
19083                                )),
19084                                false,
19085                                shard.stage1_raw[1],
19086                            )
19087                        })?);
19088                    }
19089                    tgraphs.c[0][li].as_ref().unwrap().0.launch()?;
19090                } else {
19091                    self.tp2_seg_c(
19092                        e0,
19093                        ws0,
19094                        (gc, gs, gm),
19095                        (uc, us, um),
19096                        (dc, ds, dm),
19097                        ff,
19098                        max_sel,
19099                        Some((
19100                            &tw.moe.shared_gu0_b16,
19101                            &tw.moe.shared_down0,
19102                            moe.shared_input_gate.as_ref(),
19103                            sffh,
19104                        )),
19105                        false,
19106                        shard.stage1_raw[1],
19107                    )?;
19108                }
19109                shard.ev0[1].record(&e0.gpu.stream())?;
19110            }
19111            {
19112                let _g = e1.gpu.enter_main()?;
19113                e1.gpu.stream().wait(&shard.ev0[1])?;
19114                if graphs_live {
19115                    if tgraphs.d[1][li].is_none() {
19116                        tgraphs.d[1][li] = Some(e1.capture_graph_retained_nowarm(|eng| {
19117                            self.tp2_seg_d(eng, ws1, &ptrs1, &mut planes1, &shard.stage1[1], false)
19118                        })?);
19119                    }
19120                    tgraphs.d[1][li].as_ref().unwrap().0.launch()?;
19121                } else {
19122                    self.tp2_seg_d(e1, ws1, &ptrs1, &mut planes1, &shard.stage1[1], false)?;
19123                }
19124            }
19125            {
19126                let _g = e0.gpu.enter_main()?;
19127                e0.gpu.stream().wait(&shard.ev1[1])?;
19128                if graphs_live {
19129                    if tgraphs.d[0][li].is_none() {
19130                        tgraphs.d[0][li] = Some(e0.capture_graph_retained_nowarm(|eng| {
19131                            self.tp2_seg_d(eng, ws0, &ptrs0, &mut planes0, &shard.stage0[1], true)
19132                        })?);
19133                    }
19134                    tgraphs.d[0][li].as_ref().unwrap().0.launch()?;
19135                } else {
19136                    self.tp2_seg_d(e0, ws0, &ptrs0, &mut planes0, &shard.stage0[1], true)?;
19137                }
19138            }
19139        }
19140
19141        // Exit mixer (replicated) + vocab-split lm_head, per card (graphable).
19142        {
19143            let _g = e1.gpu.enter_main()?;
19144            if graphs_live {
19145                if tgraphs.exit[1].is_none() {
19146                    tgraphs.exit[1] = Some(e1.capture_graph_retained_nowarm(|eng| {
19147                        self.tp2_seg_exit(
19148                            eng,
19149                            ws1,
19150                            &ptrs1,
19151                            &shard.exit_gate1,
19152                            &planes1,
19153                            &shard.lm_head1,
19154                            vocab - vsplit,
19155                            1, // decode_step_tp2 is t == 1 by construction
19156                        )
19157                    })?);
19158                }
19159                tgraphs.exit[1].as_ref().unwrap().0.launch()?;
19160            } else {
19161                self.tp2_seg_exit(
19162                    e1,
19163                    ws1,
19164                    &ptrs1,
19165                    &shard.exit_gate1,
19166                    &planes1,
19167                    &shard.lm_head1,
19168                    vocab - vsplit,
19169                    1, // decode_step_tp2 is t == 1 by construction
19170                )?;
19171            }
19172        }
19173        {
19174            let _g = e0.gpu.enter_main()?;
19175            let head0 = self
19176                .output_b16
19177                .as_ref()
19178                .ok_or("qwen4exp_gpu tp2: lm_head has no bf16 twin")?;
19179            if graphs_live {
19180                if tgraphs.exit[0].is_none() {
19181                    tgraphs.exit[0] = Some(e0.capture_graph_retained_nowarm(|eng| {
19182                        self.tp2_seg_exit(
19183                            eng,
19184                            ws0,
19185                            &ptrs0,
19186                            &self.exit_mixer,
19187                            &planes0,
19188                            head0,
19189                            vsplit,
19190                            1, // decode_step_tp2 is t == 1 by construction
19191                        )
19192                    })?);
19193                }
19194                tgraphs.exit[0].as_ref().unwrap().0.launch()?;
19195            } else {
19196                self.tp2_seg_exit(
19197                    e0,
19198                    ws0,
19199                    &ptrs0,
19200                    &self.exit_mixer,
19201                    &planes0,
19202                    head0,
19203                    vsplit,
19204                    1, // decode_step_tp2 is t == 1 by construction
19205                )?;
19206            }
19207        }
19208        let mut out = vec![0.0f32; vocab];
19209        {
19210            let _g = e0.gpu.enter_main()?;
19211            let logits0 = ws0.peek_f32("logits")?;
19212            let host0 = e0.dtoh_view(&logits0.slice(0..vsplit))?;
19213            out[..vsplit].copy_from_slice(&host0);
19214        }
19215        {
19216            let _g = e1.gpu.enter_main()?;
19217            let logits1 = ws1.peek_f32("logits")?;
19218            let host1 = e1.dtoh_view(&logits1.slice(0..vocab - vsplit))?;
19219            out[vsplit..].copy_from_slice(&host1);
19220        }
19221        for (s, plane) in planes0.into_iter().enumerate() {
19222            ws0.put_f32(PLANE_SLOTS[s], plane);
19223        }
19224        for (s, plane) in planes1.into_iter().enumerate() {
19225            ws1.put_f32(PLANE_SLOTS[s], plane);
19226        }
19227        ws0.put_u64("hc.ptrs", ptrs0);
19228        ws1.put_u64("hc.ptrs", ptrs1);
19229        state.pos += 1;
19230        Ok(out)
19231    }
19232}
19233
19234impl Qwen4ExpGpu {
19235    /// TP2-NATIVE long-context state (tp2-prefill lane): the per-card halves allocate
19236    /// DIRECTLY at `capacity` and the single-card KV allocates as a stub — a 1M-token
19237    /// state never materializes the single-card cache at all (the yarn cell's card-0
19238    /// blocker). The state is TP2-latched from birth: single-card forwards refuse it
19239    /// (`state.tp2.is_some()`), and `decode_step_tp2` skips the migration.
19240    pub fn alloc_state_tp2(
19241        &self,
19242        e0: &Engine,
19243        e1: &Engine,
19244        shard: &Tp2Shard,
19245        capacity: usize,
19246        reserve: usize,
19247    ) -> Res<Qwen4ExpState> {
19248        // The single-card side: stub KV, live idx caches (the TP2 indexer runs on
19249        // card 0 through the same machinery), PLE/GDN states on card 0 unused by the
19250        // TP2 route but kept tiny.
19251        let mut state = {
19252            // Stub the single-card KV by allocating under a 1-token capacity, then
19253            // restore the real capacity for the mask/meta bookkeeping.
19254            // The stub's reserve is 1, not `reserve`: `reserve.min(1).max(1)` was written
19255            // here and is the constant 1 for every usize (clippy::min_max, deny-by-default,
19256            // which is how it surfaced). Behaviour-identical simplification — the real
19257            // `reserve` is restored two lines down.
19258            let mut st = self.alloc_state_reserve(e0, 1, 1, None)?;
19259            st.capacity = capacity;
19260            st.reserve = reserve;
19261            st
19262        };
19263        let mut tlayers = Vec::with_capacity(self.layers.len());
19264        for (layer, tw) in self.layers.iter().zip(shard.layers.iter()) {
19265            let mk_half = |e: &Engine, hw: &MixerHalfW| -> Res<MixerHalfState> {
19266                let _g = e.gpu.enter_main()?;
19267                match hw {
19268                    MixerHalfW::Gdn(h) => {
19269                        let conv_dim = 2 * h.nk_h * h.hk + h.nv_h * h.hv;
19270                        let pad = h.kernel - 1;
19271                        Ok(MixerHalfState::Gdn {
19272                            conv: e.zeros(pad * conv_dim)?,
19273                            state: e.zeros(h.nv_h * h.hv * h.hk)?,
19274                        })
19275                    }
19276                    MixerHalfW::Qsa(h) => {
19277                        let kv_dim = h.nkv_h * h.hd;
19278                        let kv = if kv_quant_on() {
19279                            QsaKvStore::Q8Q5 {
19280                                k: e.alloc_u8(capacity * q8_row_bytes(kv_dim))?,
19281                                v: e.alloc_u8(capacity * q5_row_bytes(kv_dim))?,
19282                            }
19283                        } else {
19284                            QsaKvStore::F32 {
19285                                k: e.zeros(capacity * kv_dim)?,
19286                                v: e.zeros(capacity * kv_dim)?,
19287                            }
19288                        };
19289                        Ok(MixerHalfState::Qsa { kv })
19290                    }
19291                }
19292            };
19293            let m0 = mk_half(e0, &tw.mixer0)?;
19294            let m1 = mk_half(e1, &tw.mixer1)?;
19295            let ple1 = match layer.ple.as_ref() {
19296                None => None,
19297                Some(ple) => {
19298                    let pad = (ple.plan.conv_kernel as usize - 1) * ple.plan.max_ngram as usize;
19299                    let _g = e1.gpu.enter_main()?;
19300                    let mut conv_hist = Vec::with_capacity(self.streams);
19301                    for _ in 0..self.streams {
19302                        conv_hist.push(e1.zeros(pad * self.hidden)?);
19303                    }
19304                    Some(PleState {
19305                        conv_hist,
19306                        ngram_ids: Vec::new(),
19307                        ngram_history: Vec::new(),
19308                        ngram_last_eos: -1,
19309                    })
19310                }
19311            };
19312            tlayers.push(Tp2LayerState { m0, m1, ple1 });
19313        }
19314        state.tp2 = Some(Tp2State {
19315            ws1: StepPool::default(),
19316            layers: tlayers,
19317            graphs: Tp2Graphs::default(),
19318            pf_stage0: None,
19319            pf_stage1: None,
19320            pf_stage0_raw: [0; 2],
19321            pf_stage1_raw: [0; 2],
19322            pf_rows: 0,
19323        });
19324        Ok(state)
19325    }
19326
19327    /// TP2 LONG-context chunked prefill: `prefill_extend`'s program on the TP2 route —
19328    /// KV/state fill happens SHARDED-LOCAL on each card (the yarn cell measured remote
19329    /// KV at 18x decode collapse; local halves are the 1M route). Returns the LAST
19330    /// row's logits [vocab].
19331    pub fn prefill_extend_tp2(
19332        &self,
19333        e0: &Engine,
19334        e1: &Engine,
19335        shard: &Tp2Shard,
19336        ids: &[u32],
19337        state: &mut Qwen4ExpState,
19338        chunk: usize,
19339    ) -> Res<Vec<f32>> {
19340        if ids.is_empty() || chunk == 0 {
19341            return Err("qwen4exp_gpu: prefill_extend_tp2 needs ids and a chunk size".into());
19342        }
19343        let mut last = Vec::new();
19344        for piece in ids.chunks(chunk) {
19345            let is_last =
19346                piece.as_ptr() as usize + piece.len() * 4 == ids.as_ptr() as usize + ids.len() * 4;
19347            let head = if is_last {
19348                HeadMode::LastRow
19349            } else {
19350                HeadMode::Skip
19351            };
19352            last = self.forward_tp2(e0, e1, shard, piece, state, head)?;
19353        }
19354        Ok(last)
19355    }
19356
19357    /// One TP2 forward over `t` rows (eager; the TP2-prefill program). Replicated
19358    /// planes + gate reads on both cards, mixer/MoE halves with LOCAL KV/state, join
19359    /// adds in fixed rank order (the decode joins' determinism argument), the indexer
19360    /// selection ONCE on card 0 feeding both cards' block-list halves, and the MoE
19361    /// route split by expert half from the card-0 host route.
19362    #[allow(clippy::too_many_arguments)]
19363    pub fn forward_tp2(
19364        &self,
19365        e0: &Engine,
19366        e1: &Engine,
19367        shard: &Tp2Shard,
19368        ids: &[u32],
19369        state: &mut Qwen4ExpState,
19370        head: HeadMode,
19371    ) -> Res<Vec<f32>> {
19372        if !trunk_bf16_on() || !hc_fused_gate_on() {
19373            return Err(
19374                "qwen4exp_gpu tp2: requires set_trunk_bf16(true) and set_hc_fused_gate(true)"
19375                    .into(),
19376            );
19377        }
19378        let t = ids.len();
19379        if t == 0 {
19380            return Err("qwen4exp_gpu tp2: empty chunk".into());
19381        }
19382        if state.pos + t > state.capacity {
19383            return Err("qwen4exp_gpu: state capacity exceeded".into());
19384        }
19385        if state.tp2.is_none() {
19386            self.tp2_migrate(e0, e1, shard, state)?;
19387            state.graphs = StepGraphs::default();
19388        }
19389        let hidden = self.hidden;
19390        let vocab = self.vocab;
19391        let vsplit = shard.vsplit;
19392        let base_pos = state.pos;
19393        let reserve = state.reserve;
19394        state.tokens.extend_from_slice(ids);
19395        let Qwen4ExpState {
19396            ref tokens,
19397            ws: ref mut ws0,
19398            ref mut tp2,
19399            layers: ref mut lstates,
19400            ..
19401        } = *state;
19402        let tp2s = tp2.as_mut().expect("alloc'd or migrated above");
19403        // Prefill join staging: [t*hidden] x 2 per direction, grown to the largest
19404        // chunk seen (the two-buffer parity proof is the decode staging's, verbatim).
19405        if tp2s.pf_rows < t {
19406            {
19407                let _g = e1.gpu.enter_main()?;
19408                let s1 = [e1.zeros(t * hidden)?, e1.zeros(t * hidden)?];
19409                let s = e1.gpu.stream();
19410                tp2s.pf_stage1_raw = [s1[0].device_ptr(&s).0, s1[1].device_ptr(&s).0];
19411                tp2s.pf_stage1 = Some(s1);
19412            }
19413            {
19414                let _g = e0.gpu.enter_main()?;
19415                let s0 = [e0.zeros(t * hidden)?, e0.zeros(t * hidden)?];
19416                let s = e0.gpu.stream();
19417                tp2s.pf_stage0_raw = [s0[0].device_ptr(&s).0, s0[1].device_ptr(&s).0];
19418                tp2s.pf_stage0 = Some(s0);
19419            }
19420            tp2s.pf_rows = t;
19421        }
19422        let Tp2State {
19423            ws1,
19424            layers: tlayers,
19425            pf_stage0,
19426            pf_stage1,
19427            pf_stage0_raw,
19428            pf_stage1_raw,
19429            ..
19430        } = tp2s;
19431        let pf_stage0 = pf_stage0.as_ref().expect("sized above");
19432        let pf_stage1 = pf_stage1.as_ref().expect("sized above");
19433        let resv = reserve.max(t);
19434
19435        // Entry: embed rows, H2D to BOTH cards' plane slots (replicated planes).
19436        let mut embedded = vec![0.0f32; t * hidden];
19437        for (row, &token) in ids.iter().enumerate() {
19438            let token = token as usize;
19439            if token >= vocab {
19440                return Err(format!("qwen4exp_gpu: token {token} out of range").into());
19441            }
19442            embedded[row * hidden..(row + 1) * hidden]
19443                .copy_from_slice(&self.embed_host[token * hidden..(token + 1) * hidden]);
19444        }
19445        let mut planes1: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
19446        let ptrs1 = {
19447            let _g = e1.gpu.enter_main()?;
19448            let embedded_dev = ws1.take_f32_h2d(e1, "entry.embed", &embedded, resv * hidden)?;
19449            for s in 0..self.streams {
19450                let mut plane = ws1.take_f32(e1, PLANE_SLOTS[s], t * hidden, resv * hidden)?;
19451                e1.copy_into(&mut plane, 0, &embedded_dev, t * hidden)?;
19452                planes1.push(plane);
19453            }
19454            ws1.put_f32("entry.embed", embedded_dev);
19455            let ptr_vals: Vec<u64> = {
19456                let stream = e1.gpu.stream();
19457                planes1.iter().map(|p| p.device_ptr(&stream).0).collect()
19458            };
19459            ws1.take_u64_h2d(e1, "hc.ptrs", &ptr_vals, 0)?
19460        };
19461        let mut planes0: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
19462        let ptrs0 = {
19463            let _g = e0.gpu.enter_main()?;
19464            let embedded_dev = ws0.take_f32_h2d(e0, "entry.embed", &embedded, resv * hidden)?;
19465            for s in 0..self.streams {
19466                let mut plane = ws0.take_f32(e0, PLANE_SLOTS[s], t * hidden, resv * hidden)?;
19467                e0.copy_into(&mut plane, 0, &embedded_dev, t * hidden)?;
19468                planes0.push(plane);
19469            }
19470            ws0.put_f32("entry.embed", embedded_dev);
19471            let ptr_vals: Vec<u64> = {
19472                let stream = e0.gpu.stream();
19473                planes0.iter().map(|p| p.device_ptr(&stream).0).collect()
19474            };
19475            ws0.take_u64_h2d(e0, "hc.ptrs", &ptr_vals, 0)?
19476        };
19477
19478        for (li, layer) in self.layers.iter().enumerate() {
19479            let lstate = &mut lstates[li];
19480            let tw = &shard.layers[li];
19481            let ts = &mut tlayers[li];
19482            let eps_a = layer.eps_attn;
19483            let eps_m = layer.eps_mlp;
19484            let moe = &layer.moe;
19485            let ff = moe.plan.expert_intermediate_size as usize;
19486            let experts = moe.plan.expert_count as usize;
19487            let selected = moe.plan.experts_per_token as usize;
19488            let sff = moe
19489                .plan
19490                .shared
19491                .as_ref()
19492                .map(|s| s.intermediate_size as usize)
19493                .unwrap_or(0);
19494            let sffh = sff / 2;
19495
19496            // ---- PLE (wide-stream add), replicated on both cards ----
19497            if let (Some(ple), Some(ps)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
19498                let _g = e0.gpu.enter_main()?;
19499                self.ple_block(
19500                    e0,
19501                    layer,
19502                    ple,
19503                    &ple.table,
19504                    ps,
19505                    &mut planes0,
19506                    tokens,
19507                    t,
19508                    false,
19509                    None,
19510                )?;
19511            }
19512            if let (Some(ple1), Some(ps1)) = (tw.ple1.as_ref(), ts.ple1.as_mut()) {
19513                let table = &layer.ple.as_ref().expect("ple plan").table;
19514                let _g = e1.gpu.enter_main()?;
19515                self.ple_block(
19516                    e1,
19517                    layer,
19518                    ple1,
19519                    table,
19520                    ps1,
19521                    &mut planes1,
19522                    tokens,
19523                    t,
19524                    false,
19525                    None,
19526                )?;
19527            }
19528
19529            // ---- phase 1: attn gate + mixer halves + join push (parity 0) ----
19530            match (&layer.mixer, &tw.mixer0, &tw.mixer1) {
19531                (MixerW::Gdn(_), MixerHalfW::Gdn(h0), MixerHalfW::Gdn(h1)) => {
19532                    {
19533                        let _g = e1.gpu.enter_main()?;
19534                        let (mixed1, inj1) = self.gate_read(
19535                            e1,
19536                            ws1,
19537                            &ptrs1,
19538                            &tw.attn_gate1,
19539                            &planes1,
19540                            t,
19541                            eps_a,
19542                            false,
19543                        )?;
19544                        let p1 =
19545                            self.gdn_forward_half(e1, ws1, eps_a, h1, &mixed1, &mut ts.m1, t)?;
19546                        ws1.put_f32("hc.mixed", mixed1);
19547                        launch_push(e1, &p1, pf_stage0_raw[0], t * hidden)?;
19548                        ws1.put_f32("mixer.out", p1);
19549                        put_inject(ws1, inj1);
19550                        shard.ev1[0].record(&e1.gpu.stream())?;
19551                    }
19552                    {
19553                        let _g = e0.gpu.enter_main()?;
19554                        let (mixed0, inj0) = self.gate_read(
19555                            e0,
19556                            ws0,
19557                            &ptrs0,
19558                            &layer.attn_gate,
19559                            &planes0,
19560                            t,
19561                            eps_a,
19562                            false,
19563                        )?;
19564                        let p0 =
19565                            self.gdn_forward_half(e0, ws0, eps_a, h0, &mixed0, &mut ts.m0, t)?;
19566                        ws0.put_f32("hc.mixed", mixed0);
19567                        launch_push(e0, &p0, pf_stage1_raw[0], t * hidden)?;
19568                        ws0.put_f32("mixer.out", p0);
19569                        put_inject(ws0, inj0);
19570                        shard.ev0[0].record(&e0.gpu.stream())?;
19571                    }
19572                }
19573                (MixerW::Qsa(qsa), MixerHalfW::Qsa(h0), MixerHalfW::Qsa(h1)) => {
19574                    let (q1, g1, inj1) = {
19575                        let _g = e1.gpu.enter_main()?;
19576                        let (mixed1, inj1) = self.gate_read(
19577                            e1,
19578                            ws1,
19579                            &ptrs1,
19580                            &tw.attn_gate1,
19581                            &planes1,
19582                            t,
19583                            eps_a,
19584                            false,
19585                        )?;
19586                        let (q1, g1) = self
19587                            .qsa_half_proj(e1, ws1, eps_a, h1, &mixed1, &mut ts.m1, base_pos, t)?;
19588                        ws1.put_f32("hc.mixed", mixed1);
19589                        (q1, g1, inj1)
19590                    };
19591                    let (sels, q0, g0, inj0) = {
19592                        let _g = e0.gpu.enter_main()?;
19593                        let (mixed0, inj0) = self.gate_read(
19594                            e0,
19595                            ws0,
19596                            &ptrs0,
19597                            &layer.attn_gate,
19598                            &planes0,
19599                            t,
19600                            eps_a,
19601                            false,
19602                        )?;
19603                        let (q0, g0) = self
19604                            .qsa_half_proj(e0, ws0, eps_a, h0, &mixed0, &mut ts.m0, base_pos, t)?;
19605                        let MixerState::Qsa {
19606                            raw_keys,
19607                            pooled_keys,
19608                            pooled_dev,
19609                            pooled_dev_rows,
19610                            raw_dev,
19611                            raw_dev_rows,
19612                            idx_audit,
19613                            ..
19614                        } = &mut lstate.mixer
19615                        else {
19616                            return Err("qwen4exp_gpu tp2: QSA layer without raw-key cache".into());
19617                        };
19618                        let sels = self.qsa_update_select(
19619                            e0,
19620                            ws0,
19621                            qsa,
19622                            eps_a,
19623                            &mixed0,
19624                            raw_keys,
19625                            pooled_keys,
19626                            pooled_dev,
19627                            pooled_dev_rows,
19628                            raw_dev,
19629                            raw_dev_rows,
19630                            idx_audit.as_mut(),
19631                            base_pos,
19632                            t,
19633                            0,
19634                            false,
19635                        )?;
19636                        ws0.put_f32("hc.mixed", mixed0);
19637                        (sels, q0, g0, inj0)
19638                    };
19639                    let t_kv = base_pos + t;
19640                    let block_size = qsa.overlay.block_size as usize;
19641                    let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
19642                    {
19643                        let _g = e1.gpu.enter_main()?;
19644                        let pos_dev = ws1.take_i32(e1, "qsa.selpos", &pos_flat, 0)?;
19645                        let meta_dev = ws1.take_i32(e1, "qsa.selmeta", &meta, 0)?;
19646                        let p1 = self.qsa_half_attend(
19647                            e1, ws1, h1, &ts.m1, q1, g1, &pos_dev, &meta_dev, max_count, t, t_kv,
19648                        )?;
19649                        ws1.put_i32("qsa.selpos", pos_dev);
19650                        ws1.put_i32("qsa.selmeta", meta_dev);
19651                        launch_push(e1, &p1, pf_stage0_raw[0], t * hidden)?;
19652                        ws1.put_f32("mixer.out", p1);
19653                        put_inject(ws1, inj1);
19654                        shard.ev1[0].record(&e1.gpu.stream())?;
19655                    }
19656                    {
19657                        let _g = e0.gpu.enter_main()?;
19658                        let pos_dev = ws0.take_i32(e0, "qsa.selpos", &pos_flat, 0)?;
19659                        let meta_dev = ws0.take_i32(e0, "qsa.selmeta", &meta, 0)?;
19660                        let p0 = self.qsa_half_attend(
19661                            e0, ws0, h0, &ts.m0, q0, g0, &pos_dev, &meta_dev, max_count, t, t_kv,
19662                        )?;
19663                        ws0.put_i32("qsa.selpos", pos_dev);
19664                        ws0.put_i32("qsa.selmeta", meta_dev);
19665                        launch_push(e0, &p0, pf_stage1_raw[0], t * hidden)?;
19666                        ws0.put_f32("mixer.out", p0);
19667                        put_inject(ws0, inj0);
19668                        shard.ev0[0].record(&e0.gpu.stream())?;
19669                    }
19670                }
19671                _ => return Err("qwen4exp_gpu tp2: mixer/shard shape mismatch".into()),
19672            }
19673            {
19674                let _g = e0.gpu.enter_main()?;
19675                e0.gpu.stream().wait(&shard.ev1[0])?;
19676            }
19677            {
19678                let _g = e1.gpu.enter_main()?;
19679                e1.gpu.stream().wait(&shard.ev0[0])?;
19680            }
19681
19682            // ---- phase 2: join add (fixed rank order) + gate_write + mlp gate_read ----
19683            let join_write = |e: &Engine,
19684                              ws: &mut StepPool,
19685                              ptrs: &CudaSlice<u64>,
19686                              planes: &mut [CudaSlice<f32>],
19687                              stage: &CudaSlice<f32>,
19688                              rank0: bool|
19689             -> Res<()> {
19690                let p = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
19691                let mut out = ws.take_f32(e, "join.out", t * hidden, 0)?;
19692                if rank0 {
19693                    e.add(&p, stage, &mut out, t * hidden)?;
19694                } else {
19695                    e.add(stage, &p, &mut out, t * hidden)?;
19696                }
19697                let inj = take_inject(e, ws, self.streams, t)?;
19698                self.gate_write(e, planes, ptrs, &out, &inj, t)?;
19699                ws.put_f32("mixer.out", p);
19700                ws.put_f32("join.out", out);
19701                put_inject(ws, inj);
19702                Ok(())
19703            };
19704            {
19705                let _g = e1.gpu.enter_main()?;
19706                join_write(e1, ws1, &ptrs1, &mut planes1, &pf_stage1[0], false)?;
19707            }
19708            {
19709                let _g = e0.gpu.enter_main()?;
19710                join_write(e0, ws0, &ptrs0, &mut planes0, &pf_stage0[0], true)?;
19711            }
19712
19713            // ---- phase 3: mlp gate + MoE halves + shared halves + join (parity 1) ----
19714            let mixed1 = {
19715                let _g = e1.gpu.enter_main()?;
19716                let (mixed1, injm1) =
19717                    self.gate_read(e1, ws1, &ptrs1, &tw.mlp_gate1, &planes1, t, eps_m, false)?;
19718                put_inject(ws1, injm1);
19719                mixed1
19720            };
19721            let mixed0 = {
19722                let _g = e0.gpu.enter_main()?;
19723                let (mixed0, injm0) =
19724                    self.gate_read(e0, ws0, &ptrs0, &layer.mlp_gate, &planes0, t, eps_m, false)?;
19725                put_inject(ws0, injm0);
19726                mixed0
19727            };
19728            // Route on card 0 (host twin — TP2 keeps host expert ids by construction),
19729            // split by expert half.
19730            let routes: Vec<Vec<(usize, f32)>> = {
19731                let _g = e0.gpu.enter_main()?;
19732                let mut router_out = ws0.take_f32(e0, "moe.router", t * experts, 0)?;
19733                let none: Option<CudaSlice<u8>> = None;
19734                let rb = if router_bf16_on() {
19735                    &moe.router_b16
19736                } else {
19737                    &none
19738                };
19739                linear_trunk_into(
19740                    e0,
19741                    &moe.router,
19742                    rb,
19743                    &mixed0,
19744                    &mut router_out,
19745                    t,
19746                    hidden,
19747                    experts,
19748                )?;
19749                let logits = e0.dtoh_view(&router_out.slice(0..t * experts))?;
19750                ws0.put_f32("moe.router", router_out);
19751                let mut routes = Vec::with_capacity(t);
19752                for token in 0..t {
19753                    routes.push(host_route_softmax_topk(
19754                        &logits[token * experts..(token + 1) * experts],
19755                        selected,
19756                    ));
19757                }
19758                routes
19759            };
19760            // Split by PLACEMENT (see the decode site); with no map loaded this is the
19761            // even split and reproduces the previous `eid < e_half` / `eid - e_half`
19762            // arithmetic exactly.
19763            let place = &tw.place;
19764            let split_half = |home: bool| -> Vec<Vec<(usize, f32)>> {
19765                routes
19766                    .iter()
19767                    .map(|r| {
19768                        r.iter()
19769                            .filter(|&&(eid, _)| (place.rank(eid) == 0) == home)
19770                            .map(|&(eid, w)| (place.local(eid), w))
19771                            .collect()
19772                    })
19773                    .collect()
19774            };
19775            let mut routes0 = split_half(true);
19776            let mut routes1 = split_half(false);
19777            // Per-rank engagement + the shared-format route trace, in the PREFILL shape
19778            // (one line per (layer, forward) carrying this chunk's t rows of picks).
19779            tp2_count_split(&routes0, &routes1);
19780            trace_moe_routes(layer.index, t, &routes);
19781            match tp2_gate_red()? {
19782                Tp2GateRed::None => {}
19783                Tp2GateRed::SkipPeerMoe => routes1.iter_mut().for_each(|r| r.clear()),
19784                Tp2GateRed::PeerLocalIds => {
19785                    for (r0, r1) in routes0.iter_mut().zip(routes1.iter_mut()) {
19786                        r0.append(r1);
19787                    }
19788                }
19789                Tp2GateRed::ReverseePeerWeights => {
19790                    for r in routes1.iter_mut() {
19791                        let n = r.len();
19792                        for i in 0..n / 2 {
19793                            let (a, b) = (r[i].1, r[n - 1 - i].1);
19794                            r[i].1 = b;
19795                            r[n - 1 - i].1 = a;
19796                        }
19797                    }
19798                }
19799            }
19800            let (routes0, routes1) = (routes0, routes1);
19801            // Card 1: routed half over the bank half (local ids) + shared suffix half.
19802            {
19803                let _g = e1.gpu.enter_main()?;
19804                let mut out1 = self.tp2_moe_rows(
19805                    e1,
19806                    ws1,
19807                    (
19808                        &tw.moe.gate1.codes,
19809                        &tw.moe.gate1.scales,
19810                        &tw.moe.gate1.macros_dev,
19811                    ),
19812                    (
19813                        &tw.moe.up1.codes,
19814                        &tw.moe.up1.scales,
19815                        &tw.moe.up1.macros_dev,
19816                    ),
19817                    (
19818                        &tw.moe.down1.codes,
19819                        &tw.moe.down1.scales,
19820                        &tw.moe.down1.macros_dev,
19821                    ),
19822                    &routes1,
19823                    &mixed1,
19824                    t,
19825                    ff,
19826                )?;
19827                let (sh, g) = self.tp2_shared_half(
19828                    e1,
19829                    ws1,
19830                    &tw.moe.shared_gu1_b16,
19831                    &tw.moe.shared_down1,
19832                    tw.moe.shared_input_gate1.as_ref(),
19833                    &mixed1,
19834                    sffh,
19835                    t,
19836                )?;
19837                match g.as_ref() {
19838                    Some(g) => e1.add_scaled_rows(&sh, g, &mut out1, hidden, t)?,
19839                    None => {
19840                        let mut summed = ws1.take_f32(e1, "moe.sum", t * hidden, 0)?;
19841                        e1.add(&out1, &sh, &mut summed, t * hidden)?;
19842                        ws1.put_f32("moe.out", out1);
19843                        out1 = summed;
19844                    }
19845                }
19846                ws1.put_f32("moe.sh_down", sh);
19847                if let Some(g) = g {
19848                    ws1.put_f32("moe.g", g);
19849                }
19850                launch_push(e1, &out1, pf_stage0_raw[1], t * hidden)?;
19851                ws1.put_f32("moe.out", out1);
19852                ws1.put_f32("hc.mixed", mixed1);
19853                shard.ev1[1].record(&e1.gpu.stream())?;
19854            }
19855            // Card 0: routed half over the FULL resident bank (absolute ids < E/2) +
19856            // shared prefix half.
19857            {
19858                let _g = e0.gpu.enter_main()?;
19859                let (
19860                    BankHalf::Nvfp4 {
19861                        codes: gc,
19862                        scales: gs,
19863                        macros_dev: gm,
19864                        ..
19865                    },
19866                    BankHalf::Nvfp4 {
19867                        codes: uc,
19868                        scales: us,
19869                        macros_dev: um,
19870                        ..
19871                    },
19872                    BankHalf::Nvfp4 {
19873                        codes: dc,
19874                        scales: ds,
19875                        macros_dev: dm,
19876                        ..
19877                    },
19878                ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
19879                else {
19880                    return Err("qwen4exp_gpu tp2: card0 bank is not NVFP4".into());
19881                };
19882                let mut out0 = self.tp2_moe_rows(
19883                    e0,
19884                    ws0,
19885                    (gc, gs, gm),
19886                    (uc, us, um),
19887                    (dc, ds, dm),
19888                    &routes0,
19889                    &mixed0,
19890                    t,
19891                    ff,
19892                )?;
19893                let (sh, g) = self.tp2_shared_half(
19894                    e0,
19895                    ws0,
19896                    &tw.moe.shared_gu0_b16,
19897                    &tw.moe.shared_down0,
19898                    moe.shared_input_gate.as_ref(),
19899                    &mixed0,
19900                    sffh,
19901                    t,
19902                )?;
19903                match g.as_ref() {
19904                    Some(g) => e0.add_scaled_rows(&sh, g, &mut out0, hidden, t)?,
19905                    None => {
19906                        let mut summed = ws0.take_f32(e0, "moe.sum", t * hidden, 0)?;
19907                        e0.add(&out0, &sh, &mut summed, t * hidden)?;
19908                        ws0.put_f32("moe.out", out0);
19909                        out0 = summed;
19910                    }
19911                }
19912                ws0.put_f32("moe.sh_down", sh);
19913                if let Some(g) = g {
19914                    ws0.put_f32("moe.g", g);
19915                }
19916                launch_push(e0, &out0, pf_stage1_raw[1], t * hidden)?;
19917                ws0.put_f32("moe.out", out0);
19918                ws0.put_f32("hc.mixed", mixed0);
19919                shard.ev0[1].record(&e0.gpu.stream())?;
19920            }
19921            {
19922                let _g = e1.gpu.enter_main()?;
19923                e1.gpu.stream().wait(&shard.ev0[1])?;
19924                let p = ws1.take_f32(e1, "moe.out", t * hidden, 0)?;
19925                let mut out = ws1.take_f32(e1, "join.out", t * hidden, 0)?;
19926                e1.add(&pf_stage1[1], &p, &mut out, t * hidden)?;
19927                let inj = take_inject(e1, ws1, self.streams, t)?;
19928                self.gate_write(e1, &mut planes1, &ptrs1, &out, &inj, t)?;
19929                ws1.put_f32("moe.out", p);
19930                ws1.put_f32("join.out", out);
19931                put_inject(ws1, inj);
19932            }
19933            {
19934                let _g = e0.gpu.enter_main()?;
19935                e0.gpu.stream().wait(&shard.ev1[1])?;
19936                let p = ws0.take_f32(e0, "moe.out", t * hidden, 0)?;
19937                let mut out = ws0.take_f32(e0, "join.out", t * hidden, 0)?;
19938                e0.add(&p, &pf_stage0[1], &mut out, t * hidden)?;
19939                let inj = take_inject(e0, ws0, self.streams, t)?;
19940                self.gate_write(e0, &mut planes0, &ptrs0, &out, &inj, t)?;
19941                ws0.put_f32("moe.out", p);
19942                ws0.put_f32("join.out", out);
19943                put_inject(ws0, inj);
19944            }
19945        }
19946
19947        // Exit: Skip on interior chunks; LastRow copies each plane's final row into
19948        // t == 1 exit slots and runs the decode exit segment on them; All runs the exit
19949        // segment over ALL t rows straight off the planes.
19950        //
19951        // `All` used to fall through to the LastRow body, so a caller asking for every row
19952        // got exactly one and no error. That is the failure mode the loud-failure law is
19953        // about: the TP2 class gate's whole PRIME regime is "compare EVERY row of a full-head
19954        // forward", and it could not have done that — it only surfaced because the gate
19955        // length-checks single-card logits against TP2 logits before comparing
19956        // ("single-card produced 2483200 logits, TP2 248320"). Without that check the gate
19957        // would have compared one row and reported a t>=2 verdict.
19958        //
19959        // Cost note (why this stays an instrument, not a serving path): a [t, vocab] block is
19960        // t * 248320 * 4 bytes, so it is ~9.9 MB at the gate's 10-token probe and gigabytes at
19961        // a long-context chunk. Chunked prefill therefore still uses LastRow, exactly as the
19962        // single-card path does for the same reason.
19963        let head_rows = match head {
19964            HeadMode::All => t,
19965            _ => 1,
19966        };
19967        let mut out = vec![
19968            0.0f32;
19969            if head == HeadMode::Skip {
19970                0
19971            } else {
19972                head_rows * vocab
19973            }
19974        ];
19975        if head != HeadMode::Skip {
19976            {
19977                let _g = e1.gpu.enter_main()?;
19978                // All: the planes already hold every row, so the exit reads them directly
19979                // with the pointer array the trunk built. LastRow: copy each plane's final
19980                // row into the t == 1 exit slots (the decode-shaped exit).
19981                let mut exit_planes: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
19982                if head != HeadMode::All {
19983                    for (s, plane) in planes1.iter().enumerate() {
19984                        let mut row = ws1.take_f32(e1, EXIT_PLANE_SLOTS[s], hidden, hidden)?;
19985                        e1.copy_range_into(&mut row, 0, plane, (t - 1) * hidden, hidden)?;
19986                        exit_planes.push(row);
19987                    }
19988                }
19989                let use_planes: &[CudaSlice<f32>] = if head == HeadMode::All {
19990                    &planes1
19991                } else {
19992                    &exit_planes
19993                };
19994                let ptr_vals: Vec<u64> = {
19995                    let stream = e1.gpu.stream();
19996                    use_planes.iter().map(|p| p.device_ptr(&stream).0).collect()
19997                };
19998                let eptrs = ws1.take_u64_h2d(e1, "exit.ptrs", &ptr_vals, 0)?;
19999                self.tp2_seg_exit(
20000                    e1,
20001                    ws1,
20002                    &eptrs,
20003                    &shard.exit_gate1,
20004                    use_planes,
20005                    &shard.lm_head1,
20006                    vocab - vsplit,
20007                    head_rows,
20008                )?;
20009                ws1.put_u64("exit.ptrs", eptrs);
20010                for (s, p) in exit_planes.into_iter().enumerate() {
20011                    ws1.put_f32(EXIT_PLANE_SLOTS[s], p);
20012                }
20013                let logits1 = ws1.peek_f32("logits")?;
20014                let half1 = vocab - vsplit;
20015                let host1 = e1.dtoh_view(&logits1.slice(0..head_rows * half1))?;
20016                // This card owns the HIGH column half of every row, so a [rows, half1]
20017                // block scatters into [rows, vocab] one row at a time.
20018                for r in 0..head_rows {
20019                    out[r * vocab + vsplit..(r + 1) * vocab]
20020                        .copy_from_slice(&host1[r * half1..(r + 1) * half1]);
20021                }
20022            }
20023            {
20024                let _g = e0.gpu.enter_main()?;
20025                let head0 = self
20026                    .output_b16
20027                    .as_ref()
20028                    .ok_or("qwen4exp_gpu tp2: lm_head has no bf16 twin")?;
20029                let mut exit_planes: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
20030                if head != HeadMode::All {
20031                    for (s, plane) in planes0.iter().enumerate() {
20032                        let mut row = ws0.take_f32(e0, EXIT_PLANE_SLOTS[s], hidden, hidden)?;
20033                        e0.copy_range_into(&mut row, 0, plane, (t - 1) * hidden, hidden)?;
20034                        exit_planes.push(row);
20035                    }
20036                }
20037                let use_planes: &[CudaSlice<f32>] = if head == HeadMode::All {
20038                    &planes0
20039                } else {
20040                    &exit_planes
20041                };
20042                let ptr_vals: Vec<u64> = {
20043                    let stream = e0.gpu.stream();
20044                    use_planes.iter().map(|p| p.device_ptr(&stream).0).collect()
20045                };
20046                let eptrs = ws0.take_u64_h2d(e0, "exit.ptrs", &ptr_vals, 0)?;
20047                self.tp2_seg_exit(
20048                    e0,
20049                    ws0,
20050                    &eptrs,
20051                    &self.exit_mixer,
20052                    use_planes,
20053                    head0,
20054                    vsplit,
20055                    head_rows,
20056                )?;
20057                ws0.put_u64("exit.ptrs", eptrs);
20058                for (s, p) in exit_planes.into_iter().enumerate() {
20059                    ws0.put_f32(EXIT_PLANE_SLOTS[s], p);
20060                }
20061                let logits0 = ws0.peek_f32("logits")?;
20062                let host0 = e0.dtoh_view(&logits0.slice(0..head_rows * vsplit))?;
20063                // This card owns the LOW column half of every row.
20064                for r in 0..head_rows {
20065                    out[r * vocab..r * vocab + vsplit]
20066                        .copy_from_slice(&host0[r * vsplit..(r + 1) * vsplit]);
20067                }
20068            }
20069        } else {
20070            // Establish a host boundary per chunk so the chunk loop cannot run the
20071            // host arbitrarily far ahead of both devices.
20072            {
20073                let _g = e0.gpu.enter_main()?;
20074                e0.gpu.stream().synchronize()?;
20075            }
20076            {
20077                let _g = e1.gpu.enter_main()?;
20078                e1.gpu.stream().synchronize()?;
20079            }
20080        }
20081        for (s, plane) in planes0.into_iter().enumerate() {
20082            ws0.put_f32(PLANE_SLOTS[s], plane);
20083        }
20084        for (s, plane) in planes1.into_iter().enumerate() {
20085            ws1.put_f32(PLANE_SLOTS[s], plane);
20086        }
20087        ws0.put_u64("hc.ptrs", ptrs0);
20088        ws1.put_u64("hc.ptrs", ptrs1);
20089        state.pos += t;
20090        Ok(out)
20091    }
20092
20093    /// Grouped routed-experts half at t rows (TP2 prefill): the single-card grouped
20094    /// prefill program (SLOT_CAP sub-batching, absolute-token maps, per-token
20095    /// slot-ordered combines) over THIS CARD's bank (card 0 = the full resident bank
20096    /// with absolute ids < E/2; card 1 = the half bank with local ids). Tokens with no
20097    /// experts on this card keep their zero rows (the join sums the halves).
20098    #[allow(clippy::too_many_arguments)]
20099    fn tp2_moe_rows(
20100        &self,
20101        e: &Engine,
20102        ws: &mut StepPool,
20103        gate: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20104        up: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20105        down: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20106        routes: &[Vec<(usize, f32)>],
20107        mixed: &CudaSlice<f32>,
20108        t: usize,
20109        ff: usize,
20110    ) -> Res<CudaSlice<f32>> {
20111        let hidden = self.hidden;
20112        if !(sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0) {
20113            return Err(
20114                "qwen4exp_gpu tp2: prefill MoE needs the gufuse geometry (hidden%32, ff%4)".into(),
20115            );
20116        }
20117        let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
20118        {
20119            let mut view = out.slice_mut(0..t * hidden);
20120            e.memset_zeros_view(&mut view)?;
20121        }
20122        const SLOT_CAP: usize = 8192;
20123        let mut tok0 = 0usize;
20124        while tok0 < t {
20125            // Advance until the slot budget fills (routes are variable-length halves).
20126            let mut tok_n = 0usize;
20127            let mut slots = 0usize;
20128            while tok0 + tok_n < t {
20129                let n = routes[tok0 + tok_n].len();
20130                if tok_n > 0 && slots + n > SLOT_CAP {
20131                    break;
20132                }
20133                slots += n;
20134                tok_n += 1;
20135            }
20136            let batch = &routes[tok0..tok0 + tok_n];
20137            let mut sel_all: Vec<i32> = Vec::with_capacity(slots);
20138            let mut w_all: Vec<f32> = Vec::with_capacity(slots);
20139            let mut tok_all: Vec<i32> = Vec::with_capacity(slots);
20140            let mut ranges: Vec<(usize, usize)> = Vec::with_capacity(tok_n);
20141            for (i, route) in batch.iter().enumerate() {
20142                ranges.push((sel_all.len(), route.len()));
20143                for &(eid, wgt) in route {
20144                    sel_all.push(eid as i32);
20145                    w_all.push(wgt);
20146                    tok_all.push((tok0 + i) as i32);
20147                }
20148            }
20149            let s_total = sel_all.len();
20150            if s_total > 0 {
20151                let sel = ws.take_i32(e, "moe.sel", &sel_all, 0)?;
20152                let w_dev = ws.take_f32_h2d(e, "moe.w", &w_all, 0)?;
20153                let tokm = ws.take_i32(e, "moe.tok", &tok_all, 0)?;
20154                let mut act = ws.take_f32(e, "moe.act", s_total * ff, 0)?;
20155                launch_nvfp4_sel_gu_silu(
20156                    e,
20157                    gate,
20158                    up,
20159                    Some(&sel),
20160                    0,
20161                    s_total,
20162                    mixed,
20163                    &mut act,
20164                    hidden,
20165                    ff,
20166                    Some((&tokm, hidden)),
20167                )?;
20168                let mut partial = ws.take_f32(e, "moe.partial", s_total * hidden, 0)?;
20169                launch_nvfp4_sel_matvec(
20170                    e,
20171                    down.0,
20172                    down.1,
20173                    down.2,
20174                    &sel,
20175                    &act,
20176                    &mut partial,
20177                    s_total,
20178                    ff,
20179                    hidden,
20180                    ff,
20181                )?;
20182                for (i, &(start, len)) in ranges.iter().enumerate() {
20183                    if len > 0 {
20184                        launch_axpy_rows_seq_at(
20185                            e,
20186                            &partial,
20187                            start,
20188                            &w_dev,
20189                            start,
20190                            &mut out,
20191                            tok0 + i,
20192                            hidden,
20193                            len,
20194                        )?;
20195                    }
20196                }
20197                ws.put_i32("moe.sel", sel);
20198                ws.put_i32("moe.tok", tokm);
20199                ws.put_f32("moe.w", w_dev);
20200                ws.put_f32("moe.act", act);
20201                ws.put_f32("moe.partial", partial);
20202            }
20203            tok0 += tok_n;
20204        }
20205        Ok(out)
20206    }
20207
20208    /// TP2 segment A (GDN layers, graphable): attn gate_read + GDN half + join push;
20209    /// parks the partial in "mixer.out" and the inject scalars in their slots.
20210    #[allow(clippy::too_many_arguments)]
20211    fn tp2_gdn_seg_a(
20212        &self,
20213        e: &Engine,
20214        ws: &mut StepPool,
20215        ptrs: &CudaSlice<u64>,
20216        attn_gate: &GateW,
20217        h: &GdnHalfW,
20218        hstate: &mut MixerHalfState,
20219        planes: &[CudaSlice<f32>],
20220        eps: f32,
20221        push_raw: u64,
20222    ) -> Res<()> {
20223        let (mixed, inj) = self.gate_read(e, ws, ptrs, attn_gate, planes, 1, eps, false)?;
20224        let p = self.gdn_forward_half(e, ws, eps, h, &mixed, hstate, 1)?;
20225        ws.put_f32("hc.mixed", mixed);
20226        launch_push(e, &p, push_raw, self.hidden)?;
20227        ws.put_f32("mixer.out", p);
20228        put_inject(ws, inj);
20229        Ok(())
20230    }
20231
20232    /// TP2 segment B (all layers, graphable): mixer join add (SAME rank order on both
20233    /// cards) + gate_write + mlp gate_read (+ optional card-1 shared-half prestage,
20234    /// parked in "tp2.sh"/"tp2.shg"); parks the mlp mixed in "hc.mixed" and the mlp
20235    /// inject in its slots.
20236    #[allow(clippy::too_many_arguments)]
20237    fn tp2_seg_b(
20238        &self,
20239        e: &Engine,
20240        ws: &mut StepPool,
20241        ptrs: &CudaSlice<u64>,
20242        mlp_gate: &GateW,
20243        planes: &mut [CudaSlice<f32>],
20244        stage_recv: &CudaSlice<f32>,
20245        rank0: bool,
20246        eps_m: f32,
20247        shared: Option<(
20248            &CudaSlice<u8>,
20249            &CudaSlice<u8>,
20250            Option<&CudaSlice<f32>>,
20251            usize,
20252        )>,
20253    ) -> Res<()> {
20254        let hidden = self.hidden;
20255        let p = ws.take_f32(e, "mixer.out", hidden, 0)?;
20256        let mut out = ws.take_f32(e, "join.out", hidden, 0)?;
20257        if rank0 {
20258            e.add(&p, stage_recv, &mut out, hidden)?;
20259        } else {
20260            e.add(stage_recv, &p, &mut out, hidden)?;
20261        }
20262        let inj = take_inject(e, ws, self.streams, 1)?;
20263        self.gate_write(e, planes, ptrs, &out, &inj, 1)?;
20264        ws.put_f32("mixer.out", p);
20265        ws.put_f32("join.out", out);
20266        put_inject(ws, inj);
20267        let (mixed, injm) = self.gate_read(e, ws, ptrs, mlp_gate, planes, 1, eps_m, false)?;
20268        if let Some((gu_b16, d_b16, ig, sffh)) = shared {
20269            let (sh, gg) = self.tp2_shared_half(e, ws, gu_b16, d_b16, ig, &mixed, sffh, 1)?;
20270            // Slot-cycle invariant: park under the SAME names tp2_shared_half takes
20271            // from ("moe.sh_down"/"moe.g"), or the next capture of this segment would
20272            // allocate inside the capture region (graph mem node).
20273            ws.put_f32("moe.sh_down", sh);
20274            if let Some(gg) = gg {
20275                ws.put_f32("moe.g", gg);
20276            }
20277        }
20278        ws.put_f32("hc.mixed", mixed);
20279        put_inject(ws, injm);
20280        Ok(())
20281    }
20282
20283    /// TP2 exit segment (graphable): exit mixer read + this card's lm_head half into the
20284    /// parked "logits" slot.
20285    #[allow(clippy::too_many_arguments)]
20286    /// TP2 exit segment (mixer + this card's lm_head column half) over `rows` rows.
20287    ///
20288    /// `rows` used to be hardcoded to 1, which made `HeadMode::All` silently identical to
20289    /// `HeadMode::LastRow` in the TP2 forward — see the caller for why that was a defect
20290    /// and not merely a limitation. Both `gate_read_inner` and `launch_qmatvec_bf16w`
20291    /// already take a row count (the kernel's grid y-dim IS `t`, striding `x` by
20292    /// `x_tstride`), so this is a parameter that was never threaded, not new math: at
20293    /// `rows == 1` the launch arguments are byte-for-byte the ones this function used
20294    /// before, which is what makes the decode path a control rather than a hope.
20295    fn tp2_seg_exit(
20296        &self,
20297        e: &Engine,
20298        ws: &mut StepPool,
20299        ptrs: &CudaSlice<u64>,
20300        gate: &GateW,
20301        planes: &[CudaSlice<f32>],
20302        head_b16: &CudaSlice<u8>,
20303        out_f: usize,
20304        rows: usize,
20305    ) -> Res<()> {
20306        let x = self
20307            .gate_read_inner(e, ws, ptrs, gate, planes, rows, self.exit_eps, false, false)?
20308            .0;
20309        let mut logits = ws.take_f32(e, "logits", rows * out_f, rows * out_f)?;
20310        launch_qmatvec_bf16w(
20311            e,
20312            head_b16,
20313            &x,
20314            &mut logits,
20315            self.hidden,
20316            out_f,
20317            rows,
20318            1,
20319            0,
20320            0,
20321            self.hidden,
20322            0,
20323        )?;
20324        ws.put_f32("hc.mixed", x);
20325        ws.put_f32("logits", logits);
20326        Ok(())
20327    }
20328}
20329
20330/// Launch the count-gated grouped sel matvec (`_v3c`, fixed grid over `max_sel` slots,
20331/// live count from the pack blob). TP2 graph segments only; geometry must admit the
20332/// 4-row kernel (the artifact does).
20333#[allow(clippy::too_many_arguments)]
20334fn launch_nvfp4_sel_matvec_pack(
20335    e: &Engine,
20336    codes: &CudaSlice<u8>,
20337    scales: &CudaSlice<u8>,
20338    macros_dev: &CudaSlice<f32>,
20339    pack_raw: u64,
20340    max_sel: usize,
20341    x: &CudaSlice<f32>,
20342    y: &mut CudaSlice<f32>,
20343    in_f: usize,
20344    out_f: usize,
20345    x_stride: usize,
20346) -> Res<()> {
20347    if in_f % 32 != 0 || out_f % 4 != 0 {
20348        return Err(
20349            "qmatvec_nvfp4_modelopt_sel_f32_v3c: geometry needs in_f%32==0 && out_f%4==0".into(),
20350        );
20351    }
20352    let f = e.func("qmatvec_nvfp4_modelopt_sel_f32_v3c");
20353    let cfg = LaunchConfig {
20354        grid_dim: ((out_f / 4) as u32, max_sel as u32, 1),
20355        block_dim: (32, 1, 1),
20356        shared_mem_bytes: 0,
20357    };
20358    let (inf, outf, ms) = (in_f as i32, out_f as i32, max_sel as i32);
20359    let xs = x_stride as i64;
20360    let stream = e.gpu.stream();
20361    let mut b = stream.launch_builder(&f);
20362    b.arg(codes)
20363        .arg(scales)
20364        .arg(macros_dev)
20365        .arg(&pack_raw)
20366        .arg(&ms)
20367        .arg(x)
20368        .arg(y)
20369        .arg(&inf)
20370        .arg(&outf)
20371        .arg(&xs);
20372    unsafe {
20373        b.launch(cfg)?;
20374    }
20375    Ok(())
20376}
20377
20378fn launch_axpy_rows_seq_pack(
20379    e: &Engine,
20380    x: &CudaSlice<f32>,
20381    pack_raw: u64,
20382    max_sel: usize,
20383    y: &mut CudaSlice<f32>,
20384    width: usize,
20385) -> Res<()> {
20386    let f = e.func("axpy_rows_seq_pack_f32");
20387    let cfg = LaunchConfig::for_num_elems(width as u32);
20388    let (ms, wi) = (max_sel as i32, width as i32);
20389    let stream = e.gpu.stream();
20390    let mut b = stream.launch_builder(&f);
20391    b.arg(x).arg(&pack_raw).arg(&ms).arg(y).arg(&wi);
20392    unsafe {
20393        b.launch(cfg)?;
20394    }
20395    Ok(())
20396}
20397
20398/// Build the pack blob: [max_sel i32 sel padded][max_sel f32 w padded][i32 count].
20399fn tp2_pack_bytes(sel: &[i32], w: &[f32], max_sel: usize) -> Vec<u8> {
20400    let mut out = Vec::with_capacity((2 * max_sel + 1) * 4);
20401    for i in 0..max_sel {
20402        out.extend_from_slice(&sel.get(i).copied().unwrap_or(0).to_le_bytes());
20403    }
20404    for i in 0..max_sel {
20405        out.extend_from_slice(&w.get(i).copied().unwrap_or(0.0).to_le_bytes());
20406    }
20407    out.extend_from_slice(&(sel.len() as i32).to_le_bytes());
20408    out
20409}
20410
20411impl Qwen4ExpGpu {
20412    /// TP2 segment C (graphable): count-gated routed half over the pack blob + shared
20413    /// add + join push. Card 1 takes its prestaged shared parts ("moe.sh_down"/"moe.g",
20414    /// parked by seg B); card 0 computes its shared half here. Parks the MoE partial in
20415    /// "moe.out".
20416    #[allow(clippy::too_many_arguments)]
20417    fn tp2_seg_c(
20418        &self,
20419        e: &Engine,
20420        ws: &mut StepPool,
20421        gate: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20422        up: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20423        down: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
20424        ff: usize,
20425        max_sel: usize,
20426        shared_compute: Option<(
20427            &CudaSlice<u8>,
20428            &CudaSlice<u8>,
20429            Option<&CudaSlice<f32>>,
20430            usize,
20431        )>,
20432        shared_gated: bool,
20433        push_raw: u64,
20434    ) -> Res<()> {
20435        let hidden = self.hidden;
20436        let pack_raw = {
20437            let pack = ws.peek_u8("moe.pack")?;
20438            let stream = e.gpu.stream();
20439            pack.device_ptr(&stream).0
20440        };
20441        let mixed = ws.take_f32(e, "hc.mixed", hidden, 0)?;
20442        let mut act = ws.take_f32(e, "moe.act", max_sel * ff, 0)?;
20443        // Fused gate+up+silu (round 4, count-gated pack mode): the capture bakes the
20444        // live arm; dead slots (>= live count) retire at the first instruction and the
20445        // count-gated down/axpy never read them. Bit-identical to the chain per slot.
20446        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
20447            launch_nvfp4_sel_gu_silu(
20448                e, gate, up, None, pack_raw, max_sel, &mixed, &mut act, hidden, ff, None,
20449            )?;
20450        } else {
20451            let mut yg = ws.take_f32(e, "moe.yg", max_sel * ff, 0)?;
20452            let mut yu = ws.take_f32(e, "moe.yu", max_sel * ff, 0)?;
20453            launch_nvfp4_sel_matvec_pack(
20454                e, gate.0, gate.1, gate.2, pack_raw, max_sel, &mixed, &mut yg, hidden, ff, 0,
20455            )?;
20456            launch_nvfp4_sel_matvec_pack(
20457                e, up.0, up.1, up.2, pack_raw, max_sel, &mixed, &mut yu, hidden, ff, 0,
20458            )?;
20459            e.silu_mul(&yg, &yu, &mut act, max_sel * ff)?;
20460            ws.put_f32("moe.yg", yg);
20461            ws.put_f32("moe.yu", yu);
20462        }
20463        let mut partial = ws.take_f32(e, "moe.partial", max_sel * hidden, 0)?;
20464        launch_nvfp4_sel_matvec_pack(
20465            e,
20466            down.0,
20467            down.1,
20468            down.2,
20469            pack_raw,
20470            max_sel,
20471            &act,
20472            &mut partial,
20473            ff,
20474            hidden,
20475            ff,
20476        )?;
20477        let mut r = ws.take_f32(e, "moe.out", hidden, 0)?;
20478        launch_axpy_rows_seq_pack(e, &partial, pack_raw, max_sel, &mut r, hidden)?;
20479        ws.put_f32("moe.act", act);
20480        ws.put_f32("moe.partial", partial);
20481        let (sh, g) = match shared_compute {
20482            Some((gu_b16, d_b16, ig, sffh)) => {
20483                self.tp2_shared_half(e, ws, gu_b16, d_b16, ig, &mixed, sffh, 1)?
20484            }
20485            None => {
20486                let sh = ws.take_f32(e, "moe.sh_down", hidden, 0)?;
20487                let g = if shared_gated {
20488                    Some(ws.take_f32(e, "moe.g", 1, 0)?)
20489                } else {
20490                    None
20491                };
20492                (sh, g)
20493            }
20494        };
20495        match g.as_ref() {
20496            Some(g) => e.add_scaled_rows(&sh, g, &mut r, hidden, 1)?,
20497            None => {
20498                let mut view = r.slice_mut(0..hidden);
20499                e.axpy_into(&sh, 1.0, &mut view, hidden)?;
20500            }
20501        }
20502        ws.put_f32("moe.sh_down", sh);
20503        if let Some(g) = g {
20504            ws.put_f32("moe.g", g);
20505        }
20506        launch_push(e, &r, push_raw, hidden)?;
20507        ws.put_f32("moe.out", r);
20508        ws.put_f32("hc.mixed", mixed);
20509        Ok(())
20510    }
20511
20512    /// TP2 segment D (graphable): MoE join add (SAME rank order both cards) + gate_write.
20513    #[allow(clippy::too_many_arguments)]
20514    fn tp2_seg_d(
20515        &self,
20516        e: &Engine,
20517        ws: &mut StepPool,
20518        ptrs: &CudaSlice<u64>,
20519        planes: &mut [CudaSlice<f32>],
20520        stage_recv: &CudaSlice<f32>,
20521        rank0: bool,
20522    ) -> Res<()> {
20523        let hidden = self.hidden;
20524        let mp = ws.take_f32(e, "moe.out", hidden, 0)?;
20525        let mut mo = ws.take_f32(e, "join.out", hidden, 0)?;
20526        if rank0 {
20527            e.add(&mp, stage_recv, &mut mo, hidden)?;
20528        } else {
20529            e.add(stage_recv, &mp, &mut mo, hidden)?;
20530        }
20531        let injm = take_inject(e, ws, self.streams, 1)?;
20532        self.gate_write(e, planes, ptrs, &mo, &injm, 1)?;
20533        ws.put_f32("moe.out", mp);
20534        ws.put_f32("join.out", mo);
20535        put_inject(ws, injm);
20536        Ok(())
20537    }
20538}
20539
20540#[cfg(test)]
20541mod sel_group_tests {
20542    use super::*;
20543
20544    /// The seam lives in process-global atomics and `cargo test` runs these in parallel
20545    /// THREADS of one process, so every test that mutates it takes this lock. Without it the
20546    /// mutating tests race and the suite fails intermittently on whichever one loses.
20547    static SEAM: std::sync::Mutex<()> = std::sync::Mutex::new(());
20548
20549    /// The AUTO rule at the SERVING geometry, pinned as a test because it is the shape the
20550    /// seam ships and it was WRONG once: an earlier rule derived `rows` from `g` to hold
20551    /// rows-per-warp at 4, and the measured ladder showed rows-per-LANE is what pays
20552    /// (DOWNSEL.md section 4). A regression here is a silent shape change.
20553    #[test]
20554    fn auto_resolves_the_measured_serving_shapes() {
20555        // down: out_f = hidden 2560, in_f = expert ff 640 -> pairs 20 -> g 4 (largest power
20556        // of two dividing 20), rows 4 -> rows_per_warp 32, grid.x 80.
20557        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 640, 2560), Some((4, 4)));
20558        // gate+up: out_f = ff 640, in_f = hidden 2560 -> pairs 80 -> g 16, rows 4 ->
20559        // rows_per_warp 8, grid.x 80.
20560        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 2560, 640), Some((16, 4)));
20561    }
20562
20563    #[test]
20564    fn off_and_odd_in_f_take_the_shipped_kernel() {
20565        assert_eq!(sel_group_resolve(SEL_GROUP_OFF, 640, 2560), None);
20566        // in_f % 32 != 0 is the v3 guard too; the group form must not claim it.
20567        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 48, 2560), None);
20568    }
20569
20570    /// AUTO must never hand back a shape the launcher cannot tile exactly: a ragged tile puts
20571    /// live and dead lanes in the same `__shfl_down_sync`. It steps `rows` down before giving
20572    /// up, and gives up rather than clamping.
20573    #[test]
20574    fn auto_backs_off_rows_then_refuses_rather_than_tiling_raggedly() {
20575        // pairs 2 -> g 2 -> 16 groups. out_f 32 admits rows 2 (rpw 32); rows 4 (rpw 64) does
20576        // not divide 32, so AUTO must step down instead of returning an untileable shape.
20577        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 64, 32), Some((2, 2)));
20578        // out_f 24 divides by neither 64, 32 nor 16 (rows 4/2/1 at g=2) -> refuse.
20579        assert_eq!(sel_group_resolve(SEL_GROUP_AUTO, 64, 24), None);
20580        for &(in_f, out_f) in &[(640usize, 2560usize), (2560, 640), (32, 32), (64, 16)] {
20581            let (g, rows) = sel_group_resolve(SEL_GROUP_AUTO, in_f, out_f)
20582                .unwrap_or_else(|| panic!("auto refused {in_f}x{out_f}"));
20583            assert_eq!(
20584                out_f % ((32 / g) * rows),
20585                0,
20586                "{in_f}x{out_f} -> g{g} rows{rows}"
20587            );
20588        }
20589    }
20590
20591    /// An explicit pin is honoured verbatim (the A/B ladder depends on it) but still refuses a
20592    /// geometry it cannot tile, so a mis-set cell falls back to the shipped kernel loudly
20593    /// rather than launching a ragged grid.
20594    #[test]
20595    fn explicit_pins_are_verbatim_and_still_tile_checked() {
20596        let _g = SEAM.lock().unwrap();
20597        assert!(set_sel_group("dn:8:1+gu:16:4"));
20598        assert_eq!(sel_group_resolve(sel_group_dn(), 640, 2560), Some((8, 1)));
20599        assert_eq!(sel_group_resolve(sel_group_gu(), 2560, 640), Some((16, 4)));
20600        // g=1 rows=4 -> rows_per_warp 128. Both serving widths are multiples of 128 and
20601        // tile fine (2560 = 20x128, 640 = 5x128); an out_f that is NOT must refuse.
20602        assert!(set_sel_group("dn:1:4"));
20603        assert_eq!(sel_group_resolve(sel_group_dn(), 2560, 640), Some((1, 4)));
20604        assert_eq!(sel_group_resolve(sel_group_dn(), 2560, 96), None);
20605        set_sel_group("off");
20606    }
20607
20608    /// A malformed spec must APPLY NOTHING and report false. If it half-applied or reported
20609    /// true, a typo in a cell script would silently measure the wrong arm — the failure the
20610    /// seam grammar exists to make impossible.
20611    #[test]
20612    fn malformed_specs_apply_nothing_and_refuse() {
20613        let _g = SEAM.lock().unwrap();
20614        assert!(set_sel_group("dn:4:4+gu:16:4"));
20615        let before = sel_group_spec();
20616        for bad in [
20617            "dn:3:4",      // g not a power of two
20618            "dn:4:3",      // rows not in {1,2,4}
20619            "dn:64:4",     // g > 32
20620            "dn:4",        // no rows
20621            "xx:4:4",      // unknown family
20622            "dn:4:4+xx:1", // one good half, one bad -> still nothing applied
20623            "+",
20624        ] {
20625            assert!(!set_sel_group(bad), "{bad:?} was accepted");
20626            assert_eq!(
20627                sel_group_spec(),
20628                before,
20629                "{bad:?} mutated state while refusing"
20630            );
20631        }
20632        set_sel_group("off");
20633    }
20634
20635    /// `seam_state` has to answer for this seam even though it is shape-valued: the shared
20636    /// `--ladder-ab-seam` harness restores the entry arm ONLY when it answers, and a `None`
20637    /// there leaves the ON arm armed for every number after the A/B block.
20638    #[test]
20639    fn seam_round_trips_through_the_boolean_harness() {
20640        let _g = SEAM.lock().unwrap();
20641        set_sel_group("off");
20642        assert_eq!(seam_state("selgroup"), Some(false));
20643        assert!(set_seam("selgroup", true, None));
20644        assert_eq!(seam_state("selgroup"), Some(true));
20645        assert_eq!(sel_group_spec(), "dn:auto+gu:auto");
20646        assert!(set_seam("selgroup", false, None));
20647        assert_eq!(seam_state("selgroup"), Some(false));
20648        assert_eq!(sel_group_spec(), "dn:off+gu:off");
20649        // One family armed is still "armed", or an A/B that moved only the down half would
20650        // restore to OFF and lose the entry state.
20651        assert!(set_sel_group("dn:4:4+gu:off"));
20652        assert_eq!(seam_state("selgroup"), Some(true));
20653        set_sel_group("off");
20654        // Listed name and dispatch arm agree (the drift `seam_names` cannot detect alone).
20655        assert!(seam_names().contains(&"selgroup"));
20656        assert!(seam_exists("selgroup"));
20657    }
20658}
20659
20660// ============================================================ TP2/EP2 placement unit tests
20661//
20662// SCOPE, stated because this file is a GPU forward and these tests touch no GPU: every
20663// assertion below is over `Tp2Placement`/`LayerPlacement`, which are pure host logic: map
20664// parsing, the fail-closed refusal set, the bank-split arithmetic (`card1`/`local_of`/
20665// `rank_of`) and the even-split control-arm property. They run in plain `cargo test` on any
20666// machine, which is the point: the two-card BEHAVIOUR needs a box, but the two-card
20667// BOOKKEEPING is the part that silently moves expert weights under the router, and it had no
20668// coverage at all before this lane (`qwen4exp_gpu.rs` carried no test module).
20669//
20670// Lane: research/qwen4exp-bringup-20260829/ep2/EP2-DESIGN.md.
20671#[cfg(test)]
20672mod tp2_placement_tests {
20673    use super::{LayerPlacement, Tp2Placement};
20674
20675    /// One `memra-ep-map-v1` document over `experts` experts, `layers` = the (layer,
20676    /// assignment) rows given. Written through a temp file because `load` takes a path
20677    /// (the production door is `MEMRA_Q4E_EP_MAP=<path>`).
20678    fn write_map(name: &str, body: &str) -> std::path::PathBuf {
20679        let path = std::env::temp_dir().join(format!(
20680            "memra-q4e-ep-map-{name}-{}.json",
20681            std::process::id()
20682        ));
20683        std::fs::write(&path, body).expect("write map fixture");
20684        path
20685    }
20686
20687    fn load(name: &str, body: &str, expert_count: usize) -> Result<Tp2Placement, String> {
20688        let path = write_map(name, body);
20689        let out = Tp2Placement::load(&path, expert_count).map_err(|e| e.to_string());
20690        let _ = std::fs::remove_file(&path);
20691        out
20692    }
20693
20694    /// `{"format": ..., "ranks": 2, "entry_rank": 0, "expert_count": 4, <body>}`
20695    fn doc(body: &str) -> String {
20696        format!(
20697            "{{\"format\": \"memra-ep-map-v1\", \"strategy\": \"coactivation\", \
20698             \"ranks\": 2, \"entry_rank\": 0, \"expert_count\": 4, {body}}}"
20699        )
20700    }
20701
20702    fn assert_refuses(name: &str, body: &str, expert_count: usize, clause: &str) {
20703        match load(name, body, expert_count) {
20704            Ok(_) => panic!("{name}: expected a refusal naming {clause:?}, but the map loaded"),
20705            Err(msg) => {
20706                assert!(
20707                    msg.contains(clause),
20708                    "{name}: refusal must name the broken clause {clause:?}, got: {msg}"
20709                );
20710                // Every refusal names the FILE too, or the placement lane cannot tell
20711                // which of several candidate maps it has to fix.
20712                assert!(
20713                    msg.contains("MEMRA_Q4E_EP_MAP"),
20714                    "{name}: refusal must name the flag/file, got: {msg}"
20715                );
20716            }
20717        }
20718    }
20719
20720    // ---------------------------------------------------------------- the control arm
20721
20722    /// The unset door is the even split, and the even split is the CONTROL ARM of the
20723    /// placement A/B. Its bit-identity claim rests on exactly three properties, all
20724    /// asserted here rather than argued: card 0 addresses its full resident bank by
20725    /// GLOBAL id (no remap), card 1's gather order is the ascending suffix (a contiguous
20726    /// copy of what the pre-seam code sliced), and `is_even` recognises it.
20727    #[test]
20728    fn even_split_is_the_contiguous_suffix_control_arm() {
20729        let p = Tp2Placement::even(512);
20730        assert_eq!(p.strategy(), "even");
20731        assert_eq!(p.entry_rank(), 0);
20732        assert!(p.source().contains("MEMRA_Q4E_EP_MAP unset"));
20733
20734        let l = p.layer(0, 512).expect("even split resolves every layer");
20735        assert!(l.is_even(), "the built-in even split must report as even");
20736        assert_eq!(l.card1.len(), 256);
20737        // Ascending contiguous suffix.
20738        assert_eq!(l.card1, (256u32..512).collect::<Vec<_>>());
20739        for e in 0..256 {
20740            assert_eq!(l.rank(e), 0, "expert {e} belongs to card 0");
20741            assert_eq!(l.local(e), e, "card-0 local slot IS the global id");
20742        }
20743        for (slot, e) in (256..512).enumerate() {
20744            assert_eq!(l.rank(e), 1, "expert {e} belongs to card 1");
20745            assert_eq!(l.local(e), slot, "card-1 local slot is the gather position");
20746        }
20747        // Every MoE layer index resolves identically; the even split is layer-independent.
20748        let l47 = p.layer(47, 512).expect("layer 47");
20749        assert_eq!(l47.card1, l.card1);
20750    }
20751
20752    /// A MEASURED map moves bytes, and the local-slot bookkeeping is what keeps the
20753    /// router and the bank agreeing. Non-contiguous ownership is the whole point of
20754    /// co-activation placement, so it is the case the arithmetic must get right.
20755    #[test]
20756    fn measured_map_resolves_ascending_gather_and_local_slots() {
20757        // 4 experts, card 1 owns {0, 3}, deliberately NOT a suffix.
20758        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [1, 0, 0, 1]}]";
20759        let p = load("measured", &doc(body), 4).expect("balanced map loads");
20760        assert_eq!(p.strategy(), "coactivation");
20761        let l = p.layer(0, 4).expect("layer 0");
20762
20763        assert!(
20764            !l.is_even(),
20765            "a non-suffix placement is not the control arm"
20766        );
20767        // ASCENDING is load-bearing: it makes the gather order a function of the map
20768        // alone, so no host set-iteration order can leak into device bytes.
20769        assert_eq!(l.card1, vec![0u32, 3]);
20770        assert_eq!((l.rank(0), l.rank(1), l.rank(2), l.rank(3)), (1, 0, 0, 1));
20771        // card 1: local slot = position in `card1`.
20772        assert_eq!(l.local(0), 0);
20773        assert_eq!(l.local(3), 1);
20774        // card 0: local slot = the global id, untouched.
20775        assert_eq!(l.local(1), 1);
20776        assert_eq!(l.local(2), 2);
20777    }
20778
20779    /// `is_even` must not be fooled by a BALANCED-but-permuted map: it is the predicate a
20780    /// receipt uses to claim "this run was the control arm", so a false positive would let
20781    /// a measured-placement run be banked as its own control.
20782    #[test]
20783    fn is_even_rejects_a_balanced_permutation() {
20784        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 1, 1, 0]}]";
20785        let p = load("perm", &doc(body), 4).expect("balanced map loads");
20786        let l = p.layer(0, 4).expect("layer 0");
20787        assert_eq!(l.card1, vec![1u32, 2]);
20788        assert!(!l.is_even());
20789    }
20790
20791    /// A map whose assignment IS the even suffix must be recognised as the control arm,
20792    /// so the A/B harness can prove its two arms are the same program.
20793    #[test]
20794    fn an_explicit_even_map_matches_the_builtin_even_split() {
20795        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]";
20796        let p = load("explicit-even", &doc(body), 4).expect("even map loads");
20797        let l = p.layer(0, 4).expect("layer 0");
20798        let builtin = Tp2Placement::even(4).layer(0, 4).expect("builtin");
20799        assert!(l.is_even());
20800        assert_eq!(l.card1, builtin.card1);
20801        for e in 0..4 {
20802            assert_eq!(l.rank(e), builtin.rank(e), "rank of expert {e}");
20803            assert_eq!(l.local(e), builtin.local(e), "local slot of expert {e}");
20804        }
20805    }
20806
20807    // ---------------------------------------------------------------- the refusal set
20808    //
20809    // One test per contract clause. A half-applied placement moves expert weights under
20810    // the router and reads as a MODEL bug rather than a config bug, so each of these is a
20811    // load-time refusal by name, and each refusal has to name the clause it broke.
20812
20813    #[test]
20814    fn refuses_a_foreign_format() {
20815        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]";
20816        let text = format!(
20817            "{{\"format\": \"memra-ep-map-v2\", \"ranks\": 2, \"expert_count\": 4, {body}}}"
20818        );
20819        assert_refuses("format", &text, 4, "memra-ep-map-v1");
20820    }
20821
20822    #[test]
20823    fn refuses_a_rank_count_that_is_not_two() {
20824        let text = "{\"format\": \"memra-ep-map-v1\", \"ranks\": 4, \"expert_count\": 4, \
20825                    \"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]}";
20826        assert_refuses("ranks", text, 4, "exactly two cards");
20827    }
20828
20829    #[test]
20830    fn refuses_an_expert_count_that_is_not_the_plans() {
20831        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]";
20832        assert_refuses("experts", &doc(body), 8, "expert_count=4");
20833    }
20834
20835    #[test]
20836    fn refuses_an_entry_rank_outside_the_two_cards() {
20837        let text = "{\"format\": \"memra-ep-map-v1\", \"ranks\": 2, \"entry_rank\": 2, \
20838                    \"expert_count\": 4, \
20839                    \"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]}";
20840        assert_refuses("entry", text, 4, "entry_rank=2");
20841    }
20842
20843    #[test]
20844    fn refuses_a_document_with_no_layers_array() {
20845        assert_refuses("nolayers", &doc("\"strategy2\": 0"), 4, "no `layers` array");
20846    }
20847
20848    #[test]
20849    fn refuses_an_empty_layers_array() {
20850        assert_refuses(
20851            "emptylayers",
20852            &doc("\"layers\": []"),
20853            4,
20854            "`layers` is empty",
20855        );
20856    }
20857
20858    #[test]
20859    fn refuses_an_assignment_of_the_wrong_length() {
20860        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 1]}]";
20861        assert_refuses("shortassign", &doc(body), 4, "expected 4");
20862    }
20863
20864    #[test]
20865    fn refuses_a_rank_id_outside_the_two_cards() {
20866        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 7]}]";
20867        assert_refuses("badrank", &doc(body), 4, "expert 3");
20868    }
20869
20870    /// The clause with the sharpest consequence: the card-1 bank halves are EQUAL-SIZE
20871    /// device allocations, so an unbalanced map is out-of-bounds rather than merely
20872    /// slower. The refusal must also point at the tool's rebalance knob.
20873    #[test]
20874    fn refuses_an_unbalanced_layer_and_names_the_rebalance_knob() {
20875        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 1, 1, 1]}]";
20876        assert_refuses("unbalanced", &doc(body), 4, "card 1 owns 3 experts");
20877        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 1, 1, 1]}]";
20878        assert_refuses("unbalanced2", &doc(body), 4, "--balance-tolerance");
20879    }
20880
20881    /// A map that covers SOME MoE layers is not a placement. Falling the uncovered layers
20882    /// back to the even split would make the receipt a lie about which placement ran.
20883    #[test]
20884    fn refuses_a_layer_the_map_does_not_cover() {
20885        let body = "\"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1]}]";
20886        let p = load("partial", &doc(body), 4).expect("map loads");
20887        assert!(p.layer(0, 4).is_ok(), "the covered layer resolves");
20888        let msg = p
20889            .layer(1, 4)
20890            .expect_err("an uncovered MoE layer must refuse")
20891            .to_string();
20892        assert!(msg.contains("does not cover MoE layer 1"), "got: {msg}");
20893        assert!(
20894            msg.contains("partly-applied map is not a placement"),
20895            "the refusal must say WHY it is fail-closed, got: {msg}"
20896        );
20897    }
20898
20899    #[test]
20900    fn refuses_a_layer_whose_expert_count_disagrees_with_the_map() {
20901        let p = Tp2Placement::even(512);
20902        let msg = p
20903            .layer(0, 256)
20904            .expect_err("a layer geometry the map is not for must refuse")
20905            .to_string();
20906        assert!(msg.contains("map is for 512"), "got: {msg}");
20907    }
20908
20909    #[test]
20910    fn refuses_an_unreadable_map_path() {
20911        let missing = std::env::temp_dir().join(format!(
20912            "memra-q4e-ep-map-absent-{}.json",
20913            std::process::id()
20914        ));
20915        let _ = std::fs::remove_file(&missing);
20916        let msg = Tp2Placement::load(&missing, 4)
20917            .expect_err("an unreadable map must refuse at the load preflight")
20918            .to_string();
20919        assert!(msg.contains("MEMRA_Q4E_EP_MAP"), "got: {msg}");
20920    }
20921
20922    /// An ODD routed bank has no equal halves, on either path.
20923    ///
20924    /// Scoped honestly, because the guard's first justification overclaimed and review caught
20925    /// it: production cannot reach this, since `build_tp2_shard` refuses `experts % 2 != 0`
20926    /// before it asks for a `LayerPlacement`. These are `pub` entry points and the refusal
20927    /// belongs on the contract it breaks.
20928    ///
20929    /// The loaded arm below is the one that closes a REAL hole, and it is deliberately the
20930    /// BALANCED odd map: `half = expert_count / 2` floors, so 2-of-5 on card 1 satisfies
20931    /// `on1 == half` and loaded clean before this check. An unbalanced odd map (3-of-5) would
20932    /// have been refused by the balance clause already, so testing only that would have made
20933    /// this arm nearly vacuous.
20934    #[test]
20935    fn refuses_an_odd_routed_bank_on_both_paths() {
20936        // built-in even split
20937        let msg = Tp2Placement::even(5)
20938            .layer(0, 5)
20939            .expect_err("an odd bank has no two-card placement")
20940            .to_string();
20941        assert!(msg.contains("ODD"), "got: {msg}");
20942        assert!(msg.contains("EQUAL-size"), "got: {msg}");
20943        // loaded map, BALANCED under the floored half (on1 == 5/2 == 2): this one passed the
20944        // balance clause before the geometry check existed.
20945        let balanced_odd = "{\"format\": \"memra-ep-map-v1\", \"ranks\": 2, \
20946                            \"expert_count\": 5, \
20947                            \"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 0, 1, 1]}]}";
20948        assert_refuses("odd-balanced", balanced_odd, 5, "ODD");
20949        // and the unbalanced odd map, which the balance clause would also have caught, so this
20950        // asserts the geometry clause wins the race and names the real problem.
20951        let unbalanced_odd = "{\"format\": \"memra-ep-map-v1\", \"ranks\": 2, \
20952                              \"expert_count\": 5, \
20953                              \"layers\": [{\"layer\": 0, \"assignment\": [0, 0, 1, 1, 1]}]}";
20954        assert_refuses("odd-unbalanced", unbalanced_odd, 5, "ODD");
20955    }
20956
20957    // ---------------------------------------------------------------- bank-split arithmetic
20958
20959    /// The invariant the card-1 bank upload depends on, asserted over EVERY expert of a
20960    /// serving-geometry bank: exactly half the ids land on card 1, `card1` is strictly
20961    /// ascending, and `local_of` is a bijection onto `0..half` for card 1 and the identity
20962    /// on card 0. A violation here is an out-of-bounds device read, not a slow placement.
20963    #[test]
20964    fn local_slots_are_a_bijection_at_the_serving_geometry() {
20965        let experts = 512usize;
20966        let half = experts / 2;
20967        // A deterministic non-contiguous, exactly-balanced placement: alternate ownership.
20968        let assignment: Vec<String> = (0..experts).map(|e| (e % 2).to_string()).collect();
20969        let body = format!(
20970            "\"layers\": [{{\"layer\": 0, \"assignment\": [{}]}}]",
20971            assignment.join(", ")
20972        );
20973        let text = format!(
20974            "{{\"format\": \"memra-ep-map-v1\", \"ranks\": 2, \"expert_count\": {experts}, \
20975             {body}}}"
20976        );
20977        let p = load("bijection", &text, experts).expect("balanced alternating map loads");
20978        let l: LayerPlacement = p.layer(0, experts).expect("layer 0");
20979
20980        assert_eq!(l.card1.len(), half, "card 1 must own exactly half the bank");
20981        assert!(
20982            l.card1.windows(2).all(|w| w[0] < w[1]),
20983            "the gather order must be strictly ascending"
20984        );
20985        let mut seen = vec![false; half];
20986        for e in 0..experts {
20987            match l.rank(e) {
20988                0 => assert_eq!(l.local(e), e, "card-0 slot is the global id"),
20989                1 => {
20990                    let slot = l.local(e);
20991                    assert!(slot < half, "card-1 slot {slot} outside its half-bank");
20992                    assert!(!seen[slot], "card-1 slot {slot} claimed twice");
20993                    seen[slot] = true;
20994                }
20995                r => panic!("expert {e} has rank {r}"),
20996            }
20997        }
20998        assert!(seen.into_iter().all(|s| s), "card-1 slots must be dense");
20999        assert!(!l.is_even());
21000    }
21001}