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
33use std::os::raw::c_void;
34
35use cudarc::driver::{CudaSlice, CudaView, DevicePtr, DevicePtrMut, LaunchConfig, PushKernelArg};
36use memra_gguf::model_plan::{
37    AttentionPlan, FullAttentionPlan, GatedDeltaNetPlan, GdnGateActivation, MicroBlockIndexPlan,
38    MlpPlan, ModelPlan, MoeMlpPlan, PleEmbeddingPlan, ResidualTopology, RopeFactors, RopePlan,
39    RouterPlan, TensorPresence, yarn_attention_factor, yarn_frequency_divisors,
40};
41use memra_gguf::tensor_contract::{LayerTensor, TensorId};
42use memra_reference::{ReferenceTensor, ReferenceWeights};
43
44use crate::Engine;
45
46type Res<T> = Result<T, Box<dyn std::error::Error>>;
47
48// ---------------------------------------------------------------- weights
49
50/// One gated-residual read/write gate set (attn_/mlp_hyper_connection.*) or the exit
51/// mixer (`inject == None`, use_combine=false). Stream-major slicing happens at load so
52/// the forward composes from existing per-plane ops (see `gate_read`).
53struct GateW {
54    /// Per-stream [hidden] slices of hc_norm [wide].
55    norm: Vec<CudaSlice<f32>>,
56    /// The same norm weights stacked [streams, hidden] — the batched-norm kernel
57    /// (`hc_norm_planes_f32`, hcmicro seam) indexes them by stream in one launch.
58    norm_stack: CudaSlice<f32>,
59    /// Per-stream [rank, hidden] column-slices of input_mix_weight_down [rank, wide].
60    down: Vec<CudaSlice<f32>>,
61    /// Per-stream [hidden, rank] row-slices of input_mix_weight_up [wide, rank].
62    up: Vec<CudaSlice<f32>>,
63    /// block_inject_weight [streams, streams*hidden] whole, for the fused inject-gate
64    /// kernel (`hc_inject_gates_f32`); `None` for the exit mixer (census carries no
65    /// block_inject there).
66    inject: Option<CudaSlice<f32>>,
67    /// bf16 trunk-residency twins (see `TRUNK_BF16`): the down/up twins are STACKED
68    /// across streams ([S, rank, hidden] / [S, hidden, rank]) so the fused read gate
69    /// runs each projection as ONE batched `qmatvec_bf16w_f32` launch over the
70    /// stream-major slab instead of `streams` cuBLASLt GEMVs.
71    down_b16: Option<CudaSlice<u8>>,
72    up_b16: Option<CudaSlice<u8>>,
73    inject_b16: Option<CudaSlice<u8>>,
74}
75
76/// Low-rank width of a gate — from the f32 slices, or from the bf16 stacked twin when
77/// `trunk_f32_diet` dropped them (the twin is [S, rank, hidden] bf16).
78fn gate_rank(gate: &GateW, hidden: usize, streams: usize) -> Res<usize> {
79    if gate.down[0].len() >= hidden {
80        return Ok(gate.down[0].len() / hidden);
81    }
82    match gate.down_b16.as_ref() {
83        Some(w) => Ok(w.len() / (2 * streams * hidden)),
84        None => Err("qwen4exp_gpu: gate rank underivable (f32 dropped and no bf16 twin)".into()),
85    }
86}
87
88struct QsaW {
89    attn: FullAttentionPlan,
90    overlay: MicroBlockIndexPlan,
91    wq: CudaSlice<f32>, // [2*nh*hd, H] fused [q|gate] per head
92    wk: CudaSlice<f32>, // [nkv*hd, H]
93    wv: CudaSlice<f32>, // [nkv*hd, H]
94    wo: CudaSlice<f32>, // [H, nh*hd]
95    q_norm: Option<CudaSlice<f32>>,
96    k_norm: Option<CudaSlice<f32>>,
97    idx_proj: CudaSlice<f32>, // [(ih+ikv)*id, H]
98    /// Indexer norms live host-side: the selection is a host twin of
99    /// `memra_reference::micro_block_selection_mask`.
100    idx_q_norm: Vec<f32>,
101    idx_k_norm: Vec<f32>,
102    /// bf16 trunk-residency twins (`TRUNK_BF16` guards + receipts). wq/wk/wv live in
103    /// ONE row-stacked twin (proj-stack residency — see `GdnW::proj_b16`).
104    proj_b16: Option<CudaSlice<u8>>,
105    wo_b16: Option<CudaSlice<u8>>,
106    /// YaRN rope tables (long-context lane) — `None` on the shipped config.
107    yarn: Option<YarnRopeW>,
108}
109
110/// YaRN rope consumption (qwen4_exp long-context lane): the per-pair frequency divisors
111/// (device copy for `rope_neox_ffm`, host copy for the indexer twin) plus the derived
112/// attention factor on cos/sin. Built once at load from `RopeFactors::Yarn` through the
113/// memra-gguf transformers-twin helpers (pinned against the banked receipt). The QSA q/k
114/// rope, the indexer q/pooled-k rope, and the MTP draft all consume ONE table — the
115/// indexer shares the main rotary (SEMANTICS.md §Rope), enforced at build by the
116/// overlay-vs-attention rope-width check.
117struct YarnRopeW {
118    ff: CudaSlice<f32>,
119    ff_host: Vec<f32>,
120    mscale: f32,
121}
122
123/// Resolve a QSA rope plan into the yarn tables (or `None` for the plain-rope shipped
124/// config). PartialRotary/Checkpoint stay refused — this family's plan never emits them.
125/// `overlay` = `Some` at single-card load (the shared-table width check); the TP2 half
126/// builder passes `None` because the same plan already passed the check on card 0.
127fn build_yarn(
128    e: &Engine,
129    rope: &RopePlan,
130    overlay: Option<&MicroBlockIndexPlan>,
131    layer: u32,
132) -> Res<Option<YarnRopeW>> {
133    match rope.factors {
134        RopeFactors::None => Ok(None),
135        RopeFactors::Yarn {
136            factor,
137            original_context,
138            beta_fast,
139            beta_slow,
140        } => {
141            if let Some(overlay) = overlay
142                && overlay.rope_dimensions != rope.dimensions
143            {
144                return Err(format!(
145                    "qwen4exp_gpu: layer {layer} indexer rope width {} != attention rope \
146                     width {} — the shared yarn table would be wrong",
147                    overlay.rope_dimensions, rope.dimensions
148                )
149                .into());
150            }
151            let ff_host = yarn_frequency_divisors(
152                rope.dimensions,
153                rope.base,
154                factor,
155                original_context,
156                beta_fast,
157                beta_slow,
158            );
159            Ok(Some(YarnRopeW {
160                ff: e.htod(&ff_host)?,
161                ff_host,
162                mscale: yarn_attention_factor(factor),
163            }))
164        }
165        _ => Err(format!(
166            "qwen4exp_gpu: layer {layer}: only plain or yarn rope factors are supported"
167        )
168        .into()),
169    }
170}
171
172struct GdnW {
173    plan: GatedDeltaNetPlan,
174    qkv: CudaSlice<f32>,    // [conv_dim, H]
175    z: CudaSlice<f32>,      // [nv*hv, H]
176    beta: CudaSlice<f32>,   // [nv, H]
177    alpha: CudaSlice<f32>,  // [nv, H]
178    conv_w: CudaSlice<f32>, // [conv_dim, K]
179    a: CudaSlice<f32>,      // [nv] — the reference's `a` multiplier, used as-is by gdn_glog
180    dt: CudaSlice<f32>,     // [nv]
181    norm: CudaSlice<f32>,   // [hv]
182    out: CudaSlice<f32>,    // [H, nv*hv]
183    /// bf16 trunk-residency twins (`TRUNK_BF16` guards + receipts). The same-activation
184    /// projections live in ONE row-stacked twin [qkv; z; beta; alpha] (proj-stack
185    /// residency, VRAM-neutral): the per-mat arm launches against row-offset views, the
186    /// proj-stack seam launches the whole stack in one `qmatvec_bf16w_multi4_f32`.
187    proj_b16: Option<CudaSlice<u8>>,
188    out_b16: Option<CudaSlice<u8>>,
189}
190
191enum MixerW {
192    Qsa(QsaW),
193    Gdn(GdnW),
194}
195
196/// One resident half of a routed expert bank (fused gate_up [E, 2ff, H] with gate rows
197/// first per expert — SplitExpertGateUp orientation — or down [E, H, ff]).
198/// F32 = fixture / bf16 checkpoints (dequantized exactly at load). Nvfp4 = modelopt
199/// stacked as-stored (codes [E, out, in/2] u8 + e4m3 scales [E, out, in/16] + finite
200/// macros); per routed expert the eager path dequants through the existing dsv4 kernel
201/// then upcasts, macro post-upcast in f32 (`dequant_nvfp4_expert_f32`). Halves mix
202/// freely — NVFP4 needs in_f % 16 == 0, which geometry (not policy) decides per
203/// projection.
204enum BankHalf {
205    F32(CudaSlice<f32>),
206    Nvfp4 {
207        codes: CudaSlice<u8>,
208        scales: CudaSlice<u8>,
209        macros: Vec<f32>,
210        /// Device twin of `macros` for the grouped decode path
211        /// (`qmatvec_nvfp4_modelopt_sel_f32` folds the macro in its epilogue).
212        macros_dev: CudaSlice<f32>,
213    },
214    /// HOST-resident raw bf16 bank (logical [E, out, in]) — the real-checkpoint gate
215    /// residency for BF16 artifacts whose f32 banks exceed device memory (the 360 GB
216    /// export: f32 banks ≈ 483 GB). Each routed expert's rows are uploaded and upcast
217    /// per forward call (`LoadOptions::host_bf16_banks`); bf16→f32 is exact, so the
218    /// value chain equals the device-resident F32 arm. Gate-mode residency only —
219    /// never a serving configuration.
220    HostBf16(Vec<u8>),
221    /// DEVICE-resident raw bf16 bank (logical [E, out, in], row-major bf16 bytes) — the
222    /// MTP draft bank residency (mtp-spec lane): the graft ships the 512-expert bank
223    /// BF16 (~5 GB device) and the decode path runs per-selected-expert
224    /// `qmatvec_bf16w_f32` row-offset launches straight off the resident bytes
225    /// (exact-widening products, the trunk-bf16 accumulation class). Half the bytes of
226    /// an f32 residency; no dequant materialization.
227    DeviceBf16(CudaSlice<u8>),
228}
229
230struct ExpertBank {
231    gate: BankHalf, // logical [E, ff, H]
232    up: BankHalf,   // logical [E, ff, H]
233    down: BankHalf, // logical [E, H, ff]
234}
235
236struct MoeW {
237    plan: MoeMlpPlan,
238    router: CudaSlice<f32>, // [E, H]
239    /// bf16 residency twin of the router (set_router_bf16 seam; same guards as trunk).
240    router_b16: Option<CudaSlice<u8>>,
241    bank: ExpertBank,
242    shared_gate: CudaSlice<f32>,
243    shared_up: CudaSlice<f32>,
244    shared_down: CudaSlice<f32>,
245    shared_input_gate: Option<CudaSlice<f32>>, // [H]
246    /// bf16 residency twins for the shared-expert mats (hcmicro seam; same
247    /// representability/geometry guards as the trunk twins). gate/up live in ONE
248    /// row-stacked twin (proj-stack residency — see `GdnW::proj_b16`).
249    shared_gu_b16: Option<CudaSlice<u8>>,
250    shared_down_b16: Option<CudaSlice<u8>>,
251}
252
253/// The n-gram embedding table stays HOST-resident (pure gather source).
254enum NgramTable {
255    F32(Vec<f32>),
256    Bf16(Vec<u8>),
257}
258
259impl NgramTable {
260    fn rows(&self, head_dim: usize) -> usize {
261        match self {
262            Self::F32(data) => data.len() / head_dim,
263            Self::Bf16(bytes) => bytes.len() / 2 / head_dim,
264        }
265    }
266
267    fn gather_into(&self, row: usize, head_dim: usize, dst: &mut [f32]) {
268        match self {
269            Self::F32(data) => {
270                dst.copy_from_slice(&data[row * head_dim..(row + 1) * head_dim]);
271            }
272            Self::Bf16(bytes) => {
273                let start = row * head_dim * 2;
274                for (i, out) in dst.iter_mut().enumerate() {
275                    let b = u16::from_le_bytes([bytes[start + 2 * i], bytes[start + 2 * i + 1]]);
276                    *out = f32::from_bits(u32::from(b) << 16);
277                }
278            }
279        }
280    }
281}
282
283struct PleW {
284    plan: PleEmbeddingPlan,
285    key_proj: Vec<CudaSlice<f32>>, // per-stream [H, embed] row slices of [wide, embed]
286    value_proj: CudaSlice<f32>,    // [H, embed]
287    norm_key: Vec<CudaSlice<f32>>, // per-stream [H]
288    norm_query: Vec<CudaSlice<f32>>,
289    norm_conv: Vec<CudaSlice<f32>>,
290    conv_w: Vec<CudaSlice<f32>>, // per-stream [H, K] row slices of [wide, K]
291    multipliers: Vec<i64>,
292    sizes: Vec<i64>,
293    offsets: Vec<i64>,
294    table: NgramTable,
295}
296
297struct LayerW {
298    index: u32,
299    eps_attn: f32,
300    eps_mlp: f32,
301    attn_gate: GateW,
302    mlp_gate: GateW,
303    mixer: MixerW,
304    moe: MoeW,
305    ple: Option<PleW>,
306}
307
308/// The MTP/NextN draft block (SEMANTICS.md §MTP, mtp-spec lane): input fusion =
309/// `fc_embedding(zero-centered-RMSNorm(embed(tok)))` broadcast over streams +
310/// per-stream `fc_hidden(FLAT GemmaRMSNorm_wide(trunk wide hidden))`; ONE decoder layer
311/// (QSA + MoE, own indexer, no PLE) at global index n_trunk; exit through the draft's
312/// OWN hyper_connection_mixer into the SHARED trunk lm_head. The post-layer wide state
313/// is the K>1 multi-step carrier. Norm rows arrive (1+w)-FOLDED from the loader (the
314/// family GemmaRMSNorm convention).
315struct MtpW {
316    /// Fusion-norm epsilons from the plan (`MtpInputPlan`).
317    eps_embed: f32,
318    eps_hidden: f32,
319    /// mtp.pre_fc_norm_embedding [hidden], folded.
320    pre_norm_embed: CudaSlice<f32>,
321    /// mtp.pre_fc_norm_hidden [wide] — FLAT over the whole wide vector, folded.
322    pre_norm_hidden: CudaSlice<f32>,
323    fc_embed: CudaSlice<f32>, // mtp.fc_embedding [hidden, hidden]
324    fc_embed_b16: Option<CudaSlice<u8>>,
325    fc_hidden: CudaSlice<f32>, // mtp.fc_hidden [hidden, hidden]
326    fc_hidden_b16: Option<CudaSlice<u8>>,
327    /// The draft decoder layer (index n_trunk; QSA mixer + MoE, bank DeviceBf16 on the
328    /// real graft).
329    layer: LayerW,
330    /// mtp.hyper_connection_mixer (read-only exit gate, no inject).
331    mixer: GateW,
332}
333
334/// Card-1 draft placement (mtp10): the MTP block's device tensors (weights + the ~5 GB
335/// DeviceBf16 expert bank), the draft state, and the draft workspace all live on a SECOND
336/// card, with a private full copy of the shared lm head beside them so the draft's head
337/// matvec never crosses the bus. What crosses per round is SMALL: the trunk's captured
338/// wide rows for the draft replay ((a+1) x wide f32, P2P) and the drafted token ids
339/// (4-byte dtoh each). Exactness is untouched by construction — the draft only proposes;
340/// the card-0 verify chunk arbitrates. Why this exists (measured, mtp9): the co-resident
341/// placement leaves ~2.6 GiB on card 0, which OOMs any spec run on a prompt past ~400
342/// tokens — the two-card placement is a PREREQUISITE for agentic-length prompts, not an
343/// optimization.
344struct MtpDev1 {
345    /// Engine ordinal the draft was built on (every draft call must present it).
346    dev: usize,
347    /// [vocab, H] f32 copy of the shared lm head (the cuBLASLt fallback arm).
348    output: CudaSlice<f32>,
349    /// bf16 twin of the head copy (the arm `linear_trunk_into` takes at the default
350    /// trunk_bf16 seam) — same bytes as card 0's twin, so a draft logit is bit-identical
351    /// to its single-card twin at the same row.
352    output_b16: Option<CudaSlice<u8>>,
353}
354
355/// FR-Spec draft-head trim (DRAFT-REGIME.md law 1, mtp9 lane): the DRAFT scores only
356/// the top-N own-gen rank subset, the TARGET verify stays full-vocab — so the spec
357/// byte-identity contract is untouched BY CONSTRUCTION and only ACCEPTANCE can move
358/// (a token outside the trim set is unproposable, i.e. a guaranteed one-round miss).
359/// Rows are gathered D2D from the shared lm head, so the trimmed head is the SAME
360/// bytes the full head would have read — a trimmed draft logit is bit-identical to its
361/// full-vocab twin at the same row.
362struct DraftTrim {
363    /// Rows in the trimmed head.
364    n: usize,
365    /// `d2t[i]` = the TARGET vocab id of trimmed row i (rank order, most frequent first).
366    d2t: Vec<u32>,
367    /// [n, hidden] gathered bf16 rows (the `qmatvec_bf16w_f32` arm — what the trunk seam
368    /// runs by default, and the ONLY residency built when the full head has a bf16 twin:
369    /// an f32 twin would cost 2x the bytes for a path the default never takes, and this
370    /// artifact's post-load headroom is ~2.5 GiB).
371    head_b16: Option<CudaSlice<u8>>,
372    /// [n, hidden] gathered f32 rows — built ONLY when there is no bf16 twin to gather
373    /// from (the cuBLASLt fallback arm). At least one of the two is always present.
374    head: Option<CudaSlice<f32>>,
375}
376
377/// The draft head's linear when the trim is armed — `linear_trunk_into`'s arm chain over
378/// the trimmed residency (bf16 twin first, f32 fallback), so a trimmed row's value chain
379/// is the full head's VERBATIM at the same row.
380fn linear_trim_into(
381    e: &Engine,
382    trim: &DraftTrim,
383    x: &CudaSlice<f32>,
384    y: &mut CudaSlice<f32>,
385    t: usize,
386    in_f: usize,
387) -> Res<()> {
388    if trunk_bf16_on() {
389        if let Some(w) = trim.head_b16.as_ref() {
390            if (2..=12).contains(&t) && verify_mt_on() {
391                return launch_qmatvec_bf16w_mt(e, w, 0, x, y, in_f, trim.n, t);
392            }
393            return launch_qmatvec_bf16w(e, w, x, y, in_f, trim.n, t, 1, 0, 0, in_f, 0);
394        }
395    }
396    let w = trim.head.as_ref().ok_or(
397        "qwen4exp_gpu: the draft trim was gathered bf16-only — the f32 head arm needs \
398         trunk_bf16 on (or a checkpoint without a bf16 lm-head twin)",
399    )?;
400    e.linear_device_into(x, w, y, t, in_f, trim.n)
401}
402
403pub struct Qwen4ExpGpu {
404    pub plan: ModelPlan,
405    hidden: usize,
406    streams: usize,
407    vocab: usize,
408    embed_host: Vec<f32>, // [vocab, H] — host row-gather source (reference embed twin)
409    output: CudaSlice<f32>, // [vocab, H] lm head (tied to embed when absent)
410    /// bf16 trunk-residency twin of the lm head (`TRUNK_BF16` guards + receipts).
411    output_b16: Option<CudaSlice<u8>>,
412    layers: Vec<LayerW>,
413    exit_mixer: GateW,
414    exit_eps: f32,
415    /// The MTP draft block — present when the checkpoint's mtp.* rows were materialized
416    /// (`LoadOptions::load_mtp`, or a fixture whose weights carry them).
417    mtp: Option<MtpW>,
418    /// Card-1 draft placement (mtp10): when present, `mtp`'s device tensors live on the
419    /// SECOND card and this holds that card's private lm-head copy. Every draft call
420    /// (mtp_state / mtp_draft_forward / spec_generate's draft engine) must then present
421    /// an engine on `mtp_dev1.dev` — enforced, not assumed.
422    mtp_dev1: Option<MtpDev1>,
423    /// FR-Spec draft-head trim — `None` (full-vocab draft head) unless a caller armed it
424    /// with `build_draft_trim`. Default OFF: a trim is a per-model, per-requant rank
425    /// artifact (law 1), never an inferred default.
426    draft_trim: Option<DraftTrim>,
427    /// A built trim PARKED by `set_draft_trim(false)` — the A/B's OFF arm keeps the
428    /// gathered head allocated (no per-rep realloc churn) while the draft runs full-vocab.
429    draft_trim_parked: Option<DraftTrim>,
430    /// Deferred-chain device embed table (mtp11, `SpecOpts::defer`) — `None` until a
431    /// caller armed it with `arm_spec_devchain`. Default OFF (flags law): the host
432    /// chain is the shipped mtp10 program until the deferred round carries its own
433    /// interleaved receipts.
434    chain_embed: Option<ChainEmbed>,
435}
436
437/// The deferred chain's embed rows, resident on the DRAFT engine (mtp11): the chain's
438/// device argmax feeds the next step's embed gather without a host round trip. Rows are
439/// raw bf16 when every source value is bf16-clean (this artifact's embed is a bf16
440/// export, so `f32 -> bits>>16 -> bits<<16` is the identity and the device gather's
441/// QT_BF16 deq reproduces the host `embed_host` row BITWISE — checked value-by-value at
442/// arm time, never assumed), else raw f32 (always exact, 2x bytes). With the FR-Spec
443/// trim armed the rows are gathered in TRIM-RANK order (row i = embed[d2t[i]]), so the
444/// RAW trim-space argmax index gathers its own next-step row and no d2t table crosses
445/// to the device; the round's drain maps raw -> target ids through `draft_token`.
446struct ChainEmbed {
447    table: CudaSlice<u8>,
448    qt: i32,
449    row_bytes: usize,
450    /// Rows in the table == `draft_logits_width()` at arm time (trim.n or vocab).
451    rows: usize,
452    /// Armed against a live trim (the table is trim-rank-gathered)?
453    for_trim: bool,
454    /// Device ordinal the table lives on (must be the draft engine's).
455    dev: usize,
456}
457
458// ---------------------------------------------------------------- state
459
460struct PleState {
461    /// Per-stream [pad_ple, H] device history of the NORMED gated value rows
462    /// (pad_ple = (K-1)*dilation = 9 on the artifact). Zeros = fresh context.
463    conv_hist: Vec<CudaSlice<f32>>,
464    /// INCREMENTAL n-gram id cache (`plecache` seam, 262k perf lane). `host_ngram_ids` is a
465    /// `ngram_ids` twin over the FULL token history and the caller then slices the last `t`
466    /// rows — so a decode step at a 150,000-token fill rebuilds 150,000 rows of hashes to
467    /// use ONE. Measured: `ple.host_ngram_gather` is **7.3 ms, 19.5% of a deep decode
468    /// token** (PROFILE-11 §5), second only to `qsa.sdpa`, and it is O(context) per token.
469    ///
470    /// Cacheable EXACTLY, and the proof is local: `shift_right_ignore_eos` at position p
471    /// reads `history[p - shift]` and an eos scan that only ever moves left-to-right, so
472    /// `ids[token]` is a pure function of `token_ids[..=token]` and NEVER changes when a
473    /// token is appended. The cache therefore appends; it never recomputes a row.
474    ///
475    /// `history` carries the `max_ngram - 1` eos prefix exactly as the twin builds it, and
476    /// `last_eos` is the twin's running `last_eos_inclusive` at the end of `history`. On a
477    /// rewind (spec reject) both truncate, which is the same discipline the `idxcache` seam
478    /// needed for its device mirror.
479    ngram_ids: Vec<i64>,
480    ngram_history: Vec<i64>,
481    ngram_last_eos: i64,
482}
483
484// ---- Quantized-cache storage (kvq/idxq lanes) --------------------------------------
485
486/// q8_0 row bytes for a `dim`-wide f32 row (34 B per 32-elem block, zero-padded tail).
487fn q8_row_bytes(dim: usize) -> usize {
488    dim.div_ceil(32) * 34
489}
490/// q5_1 row bytes (24 B per 32-elem block).
491fn q5_row_bytes(dim: usize) -> usize {
492    dim.div_ceil(32) * 24
493}
494
495/// QSA KV cache storage. `F32` is the historical exactness arm (every banked receipt);
496/// `Q8Q5` stores K rows as q8_0 and V rows as q5_1 byte caches (the owner's asymmetric
497/// K=q8/V=q5 default), token-slot-addressed exactly like the f32 rows — rewind stays a
498/// position rewrite, replay overwrites slots in place.
499enum QsaKvStore {
500    F32 {
501        k: CudaSlice<f32>, // [cap, nkv*hd] post-norm+rope keys
502        v: CudaSlice<f32>, // [cap, nkv*hd]
503    },
504    Q8Q5 {
505        k: CudaSlice<u8>, // [cap * q8_row_bytes(nkv*hd)]
506        v: CudaSlice<u8>, // [cap * q5_row_bytes(nkv*hd)]
507    },
508}
509
510impl QsaKvStore {
511    fn is_quant(&self) -> bool {
512        matches!(self, QsaKvStore::Q8Q5 { .. })
513    }
514    fn capacity_rows(&self, kv_dim: usize) -> usize {
515        match self {
516            QsaKvStore::F32 { k, .. } => k.len() / kv_dim,
517            QsaKvStore::Q8Q5 { k, .. } => k.len() / q8_row_bytes(kv_dim),
518        }
519    }
520}
521
522/// Host twin of the device q8_0 quantize warp program (`q4e_quant_q8_block`) — must stay
523/// BIT-IDENTICAL to it (the idxcache seam's contract: host- and device-quantized rows
524/// interleave in one cache), pinned by the tiny gate's quant-twin arm. `lrintf` under the
525/// default rounding mode == `round_ties_even`; the amax fold is order-free (fmaxf over
526/// |x| is associative + commutative); the f16 scale conversion is RNE on both sides.
527fn host_quant_q8_row(row: &[f32], dim: usize, out: &mut Vec<u8>) {
528    for b in 0..dim.div_ceil(32) {
529        let mut amax = 0.0f32;
530        for l in 0..32 {
531            let e = b * 32 + l;
532            let x = if e < dim { row[e] } else { 0.0 };
533            amax = amax.max(x.abs());
534        }
535        let d = amax / 127.0f32;
536        let mut id = if d != 0.0 { 1.0f32 / d } else { 0.0 };
537        // Subnormal-amax guard — mirrors the device kernel (contract totality).
538        if !id.is_finite() {
539            id = 0.0;
540        }
541        out.extend_from_slice(&memra_gguf::nvfp4_repack::f32_to_f16_bits(d).to_le_bytes());
542        for l in 0..32 {
543            let e = b * 32 + l;
544            let x = if e < dim { row[e] } else { 0.0 };
545            let q = ((x * id).round_ties_even() as i32).clamp(-127, 127);
546            out.push(q as i8 as u8);
547        }
548    }
549}
550
551/// Host twin of `q4e_deq_q8` (d single-mul q — one f32 multiply, same bits as the
552/// device `__fmul_rn`).
553fn host_deq_q8_rows(bytes: &[u8], row0: usize, rows: usize, dim: usize, out: &mut Vec<f32>) {
554    let rb = q8_row_bytes(dim);
555    for r in row0..row0 + rows {
556        let row = &bytes[r * rb..(r + 1) * rb];
557        for e in 0..dim {
558            let blk = &row[(e >> 5) * 34..];
559            let d = memra_gguf::dequant::fp16_to_f32(u16::from_le_bytes([blk[0], blk[1]]));
560            let q = blk[2 + (e & 31)] as i8 as f32;
561            out.push(d * q);
562        }
563    }
564}
565
566/// Host twin of the device q5_1 quantize warp program (`q4e_quant_q5_block`); min/max
567/// folds are order-free (fminf/fmaxf associative + commutative), the rest is per-lane.
568fn host_quant_q5_row(row: &[f32], dim: usize, out: &mut Vec<u8>) {
569    for b in 0..dim.div_ceil(32) {
570        let lane = |l: usize| -> f32 {
571            let e = b * 32 + l;
572            if e < dim { row[e] } else { 0.0 }
573        };
574        let mut mn = f32::INFINITY;
575        let mut mx = f32::NEG_INFINITY;
576        for l in 0..32 {
577            mn = mn.min(lane(l));
578            mx = mx.max(lane(l));
579        }
580        let d = (mx - mn) / 31.0f32;
581        let mut id = if d != 0.0 { 1.0f32 / d } else { 0.0 };
582        // Subnormal-amax guard — mirrors the device kernel (contract totality).
583        if !id.is_finite() {
584            id = 0.0;
585        }
586        let q5 = |l: usize| -> u32 {
587            (((lane(l) - mn) * id).round_ties_even() as i32).clamp(0, 31) as u32
588        };
589        let mut qh = 0u32;
590        for l in 0..32 {
591            qh |= ((q5(l) >> 4) & 1) << l;
592        }
593        out.extend_from_slice(&memra_gguf::nvfp4_repack::f32_to_f16_bits(d).to_le_bytes());
594        out.extend_from_slice(&memra_gguf::nvfp4_repack::f32_to_f16_bits(mn).to_le_bytes());
595        out.extend_from_slice(&qh.to_le_bytes());
596        for l in 0..16 {
597            out.push(((q5(l) & 0x0F) | ((q5(l + 16) & 0x0F) << 4)) as u8);
598        }
599    }
600}
601
602/// Host twin of `q4e_deq_q5` (`__fmaf_rn(d, q5, m)` == `f32::mul_add`).
603fn host_deq_q5_rows(bytes: &[u8], row0: usize, rows: usize, dim: usize, out: &mut Vec<f32>) {
604    let rb = q5_row_bytes(dim);
605    for r in row0..row0 + rows {
606        let row = &bytes[r * rb..(r + 1) * rb];
607        for e in 0..dim {
608            let blk = &row[(e >> 5) * 24..];
609            let d = memra_gguf::dequant::fp16_to_f32(u16::from_le_bytes([blk[0], blk[1]]));
610            let m = memra_gguf::dequant::fp16_to_f32(u16::from_le_bytes([blk[2], blk[3]]));
611            let qh = u32::from_le_bytes([blk[4], blk[5], blk[6], blk[7]]);
612            let lane = e & 31;
613            let lo = if lane < 16 {
614                blk[8 + lane] & 0x0F
615            } else {
616                blk[8 + lane - 16] >> 4
617            };
618            let q5 = (lo as u32) | (((qh >> lane) & 1) << 4);
619            out.push(d.mul_add(q5 as f32, m));
620        }
621    }
622}
623
624/// Host twin of the device `__float2bfloat16` RNE conversion (finite domain; the raw
625/// keys are finite projection outputs — NaN handling is not part of the pin).
626fn f32_to_bf16_rne(x: f32) -> u16 {
627    let bits = x.to_bits();
628    let rounding_bias = 0x7fff + ((bits >> 16) & 1);
629    (bits.wrapping_add(rounding_bias) >> 16) as u16
630}
631
632/// Indexer raw-key HOST cache (idxq lane): rows of `idx_dim` keys, stored f32
633/// (historical), q8_0 blocks, or bf16. Consumed ONLY through `rows_f32` into the fp32
634/// mean-pooling — quantize the cache, dequant at read, pooling math identical.
635enum IdxRawCache {
636    F32(Vec<f32>),
637    Q8(Vec<u8>),
638    Bf16(Vec<u16>),
639}
640
641impl IdxRawCache {
642    fn new(mode: IdxQMode) -> Self {
643        match mode {
644            IdxQMode::F32 => IdxRawCache::F32(Vec::new()),
645            IdxQMode::Q8 => IdxRawCache::Q8(Vec::new()),
646            IdxQMode::Bf16 => IdxRawCache::Bf16(Vec::new()),
647        }
648    }
649    fn rows(&self, idx_dim: usize) -> usize {
650        match self {
651            IdxRawCache::F32(v) => v.len() / idx_dim,
652            IdxRawCache::Q8(v) => v.len() / q8_row_bytes(idx_dim),
653            IdxRawCache::Bf16(v) => v.len() / idx_dim,
654        }
655    }
656    fn truncate_rows(&mut self, rows: usize, idx_dim: usize) {
657        match self {
658            IdxRawCache::F32(v) => v.truncate(rows * idx_dim),
659            IdxRawCache::Q8(v) => v.truncate(rows * q8_row_bytes(idx_dim)),
660            IdxRawCache::Bf16(v) => v.truncate(rows * idx_dim),
661        }
662    }
663    /// Append `n` rows given as f32 (host-side quantize twin — bit-identical to the
664    /// device append kernels, so host/device-quantized rows interleave freely).
665    fn append_rows_f32(&mut self, rows: &[f32], n: usize, idx_dim: usize) {
666        match self {
667            IdxRawCache::F32(v) => v.extend_from_slice(&rows[..n * idx_dim]),
668            IdxRawCache::Q8(v) => {
669                for r in 0..n {
670                    host_quant_q8_row(&rows[r * idx_dim..(r + 1) * idx_dim], idx_dim, v);
671                }
672            }
673            IdxRawCache::Bf16(v) => {
674                v.extend(rows[..n * idx_dim].iter().map(|&x| f32_to_bf16_rne(x)));
675            }
676        }
677    }
678    /// Dequant rows [row0, row0+n) to f32 (the pooling read).
679    fn rows_f32(&self, row0: usize, n: usize, idx_dim: usize, out: &mut Vec<f32>) {
680        out.clear();
681        match self {
682            IdxRawCache::F32(v) => out.extend_from_slice(&v[row0 * idx_dim..(row0 + n) * idx_dim]),
683            IdxRawCache::Q8(v) => host_deq_q8_rows(v, row0, n, idx_dim, out),
684            IdxRawCache::Bf16(v) => out.extend(
685                v[row0 * idx_dim..(row0 + n) * idx_dim]
686                    .iter()
687                    .map(|&b| memra_gguf::dequant::bf16_to_f32(b)),
688            ),
689        }
690    }
691}
692
693/// Indexer raw-key DEVICE cache (idxcache seam), format-matched to the host cache.
694/// Bf16 rows live as u16; Q8 rows as q8_0 bytes. The host cache materializes from these
695/// by dtoh VERBATIM (no re-quant), so lazy materialization stays bit-identical.
696enum IdxRawDev {
697    F32(CudaSlice<f32>),
698    Q8(CudaSlice<u8>),
699    Bf16(CudaSlice<u16>),
700}
701
702/// Pay the idxcache lazy-materialization debt: dtoh device rows [host_rows, dev_rows)
703/// into the host cache VERBATIM — format-matched bytes, no re-quant, so the seam's
704/// bit-identity contract holds per format.
705fn idx_materialize_host(
706    e: &Engine,
707    raw_keys: &mut IdxRawCache,
708    raw_dev: &Option<IdxRawDev>,
709    raw_dev_rows: usize,
710    idx_dim: usize,
711) -> Res<()> {
712    let host_rows = raw_keys.rows(idx_dim);
713    if raw_dev_rows <= host_rows {
714        return Ok(());
715    }
716    let m = raw_dev
717        .as_ref()
718        .ok_or("idxcache: rows counted without a cache")?;
719    match (m, raw_keys) {
720        (IdxRawDev::F32(d), IdxRawCache::F32(h)) => {
721            let delta = e.dtoh_view(&d.slice(host_rows * idx_dim..raw_dev_rows * idx_dim))?;
722            h.extend_from_slice(&delta);
723        }
724        (IdxRawDev::Q8(d), IdxRawCache::Q8(h)) => {
725            let rb = q8_row_bytes(idx_dim);
726            let delta = e.dtoh_u8_view(&d.slice(host_rows * rb..raw_dev_rows * rb))?;
727            h.extend_from_slice(&delta);
728        }
729        (IdxRawDev::Bf16(d), IdxRawCache::Bf16(h)) => {
730            let delta = e
731                .gpu
732                .stream()
733                .clone_dtoh(&d.slice(host_rows * idx_dim..raw_dev_rows * idx_dim))?;
734            e.gpu.stream().synchronize()?;
735            h.extend_from_slice(&delta);
736        }
737        _ => return Err("idxcache: device/host raw-key formats disagree".into()),
738    }
739    Ok(())
740}
741
742/// The idxq selection-identity audit twin (instrument): parallel f32 raw/pooled caches
743/// fed from the per-chunk idx_proj dtoh, selection recomputed on host per scored row.
744struct IdxAudit {
745    raw_f32: IdxRawCache, // always the F32 variant
746    pooled_f32: Vec<f32>,
747}
748
749enum MixerState {
750    Qsa {
751        kv: QsaKvStore,
752        /// Indexer RAW key cache — pre-norm, pre-rope, host-resident
753        /// (`update_indexer`, SEMANTICS.md §QSA: 128 dims/token/QSA-layer). Precision
754        /// per the idxq lane (f32 / q8_0 / bf16), latched at alloc.
755        raw_keys: IdxRawCache,
756        /// POOLED indexer key cache — the per-block mean/k_layernorm/rope form the
757        /// scorer consumes, host-resident, one row per COMPLETE block. A block's pooled
758        /// key depends only on its 4 raw keys + its start position, never on the query
759        /// row, so it is computed ONCE (bit-identical to the historical per-row
760        /// recompute: same op order per block) and extended as blocks complete.
761        /// Truncated with `raw_keys` on rewind.
762        pooled_keys: Vec<f32>,
763        /// DEVICE mirror of `pooled_keys` for the device scorer (long-context lane):
764        /// same rows, grown by H2D of the delta as blocks complete. `None` until the
765        /// scorer engages (below the drop point nothing is scored at all).
766        pooled_dev: Option<CudaSlice<f32>>,
767        /// Rows currently mirrored (<= pooled_keys.len()/head_dim).
768        pooled_dev_rows: usize,
769        /// DEVICE raw-key cache (devtwin stage 3, `idxcache` seam): the k-part rows
770        /// appended d2d as chunks land; below the selection horizon `raw_keys` LAGS
771        /// this (the lazy host materialization dtohs the delta at the first scored
772        /// chunk). Row r here is absolute cache row r — rewind clamps `raw_dev_rows`
773        /// alongside the host truncation.
774        raw_dev: Option<IdxRawDev>,
775        /// Rows valid in `raw_dev` (>= raw_keys rows while the seam is on).
776        raw_dev_rows: usize,
777        /// idxq selection-identity audit twin (instrument, `MEMRA_Q4E_IDXQ_AUDIT=1`).
778        idx_audit: Option<Box<IdxAudit>>,
779    },
780    Gdn {
781        conv: CudaSlice<f32>,  // [pad, conv_dim] raw pre-conv qkv history rows
782        state: CudaSlice<f32>, // [nv, hv, hk] recurrent matrix (reference layout)
783    },
784}
785
786struct LayerState {
787    mixer: MixerState,
788    ple: Option<PleState>,
789}
790
791/// Per-GDN-layer verify-chunk stash (mtp-spec lane): per-column recurrent snapshots +
792/// the chunk's conv-rewind inputs. Sized once at `spec_arm` (k_cap columns).
793struct GdnStash {
794    /// [k_cap, nv*hv*hk] — recurrent state AFTER column i (D2D snapshot per column).
795    states: CudaSlice<f32>,
796    /// [pad, conv_dim] — pre-chunk conv history (rewind rebuild input).
797    conv_pre: CudaSlice<f32>,
798    /// [k_cap, conv_dim] — the chunk's raw pre-conv qkv rows (rewind rebuild input).
799    qkv_rows: CudaSlice<f32>,
800    /// Verify SCAN-CHAIN segment graph (mtp9, `set_verify_graphs`): dwconv + the t
801    /// per-column {scan step, state snapshot} launches + the conv-history roll, captured
802    /// at ONE chunk width. The chain is serially DEPENDENT (every column reads and writes
803    /// the recurrent state), so each launch's issue latency is fully exposed — this is the
804    /// densest all-device launch run in the verify chunk (t=6: 14 launches x 36 GDN
805    /// layers). `Some((t, graph))`; a chunk at a different t invalidates it.
806    scan_graph: Option<(usize, GraphEntry)>,
807    /// Chunk widths already WARMED at: the first chunk of a width runs eager so every
808    /// workspace slot is allocated and parked outside the capture region (allocations
809    /// inside a capture become graph mem nodes — the trunk's draft-graph lesson).
810    scan_warm: Option<usize>,
811}
812
813/// Per-PLE-layer verify-chunk stash: pre-chunk conv history + the chunk's normed
814/// gated-value rows, per stream.
815struct PleStash {
816    hist_pre: Vec<CudaSlice<f32>>,    // per stream [pad_ple, hidden]
817    normed_rows: Vec<CudaSlice<f32>>, // per stream [k_cap, hidden]
818}
819
820/// The verify-chunk instrument (mtp-spec lane). Armed by `spec_arm`; while armed,
821/// every forward captures the trunk's FINAL WIDE rows at their absolute positions
822/// (the draft's hidden seeds) and every 1 < t <= k_cap chunk (a) runs the EXACT row
823/// programs (each row bit-identical to the t == 1 decode program — the spec
824/// byte-identity contract) and (b) stashes per-column GDN/PLE state so
825/// `verify_rewind` can drop rejected columns without replay.
826pub struct VerifyStash {
827    k_cap: usize,
828    /// The live chunk (base_pos, t) — set by the last exact chunk, consumed by rewind.
829    chunk: Option<(usize, usize)>,
830    gdn: Vec<Option<GdnStash>>,
831    ple: Vec<Option<PleStash>>,
832    /// Trunk final wide rows, RING-slotted: absolute row r lives at slot
833    /// `r % ring_rows`. `ring_rows == capacity` (the `spec_arm` default) is the
834    /// historical whole-history layout; the long-context arm (`spec_arm_ring`) bounds it
835    /// (see that doc for the freshness contract).
836    wide: CudaSlice<f32>,
837    ring_rows: usize,
838    /// Card-1 mirror of `wide` (mtp10 dev1 draft placement): the draft's hidden seeds,
839    /// P2P-copied row-range by row-range (prefill once, then (a+1) rows per round).
840    /// Allocated lazily by `spec_generate` when the draft engine is a different card.
841    wide_dev1: Option<CudaSlice<f32>>,
842    /// Per-row argmax of the last exact chunk (device argmax, 4t-byte dtoh).
843    argmax: Vec<u32>,
844    /// Device argmax staging [k_cap].
845    toks: CudaSlice<u32>,
846    /// Skip the [t, vocab] logits dtoh on exact chunks and fill `argmax` instead
847    /// (forward returns an EMPTY vec in that mode — the spec loop's fast path).
848    want_argmax: bool,
849    /// Extend the argmax fast path to t == 1 forwards (mtp11 deferred round): the
850    /// zero-draft verify and the dynk plain tail commit a device argmax + 4-byte dtoh
851    /// instead of the full [1, vocab] row + host scan (bit-identical token by the
852    /// argmax-gate contract). Only honored with `want_argmax` (greedy non-trace).
853    want_argmax_t1: bool,
854    /// Big (t > k_cap, i.e. prefill) forwards dtoh only the LAST logits row (mtp11):
855    /// the spec loop consumes exactly one row for x0, and the full block is ~1 MB/row.
856    /// Exact chunks and t == 1 steps are untouched (sampled verify samples EVERY row).
857    last_row_only: bool,
858}
859
860pub struct Qwen4ExpState {
861    pos: usize,
862    capacity: usize,
863    /// Workspace-slot reserve unit (tokens). Equals `capacity` from `alloc_state` (the
864    /// historical behavior: one allocation serves the largest possible chunk); a
865    /// long-context state (`alloc_state_reserve`) caps it at the CHUNK bound so a
866    /// 1M-capacity state does not reserve 1M-token transients. Forwards longer than
867    /// this still work (slots grow), they just reallocate.
868    reserve: usize,
869    /// Full token history (host). PLE n-gram hashing needs the EOS-segment structure of
870    /// the whole context (reference `shift_right_ignore_eos`), and eager memory cost is
871    /// 4 B/token.
872    tokens: Vec<u32>,
873    layers: Vec<LayerState>,
874    /// Named-slot step workspace (perf lane item 2a — see `StepPool`).
875    ws: StepPool,
876    /// Captured decode-step graphs (perf lane item 2b — see `StepGraphs`).
877    graphs: StepGraphs,
878    /// TP2 half-state (perf round 3). `Some` after the first `decode_step_tp2`: the
879    /// single-card mixer state is migrated into per-card halves and goes STALE — a
880    /// TP2-touched state refuses single-card forwards (fresh state per mode; the A/B
881    /// harness allocates per arm).
882    tp2: Option<Tp2State>,
883    /// Verify-chunk stash (mtp-spec lane), armed by `spec_arm`.
884    verify: Option<VerifyStash>,
885}
886
887/// Named-slot device workspace for the forward step (perf lane item 2a: PROFILE-0
888/// counted 11,366 pooled allocs + 1,685 memsets per token; 2,234 allocs remained after
889/// round 1). Every step-transient buffer is TAKEN from a named slot and PUT back at its
890/// last use; with the seam ON (`set_step_ws`, default per receipts) the same CudaSlice —
891/// and therefore the same device ADDRESS — serves every step, which both removes the
892/// cuMemAllocAsync/FreeAsync churn and is the address-stability prerequisite for CUDA
893/// graph capture (item 2b). With the seam OFF every take allocates fresh and every put
894/// drops — byte-identical to the prior pooled-alloc behavior, the A/B twin. A slot is
895/// allocated at `reserve` elements on first take (capacity-derived at the call sites)
896/// so a growing shape (the decode mask) never reallocates mid-run.
897#[derive(Default)]
898struct StepPool {
899    f32s: std::collections::BTreeMap<&'static str, CudaSlice<f32>>,
900    i32s: std::collections::BTreeMap<&'static str, CudaSlice<i32>>,
901    u8s: std::collections::BTreeMap<&'static str, CudaSlice<u8>>,
902    u64s: std::collections::BTreeMap<&'static str, CudaSlice<u64>>,
903}
904
905/// Per-stream slot names (hc_count is 4 on the artifact, 2 on the tiny plan; the loader
906/// refuses streams > 8).
907/// TP2-prefill exit slots: the last row of each plane, copied into t == 1 buffers so
908/// the decode exit segment runs unchanged on a chunk's final row.
909const EXIT_PLANE_SLOTS: [&str; 8] = [
910    "exit.p0", "exit.p1", "exit.p2", "exit.p3", "exit.p4", "exit.p5", "exit.p6", "exit.p7",
911];
912const PLANE_SLOTS: [&str; 8] = [
913    "plane.0", "plane.1", "plane.2", "plane.3", "plane.4", "plane.5", "plane.6", "plane.7",
914];
915const INJECT_SLOTS: [&str; 8] = [
916    "hc.inj.0", "hc.inj.1", "hc.inj.2", "hc.inj.3", "hc.inj.4", "hc.inj.5", "hc.inj.6", "hc.inj.7",
917];
918
919impl StepPool {
920    fn take_f32(
921        &mut self,
922        e: &Engine,
923        name: &'static str,
924        len: usize,
925        reserve: usize,
926    ) -> Res<CudaSlice<f32>> {
927        if step_ws_on() {
928            if let Some(buf) = self.f32s.remove(name) {
929                if buf.len() >= len {
930                    return Ok(buf);
931                }
932            }
933            e.uninit(len.max(reserve))
934        } else {
935            e.uninit(len)
936        }
937    }
938
939    fn put_f32(&mut self, name: &'static str, buf: CudaSlice<f32>) {
940        if step_ws_on() {
941            self.f32s.insert(name, buf);
942        }
943    }
944
945    fn take_i32(
946        &mut self,
947        e: &Engine,
948        name: &'static str,
949        host: &[i32],
950        reserve: usize,
951    ) -> Res<CudaSlice<i32>> {
952        if step_ws_on() {
953            let mut buf = match self.i32s.remove(name) {
954                Some(buf) if buf.len() >= host.len() => buf,
955                _ => e.alloc_uninit::<i32>(host.len().max(reserve))?,
956            };
957            let mut view = buf.slice_mut(0..host.len());
958            e.gpu.stream().memcpy_htod(host, &mut view)?;
959            Ok(buf)
960        } else {
961            e.htod_i32(host)
962        }
963    }
964
965    fn put_i32(&mut self, name: &'static str, buf: CudaSlice<i32>) {
966        if step_ws_on() {
967            self.i32s.insert(name, buf);
968        }
969    }
970
971    /// Take an i32 slot WITHOUT uploading (device router: contents arrive from the
972    /// `qwen4exp_route_topk_f32` launch — the take_u8 discipline for i32).
973    fn take_i32_slot(
974        &mut self,
975        e: &Engine,
976        name: &'static str,
977        len: usize,
978        reserve: usize,
979    ) -> Res<CudaSlice<i32>> {
980        if step_ws_on() {
981            if let Some(buf) = self.i32s.remove(name) {
982                if buf.len() >= len {
983                    return Ok(buf);
984                }
985            }
986        }
987        e.alloc_uninit::<i32>(len.max(reserve))
988    }
989
990    fn take_f32_h2d(
991        &mut self,
992        e: &Engine,
993        name: &'static str,
994        host: &[f32],
995        reserve: usize,
996    ) -> Res<CudaSlice<f32>> {
997        if step_ws_on() {
998            let mut buf = match self.f32s.remove(name) {
999                Some(buf) if buf.len() >= host.len() => buf,
1000                _ => e.uninit(host.len().max(reserve))?,
1001            };
1002            let mut view = buf.slice_mut(0..host.len());
1003            e.gpu.stream().memcpy_htod(host, &mut view)?;
1004            Ok(buf)
1005        } else {
1006            e.htod(host)
1007        }
1008    }
1009
1010    fn take_u8_h2d(
1011        &mut self,
1012        e: &Engine,
1013        name: &'static str,
1014        host: &[u8],
1015        reserve: usize,
1016    ) -> Res<CudaSlice<u8>> {
1017        if step_ws_on() {
1018            let mut buf = match self.u8s.remove(name) {
1019                Some(buf) if buf.len() >= host.len() => buf,
1020                _ => e.alloc_u8_uninit(host.len().max(reserve))?,
1021            };
1022            let mut view = buf.slice_mut(0..host.len());
1023            e.gpu.stream().memcpy_htod(host, &mut view)?;
1024            Ok(buf)
1025        } else {
1026            e.htod_bytes(host)
1027        }
1028    }
1029
1030    fn put_u8(&mut self, name: &'static str, buf: CudaSlice<u8>) {
1031        if step_ws_on() {
1032            self.u8s.insert(name, buf);
1033        }
1034    }
1035
1036    /// Take a u8 slot WITHOUT uploading (TP2 pack blobs: contents arrive via
1037    /// `upsert_u8` before the consuming segment runs/replays).
1038    fn take_u8(
1039        &mut self,
1040        e: &Engine,
1041        name: &'static str,
1042        len: usize,
1043        reserve: usize,
1044    ) -> Res<CudaSlice<u8>> {
1045        if step_ws_on() {
1046            if let Some(buf) = self.u8s.remove(name) {
1047                if buf.len() >= len {
1048                    return Ok(buf);
1049                }
1050            }
1051        }
1052        e.alloc_u8_uninit(len.max(reserve))
1053    }
1054
1055    /// H2D into a PARKED u8 slot, seeding it on first use (the write_i32 discipline
1056    /// with a bootstrap arm — a captured graph bakes the slot address, so after the
1057    /// first take the buffer must never rebind).
1058    fn upsert_u8(
1059        &mut self,
1060        e: &Engine,
1061        name: &'static str,
1062        host: &[u8],
1063        reserve: usize,
1064    ) -> Res<()> {
1065        if !self.u8s.contains_key(name) {
1066            let buf = self.take_u8(e, name, host.len(), reserve)?;
1067            self.put_u8(name, buf);
1068        }
1069        let buf = self
1070            .u8s
1071            .get_mut(name)
1072            .ok_or_else(|| format!("step workspace: slot {name} is not parked"))?;
1073        if buf.len() < host.len() {
1074            return Err(format!("step workspace: slot {name} is too small").into());
1075        }
1076        let mut view = buf.slice_mut(0..host.len());
1077        e.gpu.stream().memcpy_htod(host, &mut view)?;
1078        Ok(())
1079    }
1080
1081    /// Borrow a parked u8 slot without removing it (graph segments read the pack blob
1082    /// a driver upsert wrote).
1083    fn peek_u8(&self, name: &'static str) -> Res<&CudaSlice<u8>> {
1084        self.u8s
1085            .get(name)
1086            .ok_or_else(|| format!("step workspace: slot {name} is not parked").into())
1087    }
1088
1089    fn take_u64_h2d(
1090        &mut self,
1091        e: &Engine,
1092        name: &'static str,
1093        host: &[u64],
1094        reserve: usize,
1095    ) -> Res<CudaSlice<u64>> {
1096        if step_ws_on() {
1097            let mut buf = match self.u64s.remove(name) {
1098                Some(buf) if buf.len() >= host.len() => buf,
1099                _ => e.alloc_uninit::<u64>(host.len().max(reserve))?,
1100            };
1101            let mut view = buf.slice_mut(0..host.len());
1102            e.gpu.stream().memcpy_htod(host, &mut view)?;
1103            Ok(buf)
1104        } else {
1105            e.htod_u64(host)
1106        }
1107    }
1108
1109    fn put_u64(&mut self, name: &'static str, buf: CudaSlice<u64>) {
1110        if step_ws_on() {
1111            self.u64s.insert(name, buf);
1112        }
1113    }
1114
1115    /// Borrow a parked slot without removing it (graph driver: the router logits dtoh
1116    /// reads the slot a captured graph wrote).
1117    fn peek_f32(&self, name: &'static str) -> Res<&CudaSlice<f32>> {
1118        self.f32s
1119            .get(name)
1120            .ok_or_else(|| format!("step workspace: slot {name} is not parked").into())
1121    }
1122
1123    /// H2D into an EXISTING slot in place (graph driver: per-step routing inputs into
1124    /// the addresses the captured graph baked). Errors if the slot is missing or short —
1125    /// a captured graph must never silently rebind.
1126    fn write_i32(&mut self, e: &Engine, name: &'static str, host: &[i32]) -> Res<()> {
1127        let buf = self
1128            .i32s
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    fn write_f32(&mut self, e: &Engine, name: &'static str, host: &[f32]) -> Res<()> {
1140        let buf = self
1141            .f32s
1142            .get_mut(name)
1143            .ok_or_else(|| format!("step workspace: slot {name} is not parked"))?;
1144        if buf.len() < host.len() {
1145            return Err(format!("step workspace: slot {name} is too small").into());
1146        }
1147        let mut view = buf.slice_mut(0..host.len());
1148        e.gpu.stream().memcpy_htod(host, &mut view)?;
1149        Ok(())
1150    }
1151}
1152
1153/// Captured decode-step graphs (perf lane item 2b). Layer graphs bake the workspace
1154/// slot ADDRESSES (StepPool, item 2a), the state buffers, and the resident weights, so
1155/// they live beside the state they were captured against. `a[l]` = the device-only
1156/// layer interior (attn read gate → GDN mixer → write → mlp read gate) for GDN layers
1157/// without a PLE block; `b[l]` = the grouped-MoE tail (sel matvecs → shared expert →
1158/// mlp write) for all-NVFP4 layers; `exit` = exit mixer + lm head. QSA layers keep
1159/// their eager interior (the indexer host twin + mask h2d live there). Capture is
1160/// no-warmup (`capture_graph_retained_nowarm`): stream capture enqueues WITHOUT
1161/// executing, and the step's side effects (GDN state/conv advance, plane writes) must
1162/// not run twice.
1163#[derive(Default)]
1164struct StepGraphs {
1165    /// The first graph-eligible decode step runs EAGER to warm every slot (allocations
1166    /// inside a capture region become graph mem nodes — the draft-graph lesson).
1167    warm: bool,
1168    a: Vec<Option<GraphEntry>>,
1169    b: Vec<Option<GraphEntry>>,
1170    exit: Option<GraphEntry>,
1171}
1172
1173type GraphEntry = (
1174    cudarc::driver::CudaGraph,
1175    Vec<Box<dyn std::any::Any + Send>>,
1176);
1177
1178impl Qwen4ExpState {
1179    pub fn position(&self) -> usize {
1180        self.pos
1181    }
1182}
1183
1184/// Per-layer parity capture from a prefill — mirrors the transformers hidden-goldens
1185/// hook points (`make-goldens.py`): decoder-layer outputs on the WIDE stream and the
1186/// exit `hyper_connection_mixer` output.
1187pub struct PrefillCapture {
1188    /// One entry per trunk layer: post-layer wide rows, token-major [t, streams*hidden].
1189    pub layer_wide: Vec<Vec<f32>>,
1190    /// Exit mixer output [t, hidden].
1191    pub exit_mixed: Vec<f32>,
1192}
1193
1194// ---------------------------------------------------------------- profiling (perf lane)
1195
1196/// Wall-clock section profiler for the eager forward (perf lane:
1197/// research/qwen4exp-bringup-20260829/perf/). Disabled (default) the wrappers are
1198/// zero-cost passthroughs; enabled, every section boundary synchronizes the stream so a
1199/// section's time covers everything it queued. Synchronization itself distorts the step
1200/// total — the receipt therefore always banks the UNPROFILED warm ms/token beside the
1201/// profiled table and reads shares, not absolutes, from the latter.
1202pub mod prof {
1203    use std::cell::RefCell;
1204    use std::collections::BTreeMap;
1205
1206    thread_local! {
1207        static STATE: RefCell<Option<BTreeMap<&'static str, (f64, u64)>>> =
1208            const { RefCell::new(None) };
1209    }
1210
1211    /// Start accumulating (resets any previous accumulation).
1212    pub fn enable() {
1213        STATE.with(|s| *s.borrow_mut() = Some(BTreeMap::new()));
1214    }
1215
1216    pub fn on() -> bool {
1217        STATE.with(|s| s.borrow().is_some())
1218    }
1219
1220    /// Drain the accumulated rows (section, total_seconds, calls) and disable.
1221    pub fn take() -> Vec<(&'static str, f64, u64)> {
1222        STATE.with(|s| {
1223            s.borrow_mut()
1224                .take()
1225                .map(|map| map.into_iter().map(|(k, (t, c))| (k, t, c)).collect())
1226                .unwrap_or_default()
1227        })
1228    }
1229
1230    pub(super) fn add(name: &'static str, seconds: f64) {
1231        STATE.with(|s| {
1232            if let Some(map) = s.borrow_mut().as_mut() {
1233                let entry = map.entry(name).or_insert((0.0, 0));
1234                entry.0 += seconds;
1235                entry.1 += 1;
1236            }
1237        });
1238    }
1239}
1240
1241/// Grouped selected-experts decode path (attack (a) of the perf lane). Default ON —
1242/// better-wins-by-default with the interleaved A/B receipts in
1243/// research/qwen4exp-bringup-20260829/perf/; the per-expert path stays as the prefill
1244/// executor, the non-NVFP4 arm, and the A/B twin. Flipped per-arm by the gate binary.
1245static MOE_SEL_PATH: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1246
1247pub fn set_moe_sel_path(on: bool) {
1248    MOE_SEL_PATH.store(on, std::sync::atomic::Ordering::Relaxed);
1249}
1250
1251fn moe_sel_path_on() -> bool {
1252    MOE_SEL_PATH.load(std::sync::atomic::Ordering::Relaxed)
1253}
1254
1255/// Fused hyper-connection read gate (attack (c)). Default ON with the interleaved A/B
1256/// receipts in the perf lane; the unfused chain stays as the A/B twin (`gate_read_legacy`)
1257/// and as the readable statement of the reference program.
1258static HC_FUSED_GATE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1259
1260pub fn set_hc_fused_gate(on: bool) {
1261    HC_FUSED_GATE.store(on, std::sync::atomic::Ordering::Relaxed);
1262}
1263
1264fn hc_fused_gate_on() -> bool {
1265    HC_FUSED_GATE.load(std::sync::atomic::Ordering::Relaxed)
1266}
1267
1268/// bf16 trunk residency (perf lane item: PROFILE-1 residual §2 — gdn.proj/qsa.proj/
1269/// lm_head/gate GEMVs are memory-bound on f32 trunk weights at ~1.3 TB/s). Dense trunk
1270/// mats keep their f32 residency AND gain a bf16 twin when (a) every value is exactly
1271/// bf16-representable (true for BF16 checkpoints — dequant was exact, so the twin equals
1272/// the artifact bytes) and (b) in_f % 8 == 0 (the matvec kernel's uint4 vector width) —
1273/// geometry/value guards, never policy. Default ON with the interleaved A/B receipts in
1274/// research/qwen4exp-bringup-20260829/perf/PROFILE-2.md; the f32 cuBLASLt path stays
1275/// resident as the A/B twin (`--ab-seam trunk`) and the fallback for guarded tensors.
1276static TRUNK_BF16: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1277
1278pub fn set_trunk_bf16(on: bool) {
1279    TRUNK_BF16.store(on, std::sync::atomic::Ordering::Relaxed);
1280}
1281
1282fn trunk_bf16_on() -> bool {
1283    TRUNK_BF16.load(std::sync::atomic::Ordering::Relaxed)
1284}
1285
1286/// INSTRUMENT-ONLY: run a `HeadMode::All` single-card forward on the GROUPED MoE executor
1287/// instead of the per-expert one.
1288///
1289/// **Default OFF, and that is a decision with a reason, not an implementation accident.**
1290/// OFF is byte-for-byte today's behavior: `HeadMode::All` selects the per-expert executor,
1291/// which is the reference-shaped program the goldens capture and every hidden/greedy
1292/// exactness receipt in this lane rest on. Flipping the default would silently re-base
1293/// every one of those receipts, so OFF is the only safe default and there is no perf
1294/// argument on the other side (the per-expert path is the SLOW one — see the executor
1295/// comment at the `grouped` selection).
1296///
1297/// ON exists for exactly one caller: the TP2-prefill CLASS gate's PRIME regime. That regime
1298/// compares an all-rows single-card forward against an all-rows TP2 forward, and TP2's
1299/// `tp2_moe_rows` is grouped on both cards. With this flag OFF the comparison therefore
1300/// straddles TWO independent variables — the TP2 expert-half split AND the
1301/// grouped-vs-per-expert executor difference — and the executor term DOMINATES: measured on
1302/// this artifact, grouped-vs-grouped lands at 1.4e-5 while per-expert-vs-grouped lands at
1303/// 2e-3..4e-3, and the tiny gate's own `prefill-extend` arm prices the executor difference
1304/// alone at 1.865e-4 on a fixture. A band calibrated against the straddled number would be
1305/// ~100x too loose for the question the gate is asking, which is the same "calibrated
1306/// against nothing" failure the two-regime gate was written to end.
1307///
1308/// It is an instrument, not a serving seam: nothing in a serving path reads it, and
1309/// long-context prefill already rides the grouped program through `HeadMode::LastRow`.
1310static PREFILL_GROUPED_ALL: std::sync::atomic::AtomicBool =
1311    std::sync::atomic::AtomicBool::new(false);
1312
1313pub fn set_prefill_grouped_all(on: bool) {
1314    PREFILL_GROUPED_ALL.store(on, std::sync::atomic::Ordering::Relaxed);
1315}
1316
1317fn prefill_grouped_all_on() -> bool {
1318    PREFILL_GROUPED_ALL.load(std::sync::atomic::Ordering::Relaxed)
1319}
1320
1321/// Allocation-stable decode step (perf lane item 2a — see `StepPool`). Default ON with
1322/// the interleaved A/B receipts in PROFILE-2.md; OFF reproduces the pooled-alloc
1323/// behavior exactly (`--ab-seam ws`).
1324static STEP_WS: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1325
1326pub fn set_step_ws(on: bool) {
1327    STEP_WS.store(on, std::sync::atomic::Ordering::Relaxed);
1328}
1329
1330fn step_ws_on() -> bool {
1331    STEP_WS.load(std::sync::atomic::Ordering::Relaxed)
1332}
1333
1334/// Decode-step CUDA graphs (perf lane item 2b — see `StepGraphs`). Replay is
1335/// bit-identical to the ws-eager path by construction (same kernels, same launch
1336/// parameters, same baked addresses, same order — only the CPU issue path changes), so
1337/// the graph A/B's rep-0 chains must be IDENTICAL, a stronger bar than the
1338/// accumulation-class seams. Requires the step workspace (item 2a); disabled while the
1339/// section profiler is on (sync boundaries cannot cross a replay) and during prefill
1340/// capture. Default ON with the PROFILE-2.md receipts; `--ab-seam graph`.
1341static DECODE_GRAPHS: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1342
1343pub fn set_decode_graphs(on: bool) {
1344    DECODE_GRAPHS.store(on, std::sync::atomic::Ordering::Relaxed);
1345}
1346
1347fn decode_graphs_on() -> bool {
1348    DECODE_GRAPHS.load(std::sync::atomic::Ordering::Relaxed)
1349}
1350
1351/// VERIFY scan-chain segment graphs (mtp9): the spec verify chunk's per-GDN-layer
1352/// {dwconv, t x (scan step + state snapshot), conv-history roll} run, captured once per
1353/// chunk width and replayed. Replay is bit-identical to the eager chain BY CONSTRUCTION
1354/// (same kernels, same launch parameters, same baked addresses, same order — only the CPU
1355/// issue path changes), so `--verify-bit-gate` must stay 24/24 and `--spec-gate` byte
1356/// identity must hold; those are the gates, not a tolerance.
1357///
1358/// **Default OFF, deliberately** (new-flags law): the trunk's own decode-graph receipt on
1359/// this box is +1.3% for an 84-graph, 2,400-launch reduction (PROFILE-2.md), so launch
1360/// issue is mostly overlapped here and the expected value is small. This seam exists to
1361/// MEASURE the one case the trunk receipt does not cover — a serially dependent chain,
1362/// where issue latency cannot overlap — and it flips only on its own interleaved A/B.
1363/// Requires the step workspace (address stability) and no section profiler (sync
1364/// boundaries cannot cross a replay).
1365static VERIFY_GRAPHS: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
1366
1367pub fn set_verify_graphs(on: bool) {
1368    VERIFY_GRAPHS.store(on, std::sync::atomic::Ordering::Relaxed);
1369}
1370
1371fn verify_graphs_on() -> bool {
1372    VERIFY_GRAPHS.load(std::sync::atomic::Ordering::Relaxed)
1373}
1374
1375/// v2 grouped sel matvec (perf lane item 3: PROFILE-1 residual §3 — the v1 kernel sits
1376/// at ~225-275 GB/s, scalar byte loads). Default ON with the PROFILE-2.md receipts; v1
1377/// stays the fallback for guarded geometry and the A/B twin (`--ab-seam selv2`).
1378/// NOTE: flipping this invalidates nothing structurally, but captured decode graphs
1379/// bake the kernel choice — the A/B harness allocates a fresh state per arm.
1380static SEL_V2: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1381
1382pub fn set_sel_v2(on: bool) {
1383    SEL_V2.store(on, std::sync::atomic::Ordering::Relaxed);
1384}
1385
1386fn sel_v2_on() -> bool {
1387    SEL_V2.load(std::sync::atomic::Ordering::Relaxed)
1388}
1389
1390/// v3 grouped sel matvec (perf round 3: PROFILE-2 residual — v2 sits at ~340-420 GB/s;
1391/// at the artifact's down geometry a v2 thread runs at most ONE strided iteration, so
1392/// the warp has almost no memory-level parallelism). v3 = 4 rows/warp sharing the
1393/// activation registers. Default ON with the round-3 receipts
1394/// (perf/ab-selv3-nvfp4.tsv: interleaved ×5, 17.06 → 16.57 ms mean-of-means, rep-0
1395/// chains identical); v2 stays the fallback for guarded geometry (out_f % 4 != 0) and
1396/// the A/B twin (`--ab-seam selv3`).
1397pub const SEL_V3_DEFAULT: bool = true;
1398static SEL_V3: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(SEL_V3_DEFAULT);
1399
1400pub fn set_sel_v3(on: bool) {
1401    SEL_V3.store(on, std::sync::atomic::Ordering::Relaxed);
1402}
1403
1404fn sel_v3_on() -> bool {
1405    SEL_V3.load(std::sync::atomic::Ordering::Relaxed)
1406}
1407
1408/// Read/write-gate micro bundle (perf lane, after items 1-3 the residue is EXECUTION):
1409/// batched per-stream gate norms (384 one-block launches → 96 stream-batched), the
1410/// two-stage inject (the single-stage kernel ran 4 blocks on a 188-SM card), slab gate
1411/// writes (kills 384 add_scaled_rows + 384 inject-row d2d copies per token), and bf16
1412/// residency for the shared-expert mats (~2.5 GB/token of f32 reads). Default ON with
1413/// the PROFILE-2.md receipts; OFF is the exact item-3-era composition (`--ab-seam
1414/// hcmicro`).
1415static HC_MICRO: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1416
1417pub fn set_hc_micro(on: bool) {
1418    HC_MICRO.store(on, std::sync::atomic::Ordering::Relaxed);
1419}
1420
1421fn hc_micro_on() -> bool {
1422    HC_MICRO.load(std::sync::atomic::Ordering::Relaxed)
1423}
1424
1425/// GDN decode-step scan twin (perf round 3: PROFILE-2 residual — `gdn_scan_naive_f32`
1426/// at t=1 runs `nv` blocks (48) with the whole state row per thread in registers,
1427/// latency-bound). The twin launches grid (nv, hv) with one state ELEMENT per thread;
1428/// same per-element math, block reduction trees instead of sequential row sums — the
1429/// accumulation class, gated by `gate_gdn_step_kernels` + the real gates. Default ON
1430/// with the round-3 receipts (perf/ab-gdnstep-nvfp4.tsv: interleaved ×5, 16.59 → 15.60
1431/// ms mean-of-means, rep-0 chains identical); the naive kernel stays the prefill
1432/// executor, the tiny-geometry fallback (hk % 32 != 0), and the A/B twin
1433/// (`--ab-seam gdnstep`).
1434pub const GDN_STEP_DEFAULT: bool = true;
1435static GDN_STEP: std::sync::atomic::AtomicBool =
1436    std::sync::atomic::AtomicBool::new(GDN_STEP_DEFAULT);
1437
1438pub fn set_gdn_step(on: bool) {
1439    GDN_STEP.store(on, std::sync::atomic::Ordering::Relaxed);
1440}
1441
1442fn gdn_step_on() -> bool {
1443    GDN_STEP.load(std::sync::atomic::Ordering::Relaxed)
1444}
1445
1446/// GDN norm+gate fusion (perf round 3): `rms_sigmul_f32` folds the mixer's rms_norm +
1447/// sigmoid + mul chain into one launch — rms_norm_f32-verbatim reduction, sigmoid_f32
1448/// gate, no contraction seam, so BIT-IDENTICAL to the chain (asserted exactly by
1449/// `gate_gdn_step_kernels`). Sigmoid gate arm only; Silu keeps the chain. Default ON
1450/// with the round-3 receipts (perf/ab-gdnfuse-nvfp4.tsv: interleaved ×5, 16.65 → 16.52
1451/// ms mean-of-means, rep-0 chains identical; small but real, and the kernel is
1452/// bit-identical to the chain it replaces); `--ab-seam gdnfuse`.
1453pub const GDN_FUSE_DEFAULT: bool = true;
1454static GDN_FUSE: std::sync::atomic::AtomicBool =
1455    std::sync::atomic::AtomicBool::new(GDN_FUSE_DEFAULT);
1456
1457pub fn set_gdn_fuse(on: bool) {
1458    GDN_FUSE.store(on, std::sync::atomic::Ordering::Relaxed);
1459}
1460
1461fn gdn_fuse_on() -> bool {
1462    GDN_FUSE.load(std::sync::atomic::Ordering::Relaxed)
1463}
1464
1465/// Projection stack (perf round 4): same-activation trunk projections that ran as
1466/// separate `qmatvec_bf16w_f32` launches — GDN qkv/z/beta/alpha (4), QSA wq/wk/wv (3),
1467/// shared-expert gate/up (2) — collapse into ONE `qmatvec_bf16w_multi4_f32` launch over
1468/// a load-time row-stacked bf16 twin, each output row routed to its original slot buffer
1469/// by row range. Per-row math is the bf16w kernel VERBATIM, so outputs are BIT-IDENTICAL
1470/// to the per-mat launches; decode only (t == 1), requires the bf16 trunk seam. Default
1471/// ON with the round-4 receipts (perf20/ab-projstack-nvfp4.tsv: interleaved x5,
1472/// 15.72 -> 15.25 ms mean-of-means, rep-0 chains IDENTICAL; tiny gate ON/OFF receipts
1473/// byte-identical; real gate r4-on: argmax 10/10, greedy forks unchanged, tp2-gate
1474/// 24/24); the per-mat row-offset-view launches stay the OFF arm; `--ab-seam projstack`.
1475pub const PROJ_STACK_DEFAULT: bool = true;
1476static PROJ_STACK: std::sync::atomic::AtomicBool =
1477    std::sync::atomic::AtomicBool::new(PROJ_STACK_DEFAULT);
1478
1479pub fn set_proj_stack(on: bool) {
1480    PROJ_STACK.store(on, std::sync::atomic::Ordering::Relaxed);
1481}
1482
1483fn proj_stack_on() -> bool {
1484    PROJ_STACK.load(std::sync::atomic::Ordering::Relaxed)
1485}
1486
1487/// Hyper-gate diet (perf round 4): the read gate's 7-launch serial chain (norm, batched
1488/// down GEMV, lowrank reduce, batched up GEMV, mix epilogue, inject partials + reduce)
1489/// re-fuses into THREE launches at t == 1 — stage 1 (per-stream RMS recompute + normed
1490/// smem row + down/inject rows), stage 2 (silu mean + inject sigmoid), stage 3 (up dots
1491/// + mix epilogue from the stage-1 inv scalars). ACCUMULATION CLASS (new reduce widths);
1492/// gated by `gate_hc_diet_kernels` (real geometry vs the classic fused chain) + the real
1493/// gates. Requires the bf16 trunk twins + hcmicro inject posture (the Slab inject form);
1494/// geometry guards hidden % 8 == 0 && rank % 8 == 0 (tiny plans fall back). Default ON
1495/// with the round-4 receipts (perf20/ab-hcdiet-nvfp4.tsv: interleaved x5, 15.69 ->
1496/// 15.32 ms mean-of-means, rep-0 chains IDENTICAL; oracle arm 0e worst rel 2.369e-6;
1497/// real gate r4-on: argmax 10/10, greedy forks unchanged, tp2-gate 24/24); the fused
1498/// chain stays the OFF arm; `--ab-seam hcdiet`.
1499pub const HC_DIET_DEFAULT: bool = true;
1500static HC_DIET: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(HC_DIET_DEFAULT);
1501
1502pub fn set_hc_diet(on: bool) {
1503    HC_DIET.store(on, std::sync::atomic::Ordering::Relaxed);
1504}
1505
1506fn hc_diet_on() -> bool {
1507    HC_DIET.load(std::sync::atomic::Ordering::Relaxed)
1508}
1509
1510/// Fused gate+up+silu sel matvec (perf round 4, post the W4A4 owner retirement — the
1511/// activation-precision-NEUTRAL half of the sel lever): the MoE tail's gate launch +
1512/// up launch + silu launch collapse into ONE `qmatvec_nvfp4_modelopt_sel_gu_silu_f32`
1513/// (each warp runs 4 gate + 4 up rows off shared f32 activation registers; per-row
1514/// arithmetic v3-VERBATIM, epilogue silu_mul_f32-VERBATIM => BIT-IDENTICAL to the
1515/// chain, asserted by the sel oracle's gufuse mode). Cuts the sel serial chain 5 -> 3
1516/// launches and doubles outstanding code loads per warp (the slice is latency-bound at
1517/// ~27% of card bandwidth — PROFILE-4 re-profile). Geometry in_f % 32 == 0 &&
1518/// ff % 4 == 0, else the v3 chain. Default ON with the round-4 receipts
1519/// (perf24/ab-gufuse-nvfp4{,-tp2}.tsv: interleaved x5, single 14.75 -> 14.58, TP2
1520/// route 13.43 -> 13.10, rep-0 chains IDENTICAL both configs; oracle gufuse mode
1521/// asserts byte identity incl. the count-gated pack twin); `--ab-seam gufuse`.
1522pub const SEL_GUFUSE_DEFAULT: bool = true;
1523static SEL_GUFUSE: std::sync::atomic::AtomicBool =
1524    std::sync::atomic::AtomicBool::new(SEL_GUFUSE_DEFAULT);
1525
1526pub fn set_sel_gufuse(on: bool) {
1527    SEL_GUFUSE.store(on, std::sync::atomic::Ordering::Relaxed);
1528}
1529
1530fn sel_gufuse_on() -> bool {
1531    SEL_GUFUSE.load(std::sync::atomic::Ordering::Relaxed)
1532}
1533
1534/// Verify multi-token WEIGHT-SHARED kernels (mtp-spec): trunk dense mats run
1535/// `qmatvec_bf16w_mt_f32` (one block per output row, W read ONCE for every verify
1536/// column — the qwen38 t-parallel pattern) and the MoE verify columns merge into ONE
1537/// grouped launch per projection via the gufuse tok_map. Every per-(row,token) fma
1538/// chain is the t == 1 program VERBATIM => rows stay BIT-IDENTICAL to per-token
1539/// launches (asserted by the bf16-matvec oracle's mt mode and the verify-bit gate);
1540/// only weight-read counts and launch counts drop. Engages ONLY at 2 <= t <= 12 exact
1541/// chunks (plain decode and prefill untouched). Default ON with the mtp-spec lane's
1542/// receipts (spec/MTP-SPEC.md: verify-bit-gate bit-identity + interleaved spec A/B);
1543/// OFF twin = the per-token grid path, `--ab-seam vmt`.
1544pub const VERIFY_MT_DEFAULT: bool = true;
1545static VERIFY_MT: std::sync::atomic::AtomicBool =
1546    std::sync::atomic::AtomicBool::new(VERIFY_MT_DEFAULT);
1547
1548pub fn set_verify_mt(on: bool) {
1549    VERIFY_MT.store(on, std::sync::atomic::Ordering::Relaxed);
1550}
1551
1552fn verify_mt_on() -> bool {
1553    VERIFY_MT.load(std::sync::atomic::Ordering::Relaxed)
1554}
1555
1556/// Router bf16 residency (perf round 4): the MoE router GEMV was the last dense trunk
1557/// mat still on f32 cuBLASLt (the TP2 nsys counts it among the ~70 f32 gemvx
1558/// calls/token). Same guards and arithmetic class as the trunk seam (exact bf16
1559/// widening, accumulation-class reduction change — routing near-ties are gated by the
1560/// real gate's argmax/greedy battery). Default ON with the round-4 receipts
1561/// (perf24/ab-routerb16-nvfp4{,-tp2}.tsv: interleaved x5, single 14.75 -> 14.68, TP2
1562/// route 13.47 -> 13.36, rep-0 chains IDENTICAL; decode-row seam-gate 24/24 argmax,
1563/// worst KL 0.00116 — the trunk accumulation class); `--ab-seam routerb16`.
1564pub const ROUTER_B16_DEFAULT: bool = true;
1565static ROUTER_B16: std::sync::atomic::AtomicBool =
1566    std::sync::atomic::AtomicBool::new(ROUTER_B16_DEFAULT);
1567
1568pub fn set_router_bf16(on: bool) {
1569    ROUTER_B16.store(on, std::sync::atomic::Ordering::Relaxed);
1570}
1571
1572fn router_bf16_on() -> bool {
1573    ROUTER_B16.load(std::sync::atomic::Ordering::Relaxed)
1574}
1575
1576/// Gate/battery instrumentation: apply `MEMRA_Q4E_SEAMS` ("name" or "name=0", comma
1577/// separated) to the seam setters, so the tiny + real gates can prove a NEW seam green
1578/// while its shipped default is still OFF (flags law: correctness receipts precede the
1579/// default flip). Names match the `--ab-seam` vocabulary.
1580/// The masked SDPA kernel's smem score bound in KV tokens (48 KB of f32 scores). Past
1581/// this the dense-mask path is impossible; the block-list kernel takes over.
1582const SDPA_MASK_TKV_BOUND: usize = 12288;
1583
1584/// Device QSA indexer block scorer (long-context lane). Default ON: scores are
1585/// BIT-IDENTICAL to the host twin (same dim order, relu-sum and division), the host twin
1586/// stays the reference/TP2 path, and the host cost it replaces is O(context) per token
1587/// per layer — 52% of the decode token at a 32k fill and quadratic across a long
1588/// prefill (receipts in research/qwen4exp-bringup-20260829/yarn/). Rollback:
1589/// `MEMRA_Q4E_SEAMS=idxdev=0`.
1590static IDX_DEV: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
1591fn idx_dev_on() -> bool {
1592    IDX_DEV.load(std::sync::atomic::Ordering::Relaxed)
1593}
1594pub fn set_idx_dev(on: bool) {
1595    IDX_DEV.store(on, std::sync::atomic::Ordering::Relaxed);
1596}
1597
1598/// Device QSA indexer top-k SELECTION (262k perf lane, `qsa_index_topk_u32`). The
1599/// `idxdev` seam above moved the block SCORING to the GPU and then dtoh'd the whole score
1600/// slab so the HOST could run `top_blocks_ascending` per row. At the product window that
1601/// host half is the wall: at a 131,072 fill `qsa.idx_host` measured **51,235 ms — 83% of a
1602/// prefill chunk** while every GPU section stayed flat within 4%, and it is what prices the
1603/// whole 262k window down from ~32 to ~15-18 tok/s
1604/// (research/qwen4exp-bringup-20260829/round2-box-receipts/LADDER.md §4c). This seam runs
1605/// the selection on device and reads back `rows x budget` u32 instead of `rows x blocks`
1606/// f32 (4 MB instead of up to 128 MB per sub-batch).
1607///
1608/// Selection is EXACT by construction, not by tolerance: the kernel's u64 key orders
1609/// ascending exactly as the host `sel_cmp` (score desc under `total_cmp`, block index asc)
1610/// over the whole f32 domain, keys are distinct, and the emitted order is ascending block
1611/// index. Gated by `gate_qsa_index_topk` (real geometry + tie batteries incl. the
1612/// structural all-zero-score class) and by the live cross-surface audit
1613/// `MEMRA_Q4E_IDXSEL_AUDIT=1`, which recomputes the host twin from the SAME slab and
1614/// hard-compares ids AND order.
1615///
1616/// **Default ON (2026-09-01), FLIPPED on receipts** (new-flags law: a default is a decision
1617/// with its reasons and receipts stated, and it flips only once both arms are measured).
1618/// Introduced default OFF the day before; the flip carries:
1619///
1620/// - **Interleaved same-fill A/B at 131,072** (`--ladder-ab-seam idxsel`, both arms on ONE
1621///   prefill, exclusive measurement lock, sole tenant): off 56.64 ms / 17.66 tok/s vs on
1622///   32.25 ms / 31.01 tok/s = **1.7562x**, 7 reps per arm (escalated from 5), 224 warm
1623///   samples per arm, within-arm spreads 2.40% / 2.12% — the verdict is ~18x the pooled
1624///   spread. Reproduces the independent two-process pair (1.76x) on both arms.
1625/// - **The target window**: 262,144 tokens goes **15.21 -> 23.44 tok/s (1.54x)** with the
1626///   prefill wall **4,779.1 -> 1,439.2 s (3.32x)**, spread 2.56% (escalated x5) -> 0.30%.
1627/// - **The cliff is gone**: 100,000 -> 131,072 was 1.9x slower for 1.31x depth; it is now
1628///   -7.6%, and prefill per chunk is flat across a continuous 262k fill (82.8 -> 96.4 s per
1629///   16k, where the OFF arm stepped 105 -> 475).
1630/// - **Exactness**: tie-battery oracle EXACT on ids AND order at real budget 512 up to
1631///   65,536 blocks, on BOTH card classes; live at-depth audit **1,549,452 rows / 0
1632///   mismatches / deepest_blocks 32,793**; decode-row-volume audit **120,000 decode-row
1633///   selections / 0 mismatches**; greedy chain byte-identical across the seam at a
1634///   100,000-token fill; all four rule gates green and identical to the prior battery.
1635/// - **Variance improves too**: both deep rungs auto-escalated to x5 on the OFF arm (2.74% /
1636///   1.62%) and sit at 0.36% / 0.02% with the seam on — the 48-thread host top-k pool was
1637///   also the jitter source.
1638///
1639/// Rollback: `MEMRA_Q4E_SEAMS=idxsel=0` (the pure host top-k over the dtoh'd slab). Unlike
1640/// the devtwin pair, this seam has NO pairing requirement — it wins alone on every measured
1641/// surface and it is measured on top of the shipped `routerdev` + `idxcache` + `kvq` stack.
1642/// Receipts: research/qwen4exp-bringup-20260829/perf/PROFILE-11.md.
1643pub const IDX_SEL_DEFAULT: bool = true;
1644static IDX_SEL: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(IDX_SEL_DEFAULT);
1645fn idx_sel_on() -> bool {
1646    IDX_SEL.load(std::sync::atomic::Ordering::Relaxed)
1647}
1648pub fn set_idx_sel(on: bool) {
1649    IDX_SEL.store(on, std::sync::atomic::Ordering::Relaxed);
1650}
1651/// INCREMENTAL PLE n-gram id cache (262k perf lane, `plecache`). `ple_block` calls
1652/// `host_ngram_ids`, a `ngram_ids` twin over the FULL token history, and then slices the last
1653/// `t` rows — so a decode step at a 150,000-token fill rebuilds 150,000 rows of hashes to
1654/// consume ONE. Measured on the deep decode profile with `idxsel` armed:
1655/// `ple.host_ngram_gather` is **7.3 ms, 19.5% of the token**, second only to `qsa.sdpa` and
1656/// the largest remaining HOST section (PROFILE-11 §5).
1657///
1658/// This is the correction the deep profile forced on the owner's stated prefetch lever, and
1659/// it is worth stating rather than quietly fixing: the assumed mechanism was "the gather from
1660/// the 102 GB host table is synchronous, so overlap it with compute". The gather itself is
1661/// `t * 16` random rows — 16 reads of 160 f32 at decode, microseconds. The 7.3 ms is the
1662/// O(context) ID RECOMPUTE in front of it. Async-prefetching the table would have bought
1663/// ~nothing; caching the ids removes essentially all of it. Same class as the yarn lane's
1664/// O(context) host selection, in a different section.
1665///
1666/// Exact by construction (see `host_ngram_ids_cached`): `ids[token]` is a pure function of
1667/// `token_ids[..=token]`, so the cache appends and never recomputes. Divergence and rewind
1668/// are handled by a real longest-common-PREFIX compare, not a length compare.
1669///
1670/// **Default ON as of 2026-09-01, by design** (new-flags law: the decision and its reasons are
1671/// written, and the receipts landed before the flip). Introduced default OFF on 2026-08-31 with
1672/// no perf receipts; flipped after the A/B and the exactness battery below. Rollback is one
1673/// token: `MEMRA_Q4E_SEAMS=plecache=0`.
1674///
1675/// PERFORMANCE — x3 interleaved, both arms sharing one prefill and one exclusive lock hold, lead
1676/// flipped on odd reps, no escalation owed on any arm (PROFILE-12 §2, §10):
1677///
1678/// | depth | OFF | ON | speedup | this section, OFF arm |
1679/// |---|---|---|---|---|
1680/// | 131,072 | 33.52 ms / 29.83 tok/s | 25.91 ms / 38.60 tok/s | 1.2938x | 7.8 ms (20.3%) |
1681/// | 262,144 | 41.38 ms / 24.17 tok/s | 28.30 ms / 35.34 tok/s | **1.4620x** | **13.2 ms (28.9%)** |
1682///
1683/// The gain GROWS with depth because the deleted work is O(fill) per token, and at the target
1684/// window this was **the largest section of the whole token**, ahead of `qsa.sdpa`. With the seam
1685/// armed it leaves the top twelve entirely while every other section holds to a tenth of a
1686/// millisecond. It also removes decode JITTER: cv 2.48% -> 0.11% at 131,072, p99 41.70 -> 28.38 ms
1687/// at 262,144 — a p99-latency result, which is what a deep-context agentic workload feels.
1688///
1689/// EXACTNESS — the flip rests on the two arms that can actually falsify it, not on the many that
1690/// cannot:
1691/// - **Real-geometry truth pin** (`MEMRA_Q4E_PLECACHE_AUDIT=1`): `rows=32828 mismatched=0
1692///   deepest_fill=32828`. Cached ids hard-compared against the full `host_ngram_ids` twin at the
1693///   CHECKPOINT's own multipliers/sizes/offsets, over both growth shapes (2,048-token prefill
1694///   chunks and one-at-a-time decode appends).
1695/// - **Behavioural control**: the greedy chain is IDENTICAL across the seam on the same artifact
1696///   (`-1/0/-1/26` both arms, hidden-goldens argmax 10/10 both arms).
1697/// - Host oracle vs the full twin: EXACT over 69,635 cumulative-sequence comparisons across 6 case
1698///   families (decode growth, ragged prefill chunks, eos resets incl. adjacent/leading/trailing,
1699///   all-eos, repeated rewinds to DIVERGING prefixes, shorter-unrelated-sequence state reuse).
1700/// - `verify-bit` 24 `mismatched=0 policy=bit-identity`; spec byte-identity 256
1701///   `policy=byte-identity pass=true` with `first_divergence=-1` on all four prompts.
1702///
1703/// **Why those last two carry less weight than they look like they do, stated so the flip is not
1704/// over-credited:** `verify-bit` and spec byte-identity are INTRA-ARM, and an intra-arm identity
1705/// gate cannot detect a CONSISTENT error — a uniformly-wrong id set is perfectly self-consistent
1706/// and passes both with full marks. The truth pin and the greedy control are what close it.
1707///
1708/// STILL OWED (PROFILE-12 §9): `--verify-bit-deep 131072` with the seam armed has not passed — it
1709/// failed three times on this box with ~96 GB free, i.e. on the instrument rather than on the seam.
1710/// It is intra-arm, so it cannot add exactness assurance the truth pin does not already give; the
1711/// flip does not wait on it, and it stays owed rather than being quietly dropped.
1712///
1713/// COST: one `i64` id vector per state, `fill * 16 * 8` bytes = 33.5 MB of HOST memory at 262,144
1714/// (the box carries 499 GB), plus the token-history mirror. No device memory, no new kernel.
1715pub const PLE_CACHE_DEFAULT: bool = true;
1716static PLE_CACHE: std::sync::atomic::AtomicBool =
1717    std::sync::atomic::AtomicBool::new(PLE_CACHE_DEFAULT);
1718fn ple_cache_on() -> bool {
1719    PLE_CACHE.load(std::sync::atomic::Ordering::Relaxed)
1720}
1721pub fn set_ple_cache(on: bool) {
1722    PLE_CACHE.store(on, std::sync::atomic::Ordering::Relaxed);
1723}
1724/// Live cross-surface audit for the PLE id cache (`MEMRA_Q4E_PLECACHE_AUDIT=1`): recompute
1725/// the FULL `host_ngram_ids` twin and hard-compare the chunk's rows against the cached ones.
1726/// Instrument only — it restores exactly the O(context) work the seam deletes.
1727fn ple_cache_audit_on() -> bool {
1728    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1729    *C.get_or_init(|| std::env::var("MEMRA_Q4E_PLECACHE_AUDIT").as_deref() == Ok("1"))
1730}
1731static PLE_CACHE_AUDIT_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
1732static PLE_CACHE_AUDIT_MISMATCH: std::sync::atomic::AtomicU64 =
1733    std::sync::atomic::AtomicU64::new(0);
1734static PLE_CACHE_AUDIT_MAX_FILL: std::sync::atomic::AtomicU64 =
1735    std::sync::atomic::AtomicU64::new(0);
1736/// (rows audited, id mismatches, deepest history length seen) since process start.
1737pub fn ple_cache_audit_stats() -> (u64, u64, u64) {
1738    (
1739        PLE_CACHE_AUDIT_ROWS.load(std::sync::atomic::Ordering::Relaxed),
1740        PLE_CACHE_AUDIT_MISMATCH.load(std::sync::atomic::Ordering::Relaxed),
1741        PLE_CACHE_AUDIT_MAX_FILL.load(std::sync::atomic::Ordering::Relaxed),
1742    )
1743}
1744
1745/// Live device-vs-host indexer-selection audit (`MEMRA_Q4E_IDXSEL_AUDIT=1`): every device
1746/// selection ALSO dtohs the score slab and runs `top_blocks_ascending` on the same bytes,
1747/// hard-comparing the block ids AND their emitted order. Instrument only — it restores the
1748/// very dtoh this seam deletes, so it is never a perf arm. Counters feed the receipt
1749/// (`idx_sel_audit_stats`); `rows=0` is the silent-no-op failure the counter exists to
1750/// catch.
1751fn idx_sel_audit_on() -> bool {
1752    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1753    *C.get_or_init(|| std::env::var("MEMRA_Q4E_IDXSEL_AUDIT").as_deref() == Ok("1"))
1754}
1755static IDX_SEL_AUDIT_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
1756static IDX_SEL_AUDIT_MISMATCH: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
1757static IDX_SEL_AUDIT_MAX_BLOCKS: std::sync::atomic::AtomicU64 =
1758    std::sync::atomic::AtomicU64::new(0);
1759/// (rows audited, selection mismatches, deepest block count seen) since process start.
1760pub fn idx_sel_audit_stats() -> (u64, u64, u64) {
1761    (
1762        IDX_SEL_AUDIT_ROWS.load(std::sync::atomic::Ordering::Relaxed),
1763        IDX_SEL_AUDIT_MISMATCH.load(std::sync::atomic::Ordering::Relaxed),
1764        IDX_SEL_AUDIT_MAX_BLOCKS.load(std::sync::atomic::Ordering::Relaxed),
1765    )
1766}
1767
1768/// Device MoE router (devtwin lane): `qwen4exp_route_topk_f32` replaces the per-layer
1769/// router dtoh + `host_route_softmax_topk` + selection h2d — the census's 48 blocking
1770/// drains per forward and the round-3 doctrine's whole-step-graph blocker. Engages on
1771/// the GROUPED dispatch paths only (NVFP4 t==1 decode / verify columns / graph-driver
1772/// slots); the per-expert prefill executor and the TP2 route keep the host twin (they
1773/// consume host expert ids by construction). Selection set + order are gated EXACTLY
1774/// against the host twin (gate_route_kernel + MEMRA_Q4E_ROUTER_AUDIT); weights within
1775/// documented ULP (exp is the one non-bit-pinned op — kernel doc).
1776///
1777/// **Default ON (2026-08-31), decided on receipts** (better-wins-by-default): the
1778/// combined devtwin stack wins every measured surface — spec at ship admission thinkon
1779/// 1.168x / thinkoff 1.174x / efflow 1.160x / raw 1.194x / long-724 1.116x with
1780/// BYTE-IDENTICAL 256-token chains, K ladder 1.14-1.18x over K=1..8, plain decode
1781/// 1.099x with decode graphs ON and 1.112x with them OFF — under all three rule gates
1782/// green (verify-bit 24/24, spec-gate byte identity, tp2-gate) plus a 250k-row live
1783/// host-twin audit with ZERO selection mismatches. **Pair with `idxcache`: this seam
1784/// ALONE with decode graphs ON measured 0.906x** (PROFILE-9 §3/§3a) — the stack is the
1785/// unit, which is why both defaults flip together. Rollback:
1786/// `MEMRA_Q4E_SEAMS=routerdev=0`.
1787pub const ROUTER_DEV_DEFAULT: bool = true;
1788static ROUTER_DEV: std::sync::atomic::AtomicBool =
1789    std::sync::atomic::AtomicBool::new(ROUTER_DEV_DEFAULT);
1790fn router_dev_on() -> bool {
1791    ROUTER_DEV.load(std::sync::atomic::Ordering::Relaxed)
1792}
1793pub fn set_router_dev(on: bool) {
1794    ROUTER_DEV.store(on, std::sync::atomic::Ordering::Relaxed);
1795}
1796/// The device router's geometry envelope: register top-k (<= 32 slots) + smem softmax
1797/// slab (experts f32 <= 48 KB). Real geometry 512/10 sits comfortably inside; a plan
1798/// outside the envelope keeps the host twin.
1799fn route_dev_geometry(experts: usize, selected: usize) -> bool {
1800    // Even expert count: the u64 selection-key slab follows the f32 weight slab in
1801    // dynamic smem (12 B/expert total) and needs 8-byte alignment.
1802    selected > 0
1803        && selected <= 32
1804        && selected <= experts
1805        && experts % 2 == 0
1806        && experts * 12 <= 48 * 1024
1807}
1808
1809/// Live device-vs-host router twin audit (`MEMRA_Q4E_ROUTER_AUDIT=1`): every device
1810/// route ALSO computes the host twin from the same logits and hard-compares — selection
1811/// ids order-exact (Err on any mismatch), weights within `ROUTE_AUDIT_ULP_BOUND` ULP
1812/// (worst observed kept for the receipt). The sigrouter-precedent cross-surface
1813/// contract, run over REAL decode rows by any existing gate invocation. Instrument
1814/// only: it dtohs per route, so it is never a perf arm.
1815fn router_audit_on() -> bool {
1816    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1817    *C.get_or_init(|| std::env::var("MEMRA_Q4E_ROUTER_AUDIT").as_deref() == Ok("1"))
1818}
1819/// DIAGNOSTIC seam (`MEMRA_Q4E_ROUTE_SYNC=1`): keep the device route but restore the
1820/// host arm's per-layer stream sync — the instrument that separates kernel cost from
1821/// sync-structure cost in the graphs-ON regression. Never a serving arm; no FLAGS row
1822/// because it is an instrument, and it is read once per process.
1823fn route_sync_diag() -> bool {
1824    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1825    *C.get_or_init(|| std::env::var("MEMRA_Q4E_ROUTE_SYNC").as_deref() == Ok("1"))
1826}
1827
1828const ROUTE_AUDIT_ULP_BOUND: u32 = 8;
1829static ROUTE_AUDIT_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
1830static ROUTE_AUDIT_MAX_ULP: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
1831/// (rows audited, worst weight ULP distance) since process start.
1832pub fn route_audit_stats() -> (u64, u32) {
1833    (
1834        ROUTE_AUDIT_ROWS.load(std::sync::atomic::Ordering::Relaxed),
1835        ROUTE_AUDIT_MAX_ULP.load(std::sync::atomic::Ordering::Relaxed),
1836    )
1837}
1838
1839/// Device-resident indexer raw-key cache (devtwin stage 3): below the QSA selection
1840/// horizon ((base_pos + t)/block <= budget — every row structurally full), the
1841/// idx_proj dtoh exists ONLY to feed the host raw-key cache for a possible future
1842/// scored row. This seam appends the k-part rows d2d (`copy_rows_col_f32`, exact byte
1843/// moves) and materializes the host cache LAZILY at the first scored chunk — the same
1844/// bytes dtoh'd later, so the scored path is bit-identical by construction. Kills the
1845/// census's 12 idx_proj blocking dtoh per forward (+1 per draft chain step) on every
1846/// sub-horizon shape.
1847///
1848/// **Default ON (2026-08-31), decided on receipts** with `routerdev` as ONE stack (see
1849/// that seam's note and PROFILE-9): isolated plain-decode row 1.024x, and it is the half
1850/// that makes the router's sign positive with decode graphs ON. Rollback:
1851/// `MEMRA_Q4E_SEAMS=idxcache=0`.
1852pub const IDX_CACHE_DEFAULT: bool = true;
1853static IDX_CACHE: std::sync::atomic::AtomicBool =
1854    std::sync::atomic::AtomicBool::new(IDX_CACHE_DEFAULT);
1855fn idx_cache_on() -> bool {
1856    IDX_CACHE.load(std::sync::atomic::Ordering::Relaxed)
1857}
1858pub fn set_idx_cache(on: bool) {
1859    IDX_CACHE.store(on, std::sync::atomic::Ordering::Relaxed);
1860}
1861
1862/// Quantized QSA KV cache (kvq lane): K = q8_0, V = q5_1 — the owner's asymmetric
1863/// default (K feeds the score dots + rope, so it keeps symmetric 8-bit; V errors
1864/// average under the attention weighting, so affine 5-bit suffices). The format is
1865/// LATCHED PER STATE at `alloc_state`/`mtp_state` time (a byte cache cannot flip
1866/// mid-run); the f32 arm stays the exactness instrument and the rollback seam
1867/// (`MEMRA_Q4E_SEAMS=kvq=0`). Storage-only: attention math runs f32 on dequanted
1868/// values (the block-list kernel's program with in-place dequant, gated bit-identical
1869/// to the dequant-rows + f32-kernel composition). Default ON per the owner decision,
1870/// with this lane's receipts attached (flags law): within-config exactness green
1871/// (spec byte-identity 6/6, verify-bit 24/24 x3, envelope 24/24 @ 3.0e-5), cross-config
1872/// drift is the near-tie quant class stated in KVQ-CELL.md (worst rows flip between the
1873/// two eos ids; greedy forks on the valid raw instrument match the f32 class).
1874///
1875/// PERF JUSTIFICATION, DEPTH-SCOPED (corrected 2026-08-31; docs/FLAGS.md carried the scoping
1876/// and this doc comment did not, so the stale claim was still riding here). The flip cited
1877/// "the quantized cache is FASTER, 13.36-13.39 vs 13.53-13.57 ms/token interleaved". That was
1878/// measured at a SHALLOW fill and the sign REVERSES with depth: at a 100,000-token fill kvq is
1879/// **-7.4% decode and -7.3% prefill wall** vs the f32 twin (LADDER.md, KVQ-CELL.md round 2).
1880/// Never quote "kvq is faster" at depth. The DECISION stands on memory: 11.08 vs 49.0
1881/// KiB/token, and at the 262,144 target window kvq is memory-REQUIRED (the f32 arm does not
1882/// allocate that state at all), so there is no alternative to compare against.
1883/// The -7.4% is a READ-PATTERN artifact, not the cost of quantization -- see `KV_HOIST_DEFAULT`.
1884/// Receipts: research/qwen4exp-bringup-20260829/kvq/ + box ~/realgate/kvq.
1885pub const KV_QUANT_DEFAULT: bool = true;
1886static KV_QUANT: std::sync::atomic::AtomicBool =
1887    std::sync::atomic::AtomicBool::new(KV_QUANT_DEFAULT);
1888fn kv_quant_on() -> bool {
1889    KV_QUANT.load(std::sync::atomic::Ordering::Relaxed)
1890}
1891pub fn set_kv_quant(on: bool) {
1892    KV_QUANT.store(on, std::sync::atomic::Ordering::Relaxed);
1893}
1894
1895/// HOISTED K block scale in the quantized block-list attention (`kvhoist`, memory lane
1896/// 2026-08-31). Selects `q4e_sdpa_blocklist_q8q5_hoist` over `q4e_sdpa_blocklist_q8q5`;
1897/// BIT-IDENTICAL by construction (same product, same `acc +=` order, phase 2 and phase 3
1898/// verbatim), so this is a pure read-pattern seam and the bar is bit-identity, not a band.
1899///
1900/// It exists because it is the mechanism behind the kvq perf SIGN FLIP, and the flip turns out
1901/// to be a layout artifact rather than a tax. `q4e_deq_q8` recomputes the block pointer from the
1902/// element index, so the score loop reloads the fp16 block scale ONCE PER ELEMENT. Measured
1903/// statically in the sm_120 SASS (`PROFILE-C0.md` §2), score-phase inner loop per 8 K elements:
1904///
1905/// | kernel | instrs | KV-cache loads | fp16 scale loads |
1906/// |---|---|---|---|
1907/// | `sdpa_blocklist_f32` | 37 | 8 | -- |
1908/// | `q4e_sdpa_blocklist_q8q5` | **120** | 8 | **8** |
1909/// | `q4e_sdpa_blocklist_q8q5_hoist` | **52** | 8 | **0** (1 per 32-elem block) |
1910///
1911/// Phase 1 is thread-per-position (lanes sit on 32 different tokens, `k_tok_bytes` apart), so
1912/// every load instruction replays 32 ways into 32 distinct sectors. The quantized cache
1913/// therefore issued 2x the f32 twin's KV transactions while reading 3.76x fewer bytes: the byte
1914/// saving cannot land, and the extra instruction stream is a straight loss. That is the -7.4%
1915/// at a 100,000-token fill, and it is why the +1.3% shallow flip receipt had the opposite sign
1916/// (a shallow fill reads almost no rows, so phase 1 barely runs).
1917///
1918/// Default OFF at introduction, by design (new-flags law): the correctness receipts land with
1919/// the seam and the default flip is a separate change carrying the interleaved A/B. Arm with
1920/// `MEMRA_Q4E_SEAMS=kvhoist`; rollback `kvhoist=0`. Mid-run flippable (no layout latch).
1921pub const KV_HOIST_DEFAULT: bool = false;
1922static KV_HOIST: std::sync::atomic::AtomicBool =
1923    std::sync::atomic::AtomicBool::new(KV_HOIST_DEFAULT);
1924fn kv_hoist_on() -> bool {
1925    KV_HOIST.load(std::sync::atomic::Ordering::Relaxed)
1926}
1927pub fn set_kv_hoist(on: bool) {
1928    KV_HOIST.store(on, std::sync::atomic::Ordering::Relaxed);
1929}
1930/// For receipt headers, same reason as `kv_quant_is_on`.
1931pub fn kv_hoist_is_on() -> bool {
1932    kv_hoist_on()
1933}
1934
1935/// DIM-MAJOR pooled-key device plane (`poolT`, memory lane 2026-08-31). Selects
1936/// `qsa_index_score_f32_t` over `qsa_index_score_f32` and mirrors the pooled cache transposed;
1937/// BIT-IDENTICAL by construction (identical loop order and identical explicit
1938/// `__fmul_rn`/`__fadd_rn`/`__fdiv_rn` -- only the address of `pooled` changes).
1939///
1940/// It targets the SECOND depth-scaling term in the deep decode profile. With `idxsel` armed
1941/// (`ladder-r2prof-step-idxsel.tsv`), `qsa.idx_host` is 2.5 ms at 100,000 / 3.0 at 131,072 /
1942/// 3.2 at 150,000 -- linear in context, extrapolating to ~5.7 ms at 262,144, behind only
1943/// `ple.host_ngram_gather` among the terms that grow. The score kernel is thread-per-block over
1944/// the pooled plane, so lane L reads `pooled[(block0+L)*head_dim + d]`: lanes are head_dim*4 =
1945/// 512 B apart, one warp's `k[d]` touches 32 DISTINCT sectors and moves 1024 B to use 128 B.
1946/// Dim-major makes the same 32 lanes read 32 consecutive floats: 4 sectors, zero waste, 8x less
1947/// sector traffic on the one array whose size IS the context.
1948///
1949/// Default OFF at introduction, by design (new-flags law). Arm `MEMRA_Q4E_SEAMS=poolT`, roll
1950/// back `poolT=0`. **Mid-run flippable with NO rebuild**: both layouts are maintained on every
1951/// append (see the append site for why), so `**mirrored` is the single truth for both and a flip
1952/// can neither read a stale plane nor leave one behind. The seam selects only the kernel.
1953pub const POOL_T_DEFAULT: bool = false;
1954static POOL_T: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(POOL_T_DEFAULT);
1955fn pool_t_on() -> bool {
1956    POOL_T.load(std::sync::atomic::Ordering::Relaxed)
1957}
1958pub fn set_pool_t(on: bool) {
1959    POOL_T.store(on, std::sync::atomic::Ordering::Relaxed);
1960}
1961/// For receipt headers.
1962pub fn pool_t_is_on() -> bool {
1963    pool_t_on()
1964}
1965
1966/// The live KV cache format, for RECEIPT HEADERS. A receipt that does not record which
1967/// cache arm it ran cannot be read: the round-2 ladder measured the f32 arm for a full
1968/// rung while its commit message said "kvq ship defaults", and nothing in the receipt
1969/// could have contradicted that. Reported, not inferred.
1970pub fn kv_quant_is_on() -> bool {
1971    kv_quant_on()
1972}
1973
1974/// Indexer raw-key cache precision (idxq lane). The 128-dim raw keys are cached
1975/// pre-norm/pre-rope and consumed ONLY through fp32 mean-pooling into pooled keys —
1976/// this seam quantizes the CACHE and dequants at read; the pooling math is identical.
1977/// Precision is picked by measurement (selection-identity flip rate on real prompts at
1978/// depth): q8 is the target, bf16 the fallback if q8 flips selections, f32 the
1979/// rollback/reference. Latched per state at alloc. Default Q8 per the measured
1980/// receipt: the q8-vs-f32 seam gate came back BIT-ZERO on the real checkpoint
1981/// (selection provably unmoved, 24/24 argmax, worst_abs 0.000e0 —
1982/// kvq/seam-gate-idxq-idxq1.tsv), so the cheaper cache wins by measurement.
1983#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1984pub enum IdxQMode {
1985    F32,
1986    Q8,
1987    Bf16,
1988}
1989static IDXQ_MODE: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(1);
1990fn idxq_mode() -> IdxQMode {
1991    match IDXQ_MODE.load(std::sync::atomic::Ordering::Relaxed) {
1992        1 => IdxQMode::Q8,
1993        2 => IdxQMode::Bf16,
1994        _ => IdxQMode::F32,
1995    }
1996}
1997pub fn set_idxq(mode: &str) {
1998    let v = match mode {
1999        "q8" | "1" => 1,
2000        "bf16" => 2,
2001        _ => 0,
2002    };
2003    IDXQ_MODE.store(v, std::sync::atomic::Ordering::Relaxed);
2004}
2005
2006/// The live indexer raw-key cache precision, for RECEIPT HEADERS (see `kv_quant_is_on`).
2007pub fn idxq_mode_name() -> &'static str {
2008    match idxq_mode() {
2009        IdxQMode::F32 => "f32",
2010        IdxQMode::Q8 => "q8",
2011        IdxQMode::Bf16 => "bf16",
2012    }
2013}
2014
2015/// Selection-identity audit (`MEMRA_Q4E_IDXQ_AUDIT=1`): with a quantized raw-key cache,
2016/// ALSO maintain an f32 twin cache (forcing the idx_proj dtoh the idxcache seam
2017/// removed — instrument, never a perf arm) and compute every scored row's selection
2018/// twice; count rows whose selected block set differs. The 1-ULP FMA lesson says
2019/// near-tie blocks CAN flip — this measures the rate on real prompts at depth.
2020fn idxq_audit_on() -> bool {
2021    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2022    *C.get_or_init(|| std::env::var("MEMRA_Q4E_IDXQ_AUDIT").as_deref() == Ok("1"))
2023}
2024static IDXQ_AUDIT_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2025static IDXQ_AUDIT_FLIPPED: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2026static IDXQ_AUDIT_BLOCKS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2027/// (scored rows audited, rows with a flipped selection set, total symmetric-difference
2028/// blocks) since process start.
2029pub fn idxq_audit_stats() -> (u64, u64, u64) {
2030    (
2031        IDXQ_AUDIT_ROWS.load(std::sync::atomic::Ordering::Relaxed),
2032        IDXQ_AUDIT_FLIPPED.load(std::sync::atomic::Ordering::Relaxed),
2033        IDXQ_AUDIT_BLOCKS.load(std::sync::atomic::Ordering::Relaxed),
2034    )
2035}
2036
2037/// Long-context QSA attention form (yarn lane). Auto = block-list kernel ONLY past the
2038/// masked kernel's smem bound (every historical receipt is byte-stable below it);
2039/// Force = block-list everywhere (the gate arms' A/B); Off = refuse long contexts (the
2040/// historical error). FLAGS.md row `q4e-longatt`.
2041#[derive(Clone, Copy, PartialEq, Eq)]
2042enum LongAttMode {
2043    Auto,
2044    Force,
2045    Off,
2046}
2047static LONGATT_MODE: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(0);
2048fn longatt_mode() -> LongAttMode {
2049    match LONGATT_MODE.load(std::sync::atomic::Ordering::Relaxed) {
2050        1 => LongAttMode::Force,
2051        2 => LongAttMode::Off,
2052        _ => LongAttMode::Auto,
2053    }
2054}
2055pub fn set_longatt(mode: &str) {
2056    let v = match mode {
2057        "force" | "1" => 1,
2058        "off" | "0" => 2,
2059        _ => 0,
2060    };
2061    LONGATT_MODE.store(v, std::sync::atomic::Ordering::Relaxed);
2062}
2063
2064// ------------------------------------------------------------ TP2 MoE expert placement
2065//
2066// Owner directive 2026-08-31 (LAW:coactivation-expert-placement): expert placement is
2067// MEASURED, never even-split — bundles by co-activation, the always-active set pinned to
2068// a KNOWN card the token enters and leaves. This lane does NOT do that measurement; it
2069// makes the seam exist so the placement lane is a measurement + config exercise instead
2070// of an engine rewrite.
2071//
2072// The artifact is the FROZEN shared format `memra-ep-map-v1`, minted by
2073// `tools/build_expert_placement_map.py` (merged on main, 4e46be545) from
2074// `MEMRA_MOE_TRACE` route traces. Reading the shared format rather than a lane-local one
2075// is the whole point: the glm5 arm consumes the same maps through `MEMRA_GLM5_EP_MAP`,
2076// so a map minted from qwen4_exp traces is comparable with theirs.
2077//
2078// Door: `MEMRA_Q4E_EP_MAP=<path>`. UNSET is the EVEN split — this lane's CONTROL ARM,
2079// and bit-identical to the pre-placement engine BY CONSTRUCTION, not by tolerance: an
2080// even assignment makes the card-1 bank gather a contiguous copy of exactly the suffix
2081// the old code sliced, and leaves card 0 addressing its full resident bank by global id.
2082// Default OFF is a deliberate decision under the new-flags law: an unmeasured placement
2083// must not become the serving default, and no placement has been measured yet.
2084//
2085// Fail-closed, loudly, on every mismatch (a map that silently half-applies would move
2086// expert weights under the router and read as a model bug):
2087//   * format != memra-ep-map-v1, or ranks != 2 (TP2 is a two-card route)
2088//   * expert_count != the plan's expert count
2089//   * a MoE layer in the plan missing from the map, or an assignment of the wrong length
2090//   * a rank id outside {0, 1}
2091//   * an UNBALANCED layer: card 1 must own exactly experts/2. The card-1 bank halves are
2092//     equal-size device allocations, so an unbalanced map is not a slower placement, it
2093//     is an out-of-bounds one. The placement lane must balance inside the tool (it has
2094//     `--balance-tolerance`) and ranks==2 with expert_count even means exact halves.
2095#[derive(Debug, Clone)]
2096pub struct Tp2Placement {
2097    /// layer index -> rank (0 or 1) per GLOBAL expert id. Empty map = even split.
2098    by_layer: std::collections::BTreeMap<u32, Vec<u8>>,
2099    expert_count: usize,
2100    entry_rank: u8,
2101    strategy: String,
2102    source: String,
2103}
2104
2105/// One layer's resolved placement. Card 0 keeps the FULL resident bank, so a card-0
2106/// expert's local slot IS its global id (no remap, exactly as the even split behaved);
2107/// card 1 holds a gathered half, so its local slot is the position in `card1`.
2108#[derive(Debug, Clone)]
2109pub struct LayerPlacement {
2110    /// GLOBAL expert ids owned by card 1, ASCENDING — the bank gather order and the
2111    /// local-slot order. Ascending is load-bearing: it makes the even case a contiguous
2112    /// copy, and it makes the gather order a function of the map alone (no host set
2113    /// iteration order can leak into device bytes).
2114    pub card1: Vec<u32>,
2115    /// global expert id -> local slot on its owner card.
2116    local_of: Vec<u32>,
2117    /// global expert id -> owner rank.
2118    rank_of: Vec<u8>,
2119}
2120
2121impl LayerPlacement {
2122    #[inline]
2123    pub fn rank(&self, expert: usize) -> u8 {
2124        self.rank_of[expert]
2125    }
2126    #[inline]
2127    pub fn local(&self, expert: usize) -> usize {
2128        self.local_of[expert] as usize
2129    }
2130    /// True when this layer is the plain contiguous even split (the control arm).
2131    pub fn is_even(&self) -> bool {
2132        let half = self.rank_of.len() / 2;
2133        self.card1.len() == half
2134            && self
2135                .card1
2136                .iter()
2137                .enumerate()
2138                .all(|(i, &e)| e as usize == half + i)
2139    }
2140}
2141
2142impl Tp2Placement {
2143    /// The even split: `rank = expert / (experts / 2)`, the engine's historical law.
2144    pub fn even(expert_count: usize) -> Self {
2145        Self {
2146            by_layer: std::collections::BTreeMap::new(),
2147            expert_count,
2148            entry_rank: 0,
2149            strategy: "even".to_string(),
2150            source: "built-in (MEMRA_Q4E_EP_MAP unset)".to_string(),
2151        }
2152    }
2153
2154    pub fn strategy(&self) -> &str {
2155        &self.strategy
2156    }
2157    pub fn source(&self) -> &str {
2158        &self.source
2159    }
2160    pub fn entry_rank(&self) -> u8 {
2161        self.entry_rank
2162    }
2163
2164    /// Read `MEMRA_Q4E_EP_MAP`; `Ok(None)` when the door is closed (even split).
2165    pub fn from_env(expert_count: usize) -> Res<Option<Self>> {
2166        let Ok(path) = std::env::var("MEMRA_Q4E_EP_MAP") else {
2167            return Ok(None);
2168        };
2169        if path.is_empty() || path == "0" {
2170            return Ok(None);
2171        }
2172        Some(Self::load(std::path::Path::new(&path), expert_count)).transpose()
2173    }
2174
2175    pub fn load(path: &std::path::Path, expert_count: usize) -> Res<Self> {
2176        let text = std::fs::read_to_string(path)
2177            .map_err(|e| format!("MEMRA_Q4E_EP_MAP {}: {e}", path.display()))?;
2178        let v = memra_tokenizer::json::parse(&text)
2179            .map_err(|e| format!("MEMRA_Q4E_EP_MAP {}: {e}", path.display()))?;
2180        // Every refusal in this function names the file and the exact contract clause
2181        // broken: a rejected map has to tell the placement lane what to fix.
2182        let want = |k: &str| -> Res<Self> {
2183            Err(format!("MEMRA_Q4E_EP_MAP {}: {k}", path.display()).into())
2184        };
2185        match v.get("format").and_then(|f| f.as_str()) {
2186            Some("memra-ep-map-v1") => {}
2187            other => {
2188                return want(&format!(
2189                    "format is {other:?}, expected \"memra-ep-map-v1\" (mint it with \
2190                     tools/build_expert_placement_map.py)"
2191                ));
2192            }
2193        }
2194        let ranks = v.get("ranks").and_then(|r| r.as_u64()).unwrap_or(0);
2195        if ranks != 2 {
2196            return want(&format!(
2197                "ranks={ranks}, but the TP2 route is exactly two cards"
2198            ));
2199        }
2200        let map_experts = v.get("expert_count").and_then(|r| r.as_u64()).unwrap_or(0) as usize;
2201        if map_experts != expert_count {
2202            return want(&format!(
2203                "expert_count={map_experts} but this plan has {expert_count} experts"
2204            ));
2205        }
2206        let entry_rank = v.get("entry_rank").and_then(|r| r.as_u64()).unwrap_or(0) as u8;
2207        if entry_rank > 1 {
2208            return want(&format!("entry_rank={entry_rank} outside {{0,1}}"));
2209        }
2210        let strategy = v
2211            .get("strategy")
2212            .and_then(|s| s.as_str())
2213            .unwrap_or("unnamed")
2214            .to_string();
2215        let Some(layers) = v.get("layers").and_then(|l| l.as_arr()) else {
2216            return want("no `layers` array");
2217        };
2218        let half = expert_count / 2;
2219        let mut by_layer = std::collections::BTreeMap::new();
2220        for row in layers {
2221            let Some(index) = row.get("layer").and_then(|l| l.as_u64()) else {
2222                return want("a layer row without an integer `layer`");
2223            };
2224            let Some(assign) = row.get("assignment").and_then(|a| a.as_arr()) else {
2225                return want(&format!("layer {index}: no `assignment` array"));
2226            };
2227            if assign.len() != expert_count {
2228                return want(&format!(
2229                    "layer {index}: assignment has {} entries, expected {expert_count}",
2230                    assign.len()
2231                ));
2232            }
2233            let mut ranks_vec = Vec::with_capacity(expert_count);
2234            for (eid, a) in assign.iter().enumerate() {
2235                match a.as_u64() {
2236                    Some(r) if r <= 1 => ranks_vec.push(r as u8),
2237                    other => {
2238                        return want(&format!(
2239                            "layer {index} expert {eid}: rank {other:?} outside {{0,1}}"
2240                        ));
2241                    }
2242                }
2243            }
2244            let on1 = ranks_vec.iter().filter(|&&r| r == 1).count();
2245            if on1 != half {
2246                return want(&format!(
2247                    "layer {index}: card 1 owns {on1} experts but the bank halves are \
2248                     equal-size allocations, so it must own exactly {half} — rebalance \
2249                     the map (build_expert_placement_map.py --balance-tolerance)"
2250                ));
2251            }
2252            by_layer.insert(index as u32, ranks_vec);
2253        }
2254        if by_layer.is_empty() {
2255            return want("`layers` is empty");
2256        }
2257        Ok(Self {
2258            by_layer,
2259            expert_count,
2260            entry_rank,
2261            strategy,
2262            source: path.display().to_string(),
2263        })
2264    }
2265
2266    /// Resolve one MoE layer. A loaded map MUST cover every MoE layer it is asked about
2267    /// (fail-closed: silently falling one layer back to even would make the receipt a
2268    /// lie about which placement ran).
2269    pub fn layer(&self, index: u32, expert_count: usize) -> Res<LayerPlacement> {
2270        if expert_count != self.expert_count {
2271            return Err(format!(
2272                "qwen4exp_gpu tp2 placement: layer {index} has {expert_count} experts, \
2273                 map is for {}",
2274                self.expert_count
2275            )
2276            .into());
2277        }
2278        let half = expert_count / 2;
2279        let rank_of: Vec<u8> = if self.by_layer.is_empty() {
2280            (0..expert_count).map(|e| u8::from(e >= half)).collect()
2281        } else {
2282            self.by_layer
2283                .get(&index)
2284                .ok_or_else(|| {
2285                    format!(
2286                        "qwen4exp_gpu tp2 placement: map {} does not cover MoE layer \
2287                         {index} (fail-closed; a partly-applied map is not a placement)",
2288                        self.source
2289                    )
2290                })?
2291                .clone()
2292        };
2293        let card1: Vec<u32> = (0..expert_count)
2294            .filter(|&e| rank_of[e] == 1)
2295            .map(|e| e as u32)
2296            .collect();
2297        let mut local_of = vec![0u32; expert_count];
2298        for (slot, &eid) in card1.iter().enumerate() {
2299            local_of[eid as usize] = slot as u32;
2300        }
2301        // Card 0 addresses its FULL resident bank by global id.
2302        for e in 0..expert_count {
2303            if rank_of[e] == 0 {
2304                local_of[e] = e as u32;
2305            }
2306        }
2307        Ok(LayerPlacement {
2308            card1,
2309            local_of,
2310            rank_of,
2311        })
2312    }
2313}
2314
2315/// Engagement counter: PEER-owned (card 1) expert slots dispatched by the TP2 MoE split,
2316/// since process start. Copied from the glm5 TP lane's
2317/// `GLM5_EP_PEER_SLOT_DISPATCHES` for the reason that lane learned the hard way — its
2318/// first seed search found a token stream that NEVER routed a peer expert, so the arm's
2319/// identity claim would have been VACUOUS. Any TP2 exactness claim must assert this
2320/// counter moved, or it is a claim about a program that did not run.
2321static TP2_PEER_EXPERT_SLOTS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2322/// Same for card 0, so a receipt can print the per-rank token-touch/byte split instead of
2323/// only proving non-vacuity (the glm5 lane reported its ~99.3% peer-touch and ~64%
2324/// slowest-rank byte fraction as CLOSED-FORM derivations with no measurement behind them;
2325/// these two counters are what make ours measured).
2326static TP2_HOME_EXPERT_SLOTS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2327/// Layer-tokens whose top-k touched BOTH cards (the "peer is on the critical path"
2328/// fraction — the number the glm5 lane derived as ~99.3% for its 288/top-8 geometry).
2329static TP2_BOTH_TOUCH_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2330static TP2_TOUCH_ROWS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
2331
2332/// (peer slots, home slots, rows touching both cards, rows counted) since process start.
2333pub fn tp2_expert_split_stats() -> (u64, u64, u64, u64) {
2334    use std::sync::atomic::Ordering::Relaxed;
2335    (
2336        TP2_PEER_EXPERT_SLOTS.load(Relaxed),
2337        TP2_HOME_EXPERT_SLOTS.load(Relaxed),
2338        TP2_BOTH_TOUCH_ROWS.load(Relaxed),
2339        TP2_TOUCH_ROWS.load(Relaxed),
2340    )
2341}
2342
2343fn tp2_count_split(routes0: &[Vec<(usize, f32)>], routes1: &[Vec<(usize, f32)>]) {
2344    use std::sync::atomic::Ordering::Relaxed;
2345    let (mut peer, mut home, mut both) = (0u64, 0u64, 0u64);
2346    for (r0, r1) in routes0.iter().zip(routes1.iter()) {
2347        home += r0.len() as u64;
2348        peer += r1.len() as u64;
2349        if !r0.is_empty() && !r1.is_empty() {
2350            both += 1;
2351        }
2352    }
2353    TP2_HOME_EXPERT_SLOTS.fetch_add(home, Relaxed);
2354    TP2_PEER_EXPERT_SLOTS.fetch_add(peer, Relaxed);
2355    TP2_BOTH_TOUCH_ROWS.fetch_add(both, Relaxed);
2356    TP2_TOUCH_ROWS.fetch_add(routes0.len() as u64, Relaxed);
2357}
2358
2359/// Gate-only deliberate defects for the TP2 class gate: `MEMRA_Q4E_TP2_GATE_RED=<name>`.
2360/// A band is only a bar if a WRONG program lands orders outside it, so the gate runs
2361/// these and REQUIRES them to be loud (the glm5 `MEMRA_GLM5_TP_GATE_RED` pattern).
2362/// Never a serving door — an unknown value refuses at the first MoE layer.
2363#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2364pub enum Tp2GateRed {
2365    None,
2366    /// Drop the peer card's routed-expert contribution from the join.
2367    SkipPeerMoe,
2368    /// Route peer-owned experts to card 0's bank at their LOCAL slot — a plausible
2369    /// off-by-remap bug (right magnitudes, wrong experts).
2370    PeerLocalIds,
2371    /// Feed the peer half its slot weights in reversed order within each token.
2372    ReverseePeerWeights,
2373}
2374
2375fn tp2_gate_red() -> Res<Tp2GateRed> {
2376    static C: std::sync::OnceLock<Result<Tp2GateRed, String>> = std::sync::OnceLock::new();
2377    C.get_or_init(
2378        || match std::env::var("MEMRA_Q4E_TP2_GATE_RED").as_deref() {
2379            Err(_) | Ok("") | Ok("0") | Ok("none") => Ok(Tp2GateRed::None),
2380            Ok("skip-peer-moe") => Ok(Tp2GateRed::SkipPeerMoe),
2381            Ok("peer-local-ids") => Ok(Tp2GateRed::PeerLocalIds),
2382            Ok("reverse-peer-weights") => Ok(Tp2GateRed::ReverseePeerWeights),
2383            Ok(other) => Err(format!(
2384                "MEMRA_Q4E_TP2_GATE_RED={other:?}: want skip-peer-moe|peer-local-ids|\
2385             reverse-peer-weights|none"
2386            )),
2387        },
2388    )
2389    .clone()
2390    .map_err(Into::into)
2391}
2392
2393/// Per-layer MoE route trace in the FROZEN shared format
2394/// `tools/build_expert_placement_map.py` consumes (`<layer> <t> <id,id,...>`, one line
2395/// per (layer, forward); decode steps are t == 1) — byte-compatible with
2396/// `hybrid_forward.rs::trace_moe_routes` so one tool reads both arms' traces.
2397///
2398/// Doors: `MEMRA_MOE_TRACE` (ids) and `MEMRA_MOE_WEIGHT_TRACE` (`<expert>:<weight>`).
2399/// Both OFF by default: this writes an unbounded append-only file and costs host I/O per
2400/// layer per forward, which is fine for a battery and wrong for serving.
2401///
2402/// Where it taps, and the honest limit: the qwen4_exp MoE route exists on the HOST on
2403/// the TP2 route (which keeps the host router twin by construction) and on the
2404/// per-expert prefill executor. Under the shipped single-card default the route is
2405/// DEVICE-side (`routerdev`, PROFILE-9) with no readback at all, so there is nothing to
2406/// tap without re-adding the very sync that lane deleted — arming
2407/// `MEMRA_Q4E_ROUTER_AUDIT=1` restores a host recompute of every device route and the
2408/// trace rides THAT readback at zero new syncs. So: TP2 batteries trace for free;
2409/// single-card batteries trace with the audit armed.
2410fn trace_moe_routes(layer: u32, t: usize, routes: &[Vec<(usize, f32)>]) {
2411    use std::io::Write as _;
2412    static IDS: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
2413    static WEIGHTS: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
2414    let ids = IDS.get_or_init(|| {
2415        std::env::var("MEMRA_MOE_TRACE")
2416            .ok()
2417            .filter(|p| !p.is_empty())
2418    });
2419    let weights = WEIGHTS.get_or_init(|| {
2420        std::env::var("MEMRA_MOE_WEIGHT_TRACE")
2421            .ok()
2422            .filter(|p| !p.is_empty())
2423    });
2424    if ids.is_none() && weights.is_none() {
2425        return;
2426    }
2427    // One line per (layer, forward) with EVERY row's selections concatenated is what the
2428    // shared format specifies for t > 1 forwards, and the tool's co-occurrence is
2429    // "within-line", so a prefill chunk's line legitimately carries t tokens' picks.
2430    let flat: Vec<&(usize, f32)> = routes.iter().flatten().collect();
2431    let append = |path: &str, body: String| {
2432        if let Ok(mut f) = std::fs::OpenOptions::new()
2433            .create(true)
2434            .append(true)
2435            .open(path)
2436        {
2437            let _ = writeln!(f, "{layer} {t} {body}");
2438        }
2439    };
2440    if let Some(path) = ids {
2441        let body: Vec<String> = flat.iter().map(|(e, _)| e.to_string()).collect();
2442        append(path, body.join(","));
2443    }
2444    if let Some(path) = weights {
2445        let body: Vec<String> = flat.iter().map(|(e, w)| format!("{e}:{w:.9}")).collect();
2446        append(path, body.join(","));
2447    }
2448}
2449
2450/// Arm or disarm ONE seam by its `MEMRA_Q4E_SEAMS` name, returning false when the name is
2451/// unknown. Extracted from `apply_env_seams` (which is now its only-at-startup caller) so a
2452/// measurement harness can flip a seam BETWEEN timed rounds inside one process — the
2453/// interleaved-A/B instrument the 262k host lane needs, because at these depths a per-arm
2454/// process pays a fresh 25-80 minute prefill for a decode-only lever and box clock drift
2455/// then sits between the arms. `value` carries the raw `name=value` right-hand side for the
2456/// three-valued seams; `on` is already decoded for the boolean ones.
2457///
2458/// This is a MEASUREMENT seam-setter, not a serving one: flipping a seam mid-run is sound
2459/// only for seams whose state is rebuildable from the token history (`plecache` appends to a
2460/// cache it can also rebuild by longest-common-prefix), and the caller owns that judgement.
2461pub fn set_seam(name: &str, on: bool, value: Option<&str>) -> bool {
2462    seam_dispatch(name, on, value, true)
2463}
2464
2465/// The CURRENT boolean state of a seam, for exact save/restore around a measurement that
2466/// flips it. `None` for a name with no boolean state (`idxq` is three-valued, `longatt`
2467/// three-valued) and for an unknown name.
2468///
2469/// This exists because the alternative — "restore by re-running `apply_env_seams`" — is
2470/// wrong in a way that would not show up as a failure: a seam absent from
2471/// `MEMRA_Q4E_SEAMS` is not reset by that call, so the run would silently continue on
2472/// whichever arm happened to execute last. Save/restore has to read the real state.
2473pub fn seam_state(name: &str) -> Option<bool> {
2474    Some(match name {
2475        "moe" => moe_sel_path_on(),
2476        "hc" => hc_fused_gate_on(),
2477        "trunk" => trunk_bf16_on(),
2478        "ws" => step_ws_on(),
2479        "graph" => decode_graphs_on(),
2480        "selv2" => sel_v2_on(),
2481        "hcmicro" => hc_micro_on(),
2482        "selv3" => sel_v3_on(),
2483        "gdnstep" => gdn_step_on(),
2484        "gdnfuse" => gdn_fuse_on(),
2485        "projstack" => proj_stack_on(),
2486        "hcdiet" => hc_diet_on(),
2487        "gufuse" => sel_gufuse_on(),
2488        "routerb16" => router_bf16_on(),
2489        "vgraph" => verify_graphs_on(),
2490        "idxdev" => idx_dev_on(),
2491        "idxsel" => idx_sel_on(),
2492        "plecache" => ple_cache_on(),
2493        "routerdev" => router_dev_on(),
2494        "idxcache" => idx_cache_on(),
2495        "kvq" => kv_quant_on(),
2496        "kvhoist" => kv_hoist_on(),
2497        "poolT" => pool_t_on(),
2498        _ => return None,
2499    })
2500}
2501
2502/// Does this seam name exist? Same table as `set_seam`, applying NOTHING. A harness that
2503/// validates a seam name up front (before a 25-80 minute prefill it would otherwise waste on
2504/// a typo) must not have to arm or disarm the seam to find out — a validator with a silent
2505/// side effect on global state is the kind of thing that later reads as a mystery flip.
2506pub fn seam_exists(name: &str) -> bool {
2507    seam_dispatch(name, false, None, false)
2508}
2509
2510/// Every seam name `seam_dispatch` accepts, as DATA, sitting directly above the match so the two
2511/// are read together. `gate_seam_table` walks this list, so a name here that the match does not
2512/// accept fails that gate loudly.
2513///
2514/// The reverse drift — a match arm added without a list entry — is NOT machine-detectable from
2515/// here, and that seam is then uncovered rather than wrong. Said out loud instead of dressed up
2516/// as completeness, because a non-vacuity check that cannot fail is worse than no check.
2517/// **Adding a seam: add its arm below AND its name here.**
2518pub fn seam_names() -> &'static [&'static str] {
2519    &[
2520        "moe",
2521        "hc",
2522        "trunk",
2523        "ws",
2524        "graph",
2525        "selv2",
2526        "hcmicro",
2527        "selv3",
2528        "gdnstep",
2529        "gdnfuse",
2530        "projstack",
2531        "hcdiet",
2532        "gufuse",
2533        "routerb16",
2534        "vgraph",
2535        "longatt",
2536        "idxdev",
2537        "idxsel",
2538        "plecache",
2539        "routerdev",
2540        "idxcache",
2541        "kvq",
2542        "idxq",
2543        "kvhoist",
2544        "poolT",
2545    ]
2546}
2547
2548/// The one seam name table. `apply` false walks the same arms and calls no setter, so the
2549/// name check and the action can never drift apart.
2550fn seam_dispatch(name: &str, on: bool, value: Option<&str>, apply: bool) -> bool {
2551    macro_rules! seam {
2552        ($call:expr) => {{
2553            if apply {
2554                $call;
2555            }
2556            true
2557        }};
2558    }
2559    match name {
2560        "moe" => seam!(set_moe_sel_path(on)),
2561        "hc" => seam!(set_hc_fused_gate(on)),
2562        "trunk" => seam!(set_trunk_bf16(on)),
2563        "ws" => seam!(set_step_ws(on)),
2564        "graph" => seam!(set_decode_graphs(on)),
2565        "selv2" => seam!(set_sel_v2(on)),
2566        "hcmicro" => seam!(set_hc_micro(on)),
2567        "selv3" => seam!(set_sel_v3(on)),
2568        "gdnstep" => seam!(set_gdn_step(on)),
2569        "gdnfuse" => seam!(set_gdn_fuse(on)),
2570        "projstack" => seam!(set_proj_stack(on)),
2571        "hcdiet" => seam!(set_hc_diet(on)),
2572        "gufuse" => seam!(set_sel_gufuse(on)),
2573        "routerb16" => seam!(set_router_bf16(on)),
2574        "vgraph" => seam!(set_verify_graphs(on)),
2575        "longatt" => seam!(set_longatt(if on { "force" } else { "off" })),
2576        "idxdev" => seam!(set_idx_dev(on)),
2577        "idxsel" => seam!(set_idx_sel(on)),
2578        "plecache" => seam!(set_ple_cache(on)),
2579        "routerdev" => seam!(set_router_dev(on)),
2580        "idxcache" => seam!(set_idx_cache(on)),
2581        "kvq" => seam!(set_kv_quant(on)),
2582        // Bit-identical READ-PATTERN seams (memory lane): no layout latch on `kvhoist`,
2583        // and `poolT` re-mirrors on flip, so both are sound to flip between timed rounds.
2584        "kvhoist" => seam!(set_kv_hoist(on)),
2585        "poolT" => seam!(set_pool_t(on)),
2586        // Three-valued: `idxq=q8`, `idxq=bf16`, `idxq=0`/`idxq=f32` (rollback);
2587        // bare `idxq` arms the q8 target.
2588        "idxq" => seam!(set_idxq(value.unwrap_or("q8"))),
2589        _ => {
2590            debug_assert!(
2591                !seam_names().contains(&name),
2592                "seam_names() lists {name:?} but seam_dispatch has no arm for it"
2593            );
2594            false
2595        }
2596    }
2597}
2598
2599pub fn apply_env_seams() {
2600    let Ok(spec) = std::env::var("MEMRA_Q4E_SEAMS") else {
2601        return;
2602    };
2603    for part in spec.split(',').filter(|p| !p.is_empty()) {
2604        let (name, on) = match part.split_once('=') {
2605            Some((n, v)) => (n, v != "0"),
2606            None => (part, true),
2607        };
2608        if !set_seam(name, on, part.split_once('=').map(|(_, v)| v)) {
2609            eprintln!("MEMRA_Q4E_SEAMS: unknown seam {name:?} ignored");
2610        }
2611    }
2612}
2613
2614/// Per-piece kill switches for the hcmicro bundle (bisect instrumentation: set
2615/// MEMRA_Q4E_MICRO_{NORM,INJ,SHEXP}=0 to fall a single piece back while the seam stays
2616/// on). Read once per process.
2617fn micro_env_on(name: &'static str, cell: &'static std::sync::OnceLock<bool>) -> bool {
2618    *cell.get_or_init(|| std::env::var(name).as_deref() != Ok("0"))
2619}
2620
2621fn micro_norm_on() -> bool {
2622    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2623    hc_micro_on() && micro_env_on("MEMRA_Q4E_MICRO_NORM", &C)
2624}
2625
2626fn micro_inj_on() -> bool {
2627    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2628    hc_micro_on() && micro_env_on("MEMRA_Q4E_MICRO_INJ", &C)
2629}
2630
2631fn micro_shexp_on() -> bool {
2632    static C: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2633    hc_micro_on() && micro_env_on("MEMRA_Q4E_MICRO_SHEXP", &C)
2634}
2635
2636/// Run `f` as a named profile section (sync–time–sync when profiling is on).
2637fn prof_section<T>(e: &Engine, name: &'static str, f: impl FnOnce() -> Res<T>) -> Res<T> {
2638    if !prof::on() {
2639        return f();
2640    }
2641    e.gpu.stream().synchronize()?;
2642    let t0 = std::time::Instant::now();
2643    let out = f()?;
2644    e.gpu.stream().synchronize()?;
2645    prof::add(name, t0.elapsed().as_secs_f64());
2646    Ok(out)
2647}
2648
2649// ---------------------------------------------------------------- host twins (oracle math)
2650
2651fn host_sigmoid(x: f32) -> f32 {
2652    1.0 / (1.0 + (-x).exp())
2653}
2654
2655/// memra_reference `softmax_in_place` twin.
2656fn host_softmax(values: &mut [f32]) {
2657    let max = values.iter().copied().fold(f32::NEG_INFINITY, f32::max);
2658    let mut sum = 0.0;
2659    for value in values.iter_mut() {
2660        *value = (*value - max).exp();
2661        sum += *value;
2662    }
2663    for value in values {
2664        *value /= sum;
2665    }
2666}
2667
2668/// The router renorm denominator floor (memra_reference `route_experts`, mirrored by
2669/// the device twin). Note it is UNBINDABLE on real softmax geometry: the top-k weights
2670/// are the k largest of a distribution summing to 1, so their sum is >= k/experts
2671/// (10/512 ~ 0.0195 >> 6.1e-5) — kept because the reference ships it.
2672const ROUTE_DENOM_FLOOR: f32 = 6.103_515_6e-5;
2673
2674/// memra_reference `route_experts` twin, Softmax arm only (qwen4_exp router — softmax,
2675/// top-k renormalized with the 6.1035156e-5 floor, tie rule score-desc/index-asc).
2676fn host_route_softmax_topk(logits: &[f32], selected: usize) -> Vec<(usize, f32)> {
2677    let mut weights = logits.to_vec();
2678    host_softmax(&mut weights);
2679    let mut indices: Vec<usize> = (0..logits.len()).collect();
2680    indices.sort_by(|&left, &right| {
2681        weights[right]
2682            .total_cmp(&weights[left])
2683            .then(left.cmp(&right))
2684    });
2685    indices.truncate(selected);
2686    let denominator = indices
2687        .iter()
2688        .map(|&index| weights[index])
2689        .sum::<f32>()
2690        .max(ROUTE_DENOM_FLOOR);
2691    indices
2692        .into_iter()
2693        .map(|index| (index, weights[index] / denominator))
2694        .collect()
2695}
2696
2697/// memra_reference `rms_norm` twin (host, effective weights).
2698fn host_rms_norm(x: &mut [f32], width: usize, weight: &[f32], epsilon: f32) {
2699    for row in x.chunks_exact_mut(width) {
2700        let mean_square = row.iter().map(|v| v * v).sum::<f32>() / width as f32;
2701        let inverse = 1.0 / (mean_square + epsilon).sqrt();
2702        for (value, w) in row.iter_mut().zip(weight) {
2703            *value = *value * inverse * w;
2704        }
2705    }
2706}
2707
2708/// memra_reference `apply_rope_at_position` twin (NeoX split-half). `yarn` = the shared
2709/// (divisor table, mscale) pair when the plan carries YaRN factors — identical divisor
2710/// semantics to the reference (`frequency / divisor`, cos/sin scaled by mscale); `None`
2711/// keeps the historical byte-exact plain path.
2712fn host_rope_at(
2713    values: &mut [f32],
2714    head_dim: usize,
2715    dimensions: usize,
2716    base: f32,
2717    yarn: Option<(&[f32], f32)>,
2718    position: usize,
2719) {
2720    let dimensions = dimensions.min(head_dim) / 2 * 2;
2721    let half = dimensions / 2;
2722    for head in values.chunks_exact_mut(head_dim) {
2723        for index in 0..half {
2724            let frequency = base.powf(-2.0 * index as f32 / dimensions as f32);
2725            let frequency = match yarn {
2726                Some((ff, _)) => frequency / ff[index],
2727                None => frequency,
2728            };
2729            let angle = position as f32 * frequency;
2730            let (sin, cos) = angle.sin_cos();
2731            let (sin, cos) = match yarn {
2732                Some((_, mscale)) => (sin * mscale, cos * mscale),
2733                None => (sin, cos),
2734            };
2735            let first = head[index];
2736            let second = head[index + half];
2737            head[index] = first * cos - second * sin;
2738            head[index + half] = first * sin + second * cos;
2739        }
2740    }
2741}
2742
2743/// What the forward's exit computes (chunked long-context prefill skips the head: the
2744/// [t, vocab] logits block of a big chunk is gigabytes and reads/writes no state).
2745#[derive(Clone, Copy, PartialEq, Eq)]
2746pub enum HeadMode {
2747    /// Exit mixer + lm_head on every row ([t, vocab] logits) — the historical shape.
2748    All,
2749    /// Exit mixer on the chunk, lm_head on the LAST row only ([vocab] logits).
2750    LastRow,
2751    /// No exit mixer, no lm_head, empty return (mid-prefill chunks).
2752    Skip,
2753}
2754
2755/// One query row's QSA visibility in BLOCK form — the selection's native shape (the
2756/// dense [t, t_kv] mask is a rendering of this for the smem-bounded masked kernel; the
2757/// long-context block-list kernel consumes it directly).
2758struct RowSel {
2759    /// Structural fast path (complete <= budget): the FULL causal prefix is visible.
2760    full: bool,
2761    /// Selected complete blocks, ascending. Empty when `full`.
2762    blocks: Vec<u32>,
2763    /// Visible prefix length (absolute row + 1). Positions
2764    /// [complete*block_size .. visible) are the always-visible incomplete tail.
2765    visible: usize,
2766}
2767
2768/// Extend the POOLED indexer-key cache to cover every complete block of `raw_keys`:
2769/// fp32 mean over the block's raw rows (offset-outer/dim-inner, the historical loop
2770/// order), k_layernorm, rope at the block-start position + pos_off. A block's pooled key
2771/// never depends on the query row, so each block is computed ONCE — bit-identical to the
2772/// historical per-(row, block) recompute.
2773#[allow(clippy::too_many_arguments)]
2774fn extend_pooled_keys(
2775    pooled_keys: &mut Vec<f32>,
2776    raw_keys: &IdxRawCache,
2777    head_dim: usize,
2778    block_size: usize,
2779    idx_k_norm: &[f32],
2780    epsilon: f32,
2781    rope_dims: usize,
2782    rope_base: f32,
2783    yarn: Option<(&[f32], f32)>,
2784    pos_off: usize,
2785) {
2786    let complete_total = raw_keys.rows(head_dim) / block_size;
2787    let cached = pooled_keys.len() / head_dim;
2788    let mut block_rows: Vec<f32> = Vec::new();
2789    for block in cached..complete_total {
2790        let start = block * block_size;
2791        // idxq lane: dequant the block's raw rows at read; the fp32 mean-pool below is
2792        // the historical op order verbatim (f32 arm: an exact copy of the same rows).
2793        raw_keys.rows_f32(start, block_size, head_dim, &mut block_rows);
2794        let mut pooled = vec![0.0f32; head_dim];
2795        for offset in 0..block_size {
2796            for dim in 0..head_dim {
2797                pooled[dim] += block_rows[offset * head_dim + dim];
2798            }
2799        }
2800        for value in &mut pooled {
2801            *value /= block_size as f32;
2802        }
2803        host_rms_norm(&mut pooled, head_dim, idx_k_norm, epsilon);
2804        host_rope_at(
2805            &mut pooled,
2806            head_dim,
2807            rope_dims,
2808            rope_base,
2809            yarn,
2810            start + pos_off,
2811        );
2812        pooled_keys.extend_from_slice(&pooled);
2813    }
2814}
2815
2816/// Comparator of the pinned tie rule: score desc, block index asc (a STRICT total order
2817/// — `total_cmp` plus the index tiebreak leaves no equal pair).
2818#[inline]
2819fn sel_cmp(scores: &[f32], a: u32, b: u32) -> std::cmp::Ordering {
2820    scores[b as usize]
2821        .total_cmp(&scores[a as usize])
2822        .then(a.cmp(&b))
2823}
2824
2825/// Top-`budget` blocks under the pinned tie rule, returned ASCENDING. Replaces the
2826/// historical full `sort_by` + `take(budget)` with `select_nth_unstable_by` under the
2827/// SAME strict total order — the kept SET is identical by definition of a total order
2828/// (both keep exactly the `budget` smallest elements under the comparator), and the
2829/// emitted ascending order erases any within-set permutation. When the block count is
2830/// large, disjoint ranges are reduced to per-range top-`budget` candidates first: any
2831/// global top-`budget` element is beaten by fewer than `budget` blocks overall, hence by
2832/// fewer than `budget` in its own range, hence survives its range cut — the union of
2833/// range winners contains the global set, and the final cut recovers it EXACTLY.
2834fn top_blocks_ascending(scores: &[f32], budget: usize, threads: usize) -> Vec<u32> {
2835    fn cut(scores: &[f32], idx: &mut Vec<u32>, budget: usize) {
2836        let k = budget.min(idx.len());
2837        if k < idx.len() {
2838            idx.select_nth_unstable_by(k - 1, |&a, &b| sel_cmp(scores, a, b));
2839            idx.truncate(k);
2840        }
2841    }
2842    let complete = scores.len();
2843    debug_assert!(budget < complete);
2844    const PAR_MIN: usize = 1 << 15;
2845    let mut candidates: Vec<u32> = if threads > 1 && complete >= PAR_MIN {
2846        let ranges: Vec<(u32, u32)> = {
2847            let per = complete.div_ceil(threads);
2848            (0..threads)
2849                .map(|i| ((i * per) as u32, ((i + 1) * per).min(complete) as u32))
2850                .filter(|(a, b)| a < b)
2851                .collect()
2852        };
2853        std::thread::scope(|scope| {
2854            let handles: Vec<_> = ranges
2855                .iter()
2856                .map(|&(a, b)| {
2857                    scope.spawn(move || {
2858                        let mut idx: Vec<u32> = (a..b).collect();
2859                        cut(scores, &mut idx, budget);
2860                        idx
2861                    })
2862                })
2863                .collect();
2864            handles
2865                .into_iter()
2866                .flat_map(|h| h.join().unwrap())
2867                .collect()
2868        })
2869    } else {
2870        (0..complete as u32).collect()
2871    };
2872    cut(scores, &mut candidates, budget);
2873    candidates.sort_unstable();
2874    candidates
2875}
2876
2877/// Score every complete block for one prepared query row (relu-sum over heads / sqrt(d),
2878/// fp32 — the reference arithmetic verbatim, reading the pooled cache). Parallel over
2879/// DISJOINT block ranges when large: per-block values are independent, so the split
2880/// changes nothing but wall time.
2881fn score_blocks(
2882    query: &[f32],
2883    pooled_keys: &[f32],
2884    heads: usize,
2885    head_dim: usize,
2886    complete: usize,
2887    scale: f32,
2888    threads: usize,
2889) -> Vec<f32> {
2890    let mut scores = vec![0.0f32; complete];
2891    let run = |scores: &mut [f32], block0: usize| {
2892        for (i, slot) in scores.iter_mut().enumerate() {
2893            let block = block0 + i;
2894            let pooled = &pooled_keys[block * head_dim..(block + 1) * head_dim];
2895            let mut score = 0.0f32;
2896            for head in 0..heads {
2897                let mut dot = 0.0f32;
2898                for dim in 0..head_dim {
2899                    dot += query[head * head_dim + dim] * pooled[dim];
2900                }
2901                score += dot.max(0.0);
2902            }
2903            *slot = score / scale;
2904        }
2905    };
2906    const PAR_MIN: usize = 1 << 14;
2907    if threads > 1 && complete >= PAR_MIN {
2908        let per = complete.div_ceil(threads);
2909        let run = &run;
2910        std::thread::scope(|scope| {
2911            for (i, chunk) in scores.chunks_mut(per).enumerate() {
2912                scope.spawn(move || run(chunk, i * per));
2913            }
2914        });
2915    } else {
2916        run(&mut scores, 0);
2917    }
2918    scores
2919}
2920
2921/// memra_reference `micro_block_selection_mask` twin over the raw-key CACHE — the decode
2922/// form of the same program in BLOCK form: per query token at absolute position
2923/// `base_pos + qt`, score the pooled complete blocks (cache: `extend_pooled_keys`), then
2924/// the pinned tie rule (score desc, block index asc) and the always-visible incomplete
2925/// tail. Values and selected sets are bit-identical to the historical per-row recompute
2926/// (see the helper docs above); rows are computed in PARALLEL when the work is large
2927/// (rows are independent; single-row chunks parallelize across block ranges instead).
2928#[allow(clippy::too_many_arguments)]
2929#[allow(clippy::too_many_arguments)]
2930fn indexer_select_rows(
2931    overlay: &MicroBlockIndexPlan,
2932    rope_base: f32,
2933    // YaRN (divisors, mscale) — the indexer consumes the MAIN rotary (SEMANTICS.md §Rope),
2934    // so the caller passes the layer's shared table; `None` on the shipped config.
2935    yarn: Option<(&[f32], f32)>,
2936    epsilon: f32,
2937    idx_q_norm: &[f32],
2938    idx_k_norm: &[f32],
2939    proj_rows: &[f32],      // [t, (ih+ikv)*id] this chunk's index_qk_proj output
2940    raw_keys: &IdxRawCache, // [t_kv, id] cache INCLUDING the current chunk
2941    pooled_keys: &mut Vec<f32>,
2942    // Device scorer (long-context lane): `Some((engine, device pooled mirror, mirrored
2943    // rows))` runs block scoring on the GPU with the host twin's exact arithmetic
2944    // (thread-per-block sequential dim loop, same relu-sum, same division — bit-identical
2945    // scores, identical selected sets); the mirror grows by H2D of the new rows. `None`
2946    // keeps the pure-host path (the tiny/reference shape).
2947    mut dev: Option<(&Engine, &mut Option<CudaSlice<f32>>, &mut usize)>,
2948    base_pos: usize,
2949    t: usize,
2950    t_kv: usize,
2951    // Rope-position offset: cache row i carries absolute position i + pos_off. 0 for
2952    // the trunk; 1 for the MTP draft, whose row i holds TARGET position i + 1
2953    // (position 0 never enters the draft — SGLang alignment, SEMANTICS.md §MTP).
2954    pos_off: usize,
2955) -> Res<Vec<RowSel>> {
2956    let heads = overlay.query_heads as usize;
2957    let head_dim = overlay.head_dim as usize;
2958    let block_size = overlay.block_size as usize;
2959    let budget_blocks = overlay.budget_blocks as usize;
2960    let rope_dims = overlay.rope_dimensions as usize;
2961    let qk_width = (heads + overlay.kv_heads as usize) * head_dim;
2962    let scale = (head_dim as f32).sqrt();
2963    debug_assert_eq!(raw_keys.rows(head_dim), t_kv);
2964    extend_pooled_keys(
2965        pooled_keys,
2966        raw_keys,
2967        head_dim,
2968        block_size,
2969        idx_k_norm,
2970        epsilon,
2971        rope_dims,
2972        rope_base,
2973        yarn,
2974        pos_off,
2975    );
2976    let threads = std::thread::available_parallelism()
2977        .map(|n| n.get())
2978        .unwrap_or(1);
2979    // ---- device scoring path: mirror the new pooled rows, then score in row
2980    // sub-batches (the score slab is rows x n_blocks floats — at 250k blocks a whole
2981    // prefill chunk of rows would be terabytes, so rows batch).
2982    if let Some((e, mirror, mirrored)) = dev.as_mut() {
2983        let rows_needed: Vec<usize> = (0..t)
2984            .map(|qt| (base_pos + qt + 1) / block_size)
2985            .filter(|&c| c > budget_blocks)
2986            .collect();
2987        if let Some(&max_blocks) = rows_needed.iter().max() {
2988            let pooled_rows = pooled_keys.len() / head_dim;
2989            // Grow + fill the device mirror with any rows it does not have yet.
2990            let want = pooled_rows.max(max_blocks);
2991            // POOL_PLANES regions of `cap_rows * head_dim`: the row-major mirror, then the
2992            // dim-major `poolT` plane. The pitch of the plane is `cap_rows`, so it is baked at
2993            // allocation and a capacity change invalidates the plane's addressing — hence the
2994            // full re-mirror below rather than a strided forward copy of the old plane.
2995            if mirror
2996                .as_ref()
2997                .is_none_or(|m| m.len() < want * head_dim * POOL_PLANES)
2998            {
2999                let cap_rows = want.next_power_of_two().max(1024);
3000                let fresh = e.zeros(cap_rows * head_dim * POOL_PLANES)?;
3001                // The old growth path copied the mirrored prefix forward and kept `**mirrored`.
3002                // That is not sound for the plane (new pitch => every dim lands elsewhere), and a
3003                // half-addressed plane scores stale keys silently. Re-mirror from the host cache
3004                // instead, which holds every row and is the same source the append already uses.
3005                // Costs one H2D of the pooled cache per capacity DOUBLING (log2 times over a
3006                // fill), against a class of wrong-value bug this lane has already paid for twice.
3007                **mirror = Some(fresh);
3008                **mirrored = 0;
3009            }
3010            let m = mirror.as_mut().expect("allocated above");
3011            if pooled_rows > **mirrored {
3012                let delta = &pooled_keys[**mirrored * head_dim..pooled_rows * head_dim];
3013                let mut view = m.slice_mut(**mirrored * head_dim..pooled_rows * head_dim);
3014                e.gpu.stream().memcpy_htod(delta, &mut view)?;
3015                // `poolT`: keep the DIM-MAJOR twin of the same rows in the second half of the
3016                // buffer. Both layouts are maintained UNCONDITIONALLY and only the kernel choice
3017                // reads the seam. Two reasons, and the second is the important one:
3018                //
3019                //  - Experimental design. The append is then identical in both A/B arms, so the
3020                //    measurement isolates exactly the variable under test (the READ pattern) and
3021                //    the transpose cost cannot flatter or penalise either arm.
3022                //  - There is no silent-wrong-value mode. A seam that is flippable between timed
3023                //    rounds plus a layout that is only maintained while armed means an arm that
3024                //    was OFF for a while leaves the plane missing every row appended meanwhile —
3025                //    and a stale pooled plane scores stale keys, which reads as plausible output
3026                //    rather than as a failure. Maintaining both makes `**mirrored` the single
3027                //    truth for BOTH layouts, so a flip needs no rebuild and can leave nothing
3028                //    behind. (Same class as the `pooled_dev_rows` truncation trap already
3029                //    recorded at the rewind sites.)
3030                //
3031                // Instrument cost, stated: one pooled plane of extra VRAM (33.5 MB at the 262,144
3032                // target geometry, 1.6% of the ~2 GB free there) plus one transpose over the
3033                // delta — 512 rows per 2,048-token prefill chunk, 0-1 rows per decode step. When
3034                // the A/B verdict lands, the losing layout goes away in the same commit; carrying
3035                // both is an A/B instrument, not a shipping design.
3036                let cap_rows = m.len() / (head_dim * POOL_PLANES);
3037                launch_qsa_pooled_transpose(
3038                    e,
3039                    m,
3040                    **mirrored,
3041                    pooled_rows - **mirrored,
3042                    head_dim,
3043                    cap_rows,
3044                )?;
3045                **mirrored = pooled_rows;
3046            }
3047            // Per-row prepared queries (norm + rope) — the host twin's own preparation.
3048            let mut sels: Vec<RowSel> = Vec::with_capacity(t);
3049            let mut queries: Vec<f32> = Vec::new();
3050            let mut scored_rows: Vec<usize> = Vec::new();
3051            for qt in 0..t {
3052                let row = base_pos + qt;
3053                let visible = row + 1;
3054                let complete = visible / block_size;
3055                if complete <= budget_blocks {
3056                    sels.push(RowSel {
3057                        full: true,
3058                        blocks: Vec::new(),
3059                        visible,
3060                    });
3061                    continue;
3062                }
3063                let mut query = proj_rows[qt * qk_width..qt * qk_width + heads * head_dim].to_vec();
3064                host_rms_norm(&mut query, head_dim, idx_q_norm, epsilon);
3065                host_rope_at(
3066                    &mut query,
3067                    head_dim,
3068                    rope_dims,
3069                    rope_base,
3070                    yarn,
3071                    row + pos_off,
3072                );
3073                queries.extend_from_slice(&query);
3074                scored_rows.push(qt);
3075                sels.push(RowSel {
3076                    full: false,
3077                    blocks: Vec::new(),
3078                    visible,
3079                });
3080            }
3081            // Row sub-batches bounded by the score slab (default 32 M floats = 128 MB).
3082            //
3083            // TUNABLE because this constant appears to SET THE 262k PERFORMANCE CLIFF.
3084            // `qsa.idx_host` grows linearly with fill up to 120,000 (2,710 -> 3,199 ms) and then
3085            // jumps 16x to 51,235 ms — 83% of a prefill chunk — somewhere before 131,072. The
3086            // arithmetic lands exactly there: rows per sub-batch is `SCORE_CAP / complete`, and
3087            // at fill 131,072 `complete = 32,768`, so `per = 1,024` and 2,048 scored rows fit in
3088            // EXACTLY 2 sub-batches; one block deeper it becomes 3. Each sub-batch does an
3089            // `e.htod` plus an `e.uninit` of up to 128 MB and ends in a BLOCKING `dtoh`, at
3090            // depths where card 0 has ~2-4 GB free.
3091            //
3092            // The test this knob exists for: if the cliff MOVES with the cap, the mechanism is
3093            // the sub-batch transition (and the fix is a persistent pooled slab, or a cap that
3094            // keeps the transition out of the product window). If the cliff does NOT move, the
3095            // hypothesis is dead and the next suspect is the blocking dtoh count.
3096            // Default 32 reproduces today's behaviour exactly.
3097            let score_cap_mf: usize = std::env::var("MEMRA_Q4E_IDX_SCORE_CAP_MF")
3098                .ok()
3099                .and_then(|v| v.parse::<usize>().ok())
3100                .filter(|v| *v > 0)
3101                .unwrap_or(32);
3102            let score_cap: usize = score_cap_mf << 20;
3103            #[allow(non_snake_case)]
3104            let SCORE_CAP = score_cap;
3105            let mut done = 0usize;
3106            while done < scored_rows.len() {
3107                // Every row in a batch scores its OWN block count; the kernel writes a
3108                // rows x max_blocks slab and each row reads its own prefix.
3109                let batch_max = scored_rows[done..]
3110                    .iter()
3111                    .map(|&qt| (base_pos + qt + 1) / block_size)
3112                    .max()
3113                    .unwrap_or(0);
3114                let per = (SCORE_CAP / batch_max.max(1)).max(1);
3115                let n = per.min(scored_rows.len() - done);
3116                let qslab = &queries[done * heads * head_dim..(done + n) * heads * head_dim];
3117                let q_dev = e.htod(qslab)?;
3118                let mut scores_dev = e.uninit(n * batch_max)?;
3119                launch_qsa_index_score(
3120                    e,
3121                    &q_dev,
3122                    m,
3123                    &mut scores_dev,
3124                    heads,
3125                    head_dim,
3126                    batch_max,
3127                    n,
3128                    scale,
3129                )?;
3130                if idx_sel_on() {
3131                    // Device selection (`idxsel`): read back rows x budget u32 instead of
3132                    // the rows x batch_max f32 slab, and never touch the scores on the
3133                    // host at all. The audit arm below is the ONLY thing that restores
3134                    // the slab dtoh, which is why it is an instrument and not an arm.
3135                    let counts: Vec<usize> = (0..n)
3136                        .map(|i| (base_pos + scored_rows[done + i] + 1) / block_size)
3137                        .collect();
3138                    let picked =
3139                        launch_qsa_index_topk(e, &scores_dev, &counts, batch_max, budget_blocks)?;
3140                    if idx_sel_audit_on() {
3141                        let host = e.dtoh(&scores_dev)?;
3142                        let mut mismatched = 0u64;
3143                        let mut deepest = 0u64;
3144                        for i in 0..n {
3145                            let complete = counts[i];
3146                            let row_scores = &host[i * batch_max..i * batch_max + complete];
3147                            let twin = top_blocks_ascending(row_scores, budget_blocks, threads);
3148                            if twin != picked[i] {
3149                                mismatched += 1;
3150                            }
3151                            deepest = deepest.max(complete as u64);
3152                        }
3153                        IDX_SEL_AUDIT_ROWS
3154                            .fetch_add(n as u64, std::sync::atomic::Ordering::Relaxed);
3155                        IDX_SEL_AUDIT_MISMATCH
3156                            .fetch_add(mismatched, std::sync::atomic::Ordering::Relaxed);
3157                        IDX_SEL_AUDIT_MAX_BLOCKS
3158                            .fetch_max(deepest, std::sync::atomic::Ordering::Relaxed);
3159                        if mismatched > 0 {
3160                            return Err(format!(
3161                                "idxsel audit: {mismatched} of {n} device selections differ \
3162                                 from the host twin (ids or order) at fill {t_kv}"
3163                            )
3164                            .into());
3165                        }
3166                    }
3167                    for (i, blocks) in picked.into_iter().enumerate() {
3168                        sels[scored_rows[done + i]].blocks = blocks;
3169                    }
3170                } else {
3171                    let host = e.dtoh(&scores_dev)?;
3172                    for i in 0..n {
3173                        let qt = scored_rows[done + i];
3174                        let complete = (base_pos + qt + 1) / block_size;
3175                        let row_scores = &host[i * batch_max..i * batch_max + complete];
3176                        sels[qt].blocks = top_blocks_ascending(row_scores, budget_blocks, threads);
3177                    }
3178                }
3179                done += n;
3180            }
3181            for sel in &sels {
3182                if sel.visible == 0
3183                    || (!sel.full && sel.blocks.is_empty() && sel.visible % block_size == 0)
3184                {
3185                    return Err("indexer selection left a query with no visible source".into());
3186                }
3187            }
3188            return Ok(sels);
3189        }
3190    }
3191    let pooled_ref: &[f32] = pooled_keys;
3192    let select_row = |qt: usize, threads_in_row: usize| -> RowSel {
3193        let row = base_pos + qt;
3194        let position = row + pos_off;
3195        let visible = row + 1;
3196        let complete = visible / block_size;
3197        // Structural fast path (perf lane, semantic no-op): with complete <= budget the
3198        // top-k keeps EVERY complete block whatever the scores say, and the incomplete
3199        // tail is always visible — the row is the full causal prefix. Real geometry:
3200        // budget 512 x block 4 => every position < 2051 takes this path (SEMANTICS.md
3201        // §QSA); the scoring arm below stays the reference for long contexts and is
3202        // exercised by the tiny gate's budget-2 fixture at every position past 11.
3203        if complete <= budget_blocks {
3204            return RowSel {
3205                full: true,
3206                blocks: Vec::new(),
3207                visible,
3208            };
3209        }
3210        let mut query = proj_rows[qt * qk_width..qt * qk_width + heads * head_dim].to_vec();
3211        host_rms_norm(&mut query, head_dim, idx_q_norm, epsilon);
3212        host_rope_at(&mut query, head_dim, rope_dims, rope_base, yarn, position);
3213        let scores = score_blocks(
3214            &query,
3215            pooled_ref,
3216            heads,
3217            head_dim,
3218            complete,
3219            scale,
3220            threads_in_row,
3221        );
3222        let blocks = top_blocks_ascending(&scores, budget_blocks, threads_in_row);
3223        RowSel {
3224            full: false,
3225            blocks,
3226            visible,
3227        }
3228    };
3229    const ROW_PAR_MIN_WORK: usize = 1 << 16;
3230    let total_scored_blocks: usize = (0..t)
3231        .map(|qt| {
3232            let complete = (base_pos + qt + 1) / block_size;
3233            if complete <= budget_blocks {
3234                0
3235            } else {
3236                complete
3237            }
3238        })
3239        .sum();
3240    let sels: Vec<RowSel> = if t > 1 && threads > 1 && total_scored_blocks >= ROW_PAR_MIN_WORK {
3241        // Rows are independent: a work-stealing cursor over rows, each row sequential
3242        // inside (identical arithmetic to the sequential path).
3243        let cursor = std::sync::atomic::AtomicUsize::new(0);
3244        let mut out: Vec<Option<RowSel>> = (0..t).map(|_| None).collect();
3245        let slots = std::sync::Mutex::new(&mut out);
3246        std::thread::scope(|scope| {
3247            for _ in 0..threads.min(t) {
3248                scope.spawn(|| {
3249                    loop {
3250                        let qt = cursor.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
3251                        if qt >= t {
3252                            break;
3253                        }
3254                        let sel = select_row(qt, 1);
3255                        slots.lock().unwrap()[qt] = Some(sel);
3256                    }
3257                });
3258            }
3259        });
3260        out.into_iter().map(|s| s.unwrap()).collect()
3261    } else {
3262        (0..t).map(|qt| select_row(qt, threads)).collect()
3263    };
3264    for sel in &sels {
3265        if sel.visible == 0 || (!sel.full && sel.blocks.is_empty() && sel.visible % block_size == 0)
3266        {
3267            return Err("indexer selection left a query with no visible source".into());
3268        }
3269    }
3270    Ok(sels)
3271}
3272
3273/// Render row selections as the dense [t, t_kv] u8 mask the smem-bounded masked kernel
3274/// consumes — byte-identical to the historical `indexer_mask_rows` output.
3275fn rowsel_to_mask(sels: &[RowSel], block_size: usize, t_kv: usize) -> Vec<u8> {
3276    let t = sels.len();
3277    let mut mask = vec![0u8; t * t_kv];
3278    for (qt, sel) in sels.iter().enumerate() {
3279        let row = &mut mask[qt * t_kv..(qt + 1) * t_kv];
3280        if sel.full {
3281            for slot in row.iter_mut().take(sel.visible) {
3282                *slot = 1;
3283            }
3284            continue;
3285        }
3286        for &block in &sel.blocks {
3287            for offset in 0..block_size {
3288                row[block as usize * block_size + offset] = 1;
3289            }
3290        }
3291        let complete = sel.visible / block_size;
3292        for slot in row.iter_mut().take(sel.visible).skip(complete * block_size) {
3293            *slot = 1;
3294        }
3295    }
3296    mask
3297}
3298
3299/// Render row selections as ASCENDING position lists for the block-list attention
3300/// kernel: flat i32 positions + per-row (offset, count) meta. Every row is bounded by
3301/// budget*block + (block-1) + ... <= 2052 positions on real geometry, so the kernel's
3302/// smem stays fixed whatever t_kv is.
3303fn rowsel_positions(sels: &[RowSel], block_size: usize) -> (Vec<i32>, Vec<i32>, usize) {
3304    let mut flat: Vec<i32> = Vec::new();
3305    let mut meta: Vec<i32> = Vec::with_capacity(sels.len() * 2);
3306    let mut max_count = 0usize;
3307    for sel in sels {
3308        let start = flat.len();
3309        if sel.full {
3310            flat.extend(0..sel.visible as i32);
3311        } else {
3312            for &block in &sel.blocks {
3313                let first = block as usize * block_size;
3314                flat.extend(first as i32..(first + block_size) as i32);
3315            }
3316            let complete = sel.visible / block_size;
3317            flat.extend((complete * block_size) as i32..sel.visible as i32);
3318        }
3319        let count = flat.len() - start;
3320        max_count = max_count.max(count);
3321        meta.push(start as i32);
3322        meta.push(count as i32);
3323    }
3324    (flat, meta, max_count)
3325}
3326
3327/// One launch of the QSA indexer block scorer (`qsa_index_score_f32`): thread-per-block
3328/// over a [rows, n_blocks] slab. Per-score arithmetic is the host twin's verbatim (same
3329/// dim order, same relu-sum, same division by sqrt(head_dim)) — bit-identical scores.
3330#[allow(clippy::too_many_arguments)]
3331fn launch_qsa_index_score(
3332    e: &Engine,
3333    q: &CudaSlice<f32>,
3334    pooled: &CudaSlice<f32>,
3335    out: &mut CudaSlice<f32>,
3336    heads: usize,
3337    head_dim: usize,
3338    n_blocks: usize,
3339    rows: usize,
3340    scale: f32,
3341) -> Res<()> {
3342    if rows == 0 || n_blocks == 0 {
3343        return Ok(());
3344    }
3345    if out.len() < rows * n_blocks {
3346        return Err("qsa_index_score_f32: score slab too short".into());
3347    }
3348    if rows > 65535 {
3349        return Err("qsa_index_score_f32: rows exceed grid.y (caller sub-batches)".into());
3350    }
3351    // `poolT`: read the dim-major plane in the second half of the mirror (bit-identical twin —
3352    // see POOL_T_DEFAULT). The plane's pitch is the mirror's block CAPACITY, not `n_blocks`:
3353    // passing `n_blocks` would read dim d of block b as dim d of some other block for every
3354    // d > 0, which is silent wrong values, so the pitch is derived from the allocation.
3355    let cap_rows = pooled.len() / (head_dim * POOL_PLANES);
3356    let pool_t = pool_t_on();
3357    if pool_t && cap_rows < n_blocks {
3358        return Err("qsa_index_score_f32_t: pooled plane capacity below n_blocks".into());
3359    }
3360    let f = e.func(if pool_t {
3361        "qsa_index_score_f32_t"
3362    } else {
3363        "qsa_index_score_f32"
3364    });
3365    const TPB: usize = 128;
3366    let cfg = LaunchConfig {
3367        grid_dim: (n_blocks.div_ceil(TPB) as u32, rows as u32, 1),
3368        block_dim: (TPB as u32, 1, 1),
3369        shared_mem_bytes: 0,
3370    };
3371    let (h, hd, nb, r) = (heads as i32, head_dim as i32, n_blocks as i32, rows as i32);
3372    let pitch = cap_rows as i64;
3373    let stream = e.gpu.stream();
3374    if pool_t {
3375        // The plane starts at `cap_rows * head_dim`; the kernel indexes `pooled_t[d*pitch + b]`
3376        // from that base, so the slice is the plane region, not the whole buffer.
3377        let plane = pooled.slice(cap_rows * head_dim..cap_rows * head_dim * POOL_PLANES);
3378        let mut b = stream.launch_builder(&f);
3379        b.arg(q)
3380            .arg(&plane)
3381            .arg(&mut *out)
3382            .arg(&h)
3383            .arg(&hd)
3384            .arg(&nb)
3385            .arg(&r)
3386            .arg(&scale)
3387            .arg(&pitch);
3388        unsafe {
3389            b.launch(cfg)?;
3390        }
3391        return Ok(());
3392    }
3393    let mut b = stream.launch_builder(&f);
3394    b.arg(q)
3395        .arg(pooled)
3396        .arg(&mut *out)
3397        .arg(&h)
3398        .arg(&hd)
3399        .arg(&nb)
3400        .arg(&r)
3401        .arg(&scale);
3402    unsafe {
3403        b.launch(cfg)?;
3404    }
3405    Ok(())
3406}
3407
3408/// How many `cap_rows * head_dim` regions the pooled device mirror carries: the row-major
3409/// mirror, then the dim-major `poolT` plane. See the append site for why both are maintained
3410/// unconditionally (A/B isolation, and no stale-plane failure mode on a mid-run seam flip).
3411const POOL_PLANES: usize = 2;
3412
3413/// Mirror the freshly-appended pooled rows `[r0, r0+rows)` into the dim-major plane. Pure data
3414/// movement inside one buffer; `cap_rows` is the plane pitch (the mirror's block capacity).
3415fn launch_qsa_pooled_transpose(
3416    e: &Engine,
3417    buf: &mut CudaSlice<f32>,
3418    r0: usize,
3419    rows: usize,
3420    head_dim: usize,
3421    cap_rows: usize,
3422) -> Res<()> {
3423    if rows == 0 {
3424        return Ok(());
3425    }
3426    if r0 + rows > cap_rows {
3427        return Err("qsa_pooled_transpose_f32: delta exceeds the plane capacity".into());
3428    }
3429    let f = e.func("qsa_pooled_transpose_f32");
3430    const TPB: usize = 128;
3431    let cfg = LaunchConfig {
3432        grid_dim: (rows.div_ceil(TPB) as u32, head_dim as u32, 1),
3433        block_dim: (TPB as u32, 1, 1),
3434        shared_mem_bytes: 0,
3435    };
3436    let (r, hd, r0i) = (rows as i32, head_dim as i32, r0 as i32);
3437    let cap = cap_rows as i64;
3438    let stream = e.gpu.stream();
3439    let mut b = stream.launch_builder(&f);
3440    b.arg(buf).arg(&r).arg(&hd).arg(&r0i).arg(&cap);
3441    unsafe {
3442        b.launch(cfg)?;
3443    }
3444    Ok(())
3445}
3446
3447/// One launch of the device indexer top-k (`qsa_index_topk_u32`) over a score slab, plus
3448/// the structural checks that make a silent mis-write loud: every row's block count must
3449/// EXCEED the budget (so the row genuinely needs a selection and every out slot is
3450/// written), and the returned lists come back strictly ascending and in range. Returns the
3451/// `rows x budget` block ids.
3452fn launch_qsa_index_topk(
3453    e: &Engine,
3454    scores: &CudaSlice<f32>,
3455    counts: &[usize],
3456    stride: usize,
3457    budget: usize,
3458) -> Res<Vec<Vec<u32>>> {
3459    let rows = counts.len();
3460    if rows == 0 || budget == 0 {
3461        return Ok(Vec::new());
3462    }
3463    if rows > 65535 {
3464        return Err("qsa_index_topk_u32: rows exceed grid.x (caller sub-batches)".into());
3465    }
3466    if scores.len() < rows * stride {
3467        return Err("qsa_index_topk_u32: score slab too short".into());
3468    }
3469    for (r, &c) in counts.iter().enumerate() {
3470        if c <= budget || c > stride {
3471            return Err(format!(
3472                "qsa_index_topk_u32: row {r} block count {c} outside (budget {budget}, \
3473                 stride {stride}] — the caller only routes scored rows here"
3474            )
3475            .into());
3476        }
3477    }
3478    let counts_i32: Vec<i32> = counts.iter().map(|&c| c as i32).collect();
3479    let counts_dev = e.htod_i32(&counts_i32)?;
3480    // -1 fill: an unwritten slot is then VISIBLE (the check below), not a plausible block.
3481    let mut out = e.htod_i32(&vec![-1i32; rows * budget])?;
3482    let f = e.func("qsa_index_topk_u32");
3483    let cfg = LaunchConfig {
3484        grid_dim: (rows as u32, 1, 1),
3485        block_dim: (256, 1, 1),
3486        shared_mem_bytes: 0,
3487    };
3488    let (st, bu, ro) = (stride as i32, budget as i32, rows as i32);
3489    let stream = e.gpu.stream();
3490    let mut b = stream.launch_builder(&f);
3491    b.arg(scores)
3492        .arg(&counts_dev)
3493        .arg(&mut out)
3494        .arg(&st)
3495        .arg(&bu)
3496        .arg(&ro);
3497    unsafe {
3498        b.launch(cfg)?;
3499    }
3500    let host = e.gpu.stream().clone_dtoh(&out)?;
3501    e.gpu.stream().synchronize()?;
3502    let mut out_rows: Vec<Vec<u32>> = Vec::with_capacity(rows);
3503    for r in 0..rows {
3504        let row = &host[r * budget..(r + 1) * budget];
3505        let mut blocks: Vec<u32> = Vec::with_capacity(budget);
3506        let mut prev: i64 = -1;
3507        for (j, &v) in row.iter().enumerate() {
3508            if v < 0 || (v as usize) >= counts[r] || (v as i64) <= prev {
3509                return Err(format!(
3510                    "qsa_index_topk_u32: row {r} slot {j} = {v} is not a strictly ascending \
3511                     in-range block id (blocks {}, budget {budget})",
3512                    counts[r]
3513                )
3514                .into());
3515            }
3516            prev = v as i64;
3517            blocks.push(v as u32);
3518        }
3519        out_rows.push(blocks);
3520    }
3521    Ok(out_rows)
3522}
3523
3524/// One launch of the row-window column-slice copy (`copy_rows_col_f32`): append the
3525/// k-part of `rows` idx_proj rows (column offset `src_col`, row stride `src_stride`)
3526/// to the device raw-key cache at row `dst_row`. Exact byte moves, no arithmetic.
3527#[allow(clippy::too_many_arguments)]
3528fn launch_copy_rows_col(
3529    e: &Engine,
3530    src: &CudaSlice<f32>,
3531    dst: &mut CudaSlice<f32>,
3532    rows: usize,
3533    width: usize,
3534    src_stride: usize,
3535    src_col: usize,
3536    dst_row: usize,
3537) -> Res<()> {
3538    if rows == 0 {
3539        return Ok(());
3540    }
3541    if src.len() < (rows - 1) * src_stride + src_col + width || dst.len() < (dst_row + rows) * width
3542    {
3543        return Err("copy_rows_col_f32: window out of range".into());
3544    }
3545    let f = e.func("copy_rows_col_f32");
3546    let total = rows * width;
3547    let cfg = LaunchConfig::for_num_elems(total as u32);
3548    let (r, w) = (rows as i32, width as i32);
3549    let (ss, sc, dr) = (src_stride as i64, src_col as i64, dst_row as i64);
3550    let stream = e.gpu.stream();
3551    let mut b = stream.launch_builder(&f);
3552    b.arg(src)
3553        .arg(&mut *dst)
3554        .arg(&r)
3555        .arg(&w)
3556        .arg(&ss)
3557        .arg(&sc)
3558        .arg(&dr);
3559    unsafe {
3560        b.launch(cfg)?;
3561    }
3562    Ok(())
3563}
3564
3565/// One launch of the device MoE router (`qwen4exp_route_topk_f32`): per token row, the
3566/// full host_route_softmax_topk program on device (kernel doc — order-sensitive
3567/// reductions sequential on thread 0, host op order verbatim; exp through double).
3568/// `tok` = optional (slot->token map, tok_base) for the gufuse merged verify path.
3569/// Geometry guards live in the CALLER's engage condition; violations here are errors,
3570/// never silent fallbacks.
3571#[allow(clippy::too_many_arguments)]
3572fn launch_route_topk(
3573    e: &Engine,
3574    logits: &CudaSlice<f32>,
3575    sel: &mut CudaSlice<i32>,
3576    w: &mut CudaSlice<f32>,
3577    tok: Option<(&mut CudaSlice<i32>, usize)>,
3578    experts: usize,
3579    selected: usize,
3580    rows: usize,
3581) -> Res<()> {
3582    if rows == 0 {
3583        return Ok(());
3584    }
3585    if selected == 0 || selected > 32 || selected > experts {
3586        return Err("qwen4exp_route_topk_f32: selected out of range (caller guards)".into());
3587    }
3588    if experts % 2 != 0 {
3589        // The u64 key slab sits after the f32 weight slab in dynamic smem; an even
3590        // expert count keeps it 8-byte aligned (caller guards via route_dev_geometry).
3591        return Err("qwen4exp_route_topk_f32: odd expert count".into());
3592    }
3593    if logits.len() < rows * experts || sel.len() < rows * selected || w.len() < rows * selected {
3594        return Err("qwen4exp_route_topk_f32: buffer too short".into());
3595    }
3596    let smem = experts * 12; // f32 weights + u64 selection keys
3597    if smem > 48 * 1024 {
3598        return Err("qwen4exp_route_topk_f32: experts exceed the smem bound".into());
3599    }
3600    let stream = e.gpu.stream();
3601    let (tok_raw, tok_base) = match tok {
3602        Some((buf, base)) => {
3603            if buf.len() < rows * selected {
3604                return Err("qwen4exp_route_topk_f32: tok map too short".into());
3605            }
3606            (buf.device_ptr(&stream).0, base)
3607        }
3608        None => (0u64, 0usize),
3609    };
3610    let f = e.func("qwen4exp_route_topk_f32");
3611    let cfg = LaunchConfig {
3612        grid_dim: (rows as u32, 1, 1),
3613        block_dim: (128, 1, 1),
3614        shared_mem_bytes: smem as u32,
3615    };
3616    let (ex, se, ro, tb) = (
3617        experts as i32,
3618        selected as i32,
3619        rows as i32,
3620        tok_base as i32,
3621    );
3622    let floor = ROUTE_DENOM_FLOOR;
3623    let mut b = stream.launch_builder(&f);
3624    b.arg(logits)
3625        .arg(&mut *sel)
3626        .arg(&mut *w)
3627        .arg(&tok_raw)
3628        .arg(&ex)
3629        .arg(&se)
3630        .arg(&ro)
3631        .arg(&tb)
3632        .arg(&floor);
3633    unsafe {
3634        b.launch(cfg)?;
3635    }
3636    Ok(())
3637}
3638
3639/// Device route + (MEMRA_Q4E_ROUTER_AUDIT=1) the host-twin cross-check over the SAME
3640/// logits: selection ids order-exact or Err; weights within ROUTE_AUDIT_ULP_BOUND ULP,
3641/// worst observed kept for the gate receipt (`route_audit_stats`).
3642#[allow(clippy::too_many_arguments)]
3643fn route_topk_device(
3644    e: &Engine,
3645    logits: &CudaSlice<f32>,
3646    sel: &mut CudaSlice<i32>,
3647    w: &mut CudaSlice<f32>,
3648    tok: Option<(&mut CudaSlice<i32>, usize)>,
3649    experts: usize,
3650    selected: usize,
3651    rows: usize,
3652    layer: u32,
3653) -> Res<()> {
3654    launch_route_topk(e, logits, sel, w, tok, experts, selected, rows)?;
3655    if !router_audit_on() {
3656        return Ok(());
3657    }
3658    let k = selected.min(experts);
3659    let lg = e.dtoh_view(&logits.slice(0..rows * experts))?;
3660    let sel_h = e.gpu.stream().clone_dtoh(&sel.slice(0..rows * selected))?;
3661    let w_h = e.gpu.stream().clone_dtoh(&w.slice(0..rows * selected))?;
3662    // Emit the shared-format route trace off THIS readback (`trace_moe_routes`, the frozen
3663    // `memra-ep-map-v1` producer). Its own doc comment already promised exactly this — "arming
3664    // MEMRA_Q4E_ROUTER_AUDIT=1 restores a host recompute of every device route and the trace
3665    // rides THAT readback at zero new syncs ... single-card batteries trace with the audit
3666    // armed" — but the call was never made, so the tracer fired ONLY from the TP2 paths and the
3667    // shipped single-card device-routed default emitted nothing at all. The box's traces
3668    // directory was empty for that reason and not for lack of running, and the expert-placement
3669    // lane's only input silently did not exist. Prose describing a wiring that is not there is
3670    // the failure class this lane has hit twice; the wiring is here now.
3671    //
3672    // Traced from the DEVICE arrays, not from the host twin below: the trace must record the
3673    // route that actually ran. The audit's job is to prove the two agree, and it does that on
3674    // the next lines — so if they ever disagree this call has already errored out.
3675    {
3676        let routes: Vec<Vec<(usize, f32)>> = (0..rows)
3677            .map(|row| {
3678                (0..selected)
3679                    .map(|j| {
3680                        (
3681                            sel_h[row * selected + j].max(0) as usize,
3682                            w_h[row * selected + j],
3683                        )
3684                    })
3685                    .collect()
3686            })
3687            .collect();
3688        trace_moe_routes(layer, rows, &routes);
3689    }
3690    let mut worst: u32 = 0;
3691    for row in 0..rows {
3692        let twin = host_route_softmax_topk(&lg[row * experts..(row + 1) * experts], selected);
3693        if twin.len() != k {
3694            return Err("router audit: host twin emitted an unexpected selection width".into());
3695        }
3696        for (j, &(idx, wt)) in twin.iter().enumerate() {
3697            let ds = sel_h[row * selected + j];
3698            let dw = w_h[row * selected + j];
3699            if ds != idx as i32 {
3700                return Err(format!(
3701                    "router audit: selection mismatch at row {row} slot {j}: \
3702                     device {ds} vs host {idx} (host w {wt:e})"
3703                )
3704                .into());
3705            }
3706            let ulp = (dw.to_bits() as i64 - wt.to_bits() as i64).unsigned_abs();
3707            let ulp = u32::try_from(ulp).unwrap_or(u32::MAX);
3708            worst = worst.max(ulp);
3709            if ulp > ROUTE_AUDIT_ULP_BOUND {
3710                return Err(format!(
3711                    "router audit: weight ULP {ulp} > bound {ROUTE_AUDIT_ULP_BOUND} at \
3712                     row {row} slot {j}: device {dw:e} vs host {wt:e}"
3713                )
3714                .into());
3715            }
3716        }
3717    }
3718    ROUTE_AUDIT_ROWS.fetch_add(rows as u64, std::sync::atomic::Ordering::Relaxed);
3719    ROUTE_AUDIT_MAX_ULP.fetch_max(worst, std::sync::atomic::Ordering::Relaxed);
3720    Ok(())
3721}
3722
3723/// The historical mask-producing entry point, now select + render (byte-identical mask;
3724/// the TP2 decode path and the masked-kernel arm consume it).
3725#[allow(clippy::too_many_arguments)]
3726fn indexer_mask_rows(
3727    overlay: &MicroBlockIndexPlan,
3728    rope_base: f32,
3729    yarn: Option<(&[f32], f32)>,
3730    epsilon: f32,
3731    idx_q_norm: &[f32],
3732    idx_k_norm: &[f32],
3733    proj_rows: &[f32],
3734    raw_keys: &IdxRawCache,
3735    pooled_keys: &mut Vec<f32>,
3736    base_pos: usize,
3737    t: usize,
3738    t_kv: usize,
3739    pos_off: usize,
3740) -> Res<Vec<u8>> {
3741    let sels = indexer_select_rows(
3742        overlay,
3743        rope_base,
3744        yarn,
3745        epsilon,
3746        idx_q_norm,
3747        idx_k_norm,
3748        proj_rows,
3749        raw_keys,
3750        pooled_keys,
3751        // TP2 decode + the reference/mask arm keep the host scorer (TP2's selection runs
3752        // on card 0's projection and feeds both halves; its depths are decode-class).
3753        None,
3754        base_pos,
3755        t,
3756        t_kv,
3757        pos_off,
3758    )?;
3759    Ok(rowsel_to_mask(&sels, overlay.block_size as usize, t_kv))
3760}
3761
3762/// memra_reference `shift_right_ignore_eos` twin.
3763fn shift_right_ignore_eos(history: &[i64], shift: usize, eos: i64) -> Vec<i64> {
3764    if shift == 0 {
3765        return history.to_vec();
3766    }
3767    let mut last_eos_inclusive: i64 = -1;
3768    let mut output = Vec::with_capacity(history.len());
3769    for (position, &token) in history.iter().enumerate() {
3770        let previous_eos = last_eos_inclusive;
3771        if token == eos {
3772            last_eos_inclusive = position as i64;
3773        }
3774        let segment_start = previous_eos + 1;
3775        let position_in_segment = position as i64 - segment_start;
3776        let source = position as i64 - shift as i64;
3777        let valid = position_in_segment >= shift as i64 && source >= 0;
3778        output.push(if valid { history[source as usize] } else { eos });
3779    }
3780    output
3781}
3782
3783/// INCREMENTAL twin of `host_ngram_ids` (`plecache` seam, 262k perf lane): extend a cached
3784/// id vector to cover `token_ids` instead of rebuilding it. Returns the last `t` rows'
3785/// worth of ids, i.e. exactly what the caller slices.
3786///
3787/// Bit-identical to `host_ngram_ids` by construction, not by tolerance. Two local facts do
3788/// it. (1) `shift_right_ignore_eos` at position p emits `history[p - shift]` guarded by an
3789/// eos scan that only moves left-to-right, so its value at p depends on `history[..=p]`
3790/// alone. (2) the id loop at `token` reads only `shifted[*][context + token]`. Therefore
3791/// `ids[token]` is a pure function of `token_ids[..=token]` and never changes when a token
3792/// is appended — so appending rows is not an approximation of rebuilding them, it is the
3793/// same arithmetic in the same order on the same inputs.
3794///
3795/// A shrinking or diverging history (spec reject / rewind / a fresh sequence in a reused
3796/// state) is handled by TRUNCATING the cache to the longest common prefix and re-extending.
3797/// The check is a real prefix compare rather than a length compare, because a length-only
3798/// check would silently keep another sequence's hashes — the failure mode would be fluent
3799/// output from the wrong n-gram rows, which is invisible.
3800#[allow(clippy::too_many_arguments)]
3801fn host_ngram_ids_cached(
3802    cache_ids: &mut Vec<i64>,
3803    cache_history: &mut Vec<i64>,
3804    cache_last_eos: &mut i64,
3805    token_ids: &[u32],
3806    multipliers: &[i64],
3807    sizes: &[i64],
3808    offsets: &[i64],
3809    max_ngram: usize,
3810    heads_per_ngram: usize,
3811    eos_token_id: u32,
3812) {
3813    let context = max_ngram - 1;
3814    let eos = eos_token_id as i64;
3815    let total_heads = (max_ngram - 1) * heads_per_ngram;
3816    if cache_history.is_empty() {
3817        cache_history.extend(std::iter::repeat_n(eos, context));
3818        *cache_last_eos = context as i64 - 1; // every prefix row IS an eos
3819        cache_ids.clear();
3820    }
3821    let cached_tokens = (cache_history.len() - context).min(cache_ids.len() / total_heads);
3822    // Longest common prefix of the cached tokens and the requested ones.
3823    let mut keep = cached_tokens.min(token_ids.len());
3824    for i in 0..keep {
3825        if cache_history[context + i] != token_ids[i] as i64 {
3826            keep = i;
3827            break;
3828        }
3829    }
3830    if keep < cached_tokens {
3831        // Rewind: drop the diverged tail and rebuild the eos scan over what survives.
3832        cache_history.truncate(context + keep);
3833        cache_ids.truncate(keep * total_heads);
3834        *cache_last_eos = cache_history
3835            .iter()
3836            .rposition(|&v| v == eos)
3837            .map(|p| p as i64)
3838            .unwrap_or(-1);
3839    }
3840    for &token in &token_ids[keep..] {
3841        let position = cache_history.len();
3842        let value = token as i64;
3843        cache_history.push(value);
3844        // `shift_right_ignore_eos`: `previous_eos` is read BEFORE this position updates it.
3845        let previous_eos = *cache_last_eos;
3846        if value == eos {
3847            *cache_last_eos = position as i64;
3848        }
3849        let segment_start = previous_eos + 1;
3850        let position_in_segment = position as i64 - segment_start;
3851        let shifted_at = |shift: usize| -> i64 {
3852            if shift == 0 {
3853                return cache_history[position];
3854            }
3855            let source = position as i64 - shift as i64;
3856            if position_in_segment >= shift as i64 && source >= 0 {
3857                cache_history[source as usize]
3858            } else {
3859                eos
3860            }
3861        };
3862        // Same op order as the twin: shift 0 multiply, then xor the higher shifts in order.
3863        let mut row = vec![0i64; total_heads];
3864        for ngram in 2..=max_ngram {
3865            let head_start = (ngram - 2) * heads_per_ngram;
3866            let mut mixed = shifted_at(0).wrapping_mul(multipliers[0]);
3867            for shift in 1..ngram {
3868                mixed ^= shifted_at(shift).wrapping_mul(multipliers[shift]);
3869            }
3870            for head in 0..heads_per_ngram {
3871                let index = head_start + head;
3872                row[index] = mixed.rem_euclid(sizes[index]) + offsets[index];
3873            }
3874        }
3875        cache_ids.extend_from_slice(&row);
3876    }
3877    debug_assert_eq!(cache_ids.len(), token_ids.len() * total_heads);
3878    // Returns nothing on purpose: the caller reads the tail of `cache_ids` in place. Handing
3879    // back a `Vec` would clone the whole history's ids on every decode step (19 MB at a
3880    // 150,000-token fill), which is the O(context) cost this seam exists to delete.
3881}
3882
3883/// memra_reference `ngram_ids` twin over the FULL token history (context EOS rows
3884/// prepended); the caller slices the last `t` rows for the current chunk.
3885fn host_ngram_ids(
3886    token_ids: &[u32],
3887    multipliers: &[i64],
3888    sizes: &[i64],
3889    offsets: &[i64],
3890    max_ngram: usize,
3891    heads_per_ngram: usize,
3892    eos_token_id: u32,
3893) -> Vec<i64> {
3894    let context = max_ngram - 1;
3895    let eos = eos_token_id as i64;
3896    let total_heads = (max_ngram - 1) * heads_per_ngram;
3897    let mut history = Vec::with_capacity(context + token_ids.len());
3898    history.extend(std::iter::repeat_n(eos, context));
3899    history.extend(token_ids.iter().map(|&token| token as i64));
3900    let shifted: Vec<Vec<i64>> = (0..max_ngram)
3901        .map(|shift| shift_right_ignore_eos(&history, shift, eos))
3902        .collect();
3903    let tokens = token_ids.len();
3904    let mut ids = vec![0i64; tokens * total_heads];
3905    for ngram in 2..=max_ngram {
3906        let head_start = (ngram - 2) * heads_per_ngram;
3907        for token in 0..tokens {
3908            let position = context + token;
3909            let mut mixed = shifted[0][position].wrapping_mul(multipliers[0]);
3910            for (shift, row) in shifted.iter().enumerate().take(ngram).skip(1) {
3911                mixed ^= row[position].wrapping_mul(multipliers[shift]);
3912            }
3913            for head in 0..heads_per_ngram {
3914                let index = head_start + head;
3915                ids[token * total_heads + index] = mixed.rem_euclid(sizes[index]) + offsets[index];
3916            }
3917        }
3918    }
3919    ids
3920}
3921
3922// ---------------------------------------------------------------- kernel launchers
3923
3924#[allow(clippy::too_many_arguments)]
3925fn launch_sdpa_mask(
3926    e: &Engine,
3927    q: &CudaSlice<f32>,
3928    k: &CudaView<'_, f32>,
3929    v: &CudaView<'_, f32>,
3930    o: &mut CudaSlice<f32>,
3931    mask: &CudaSlice<u8>,
3932    head_dim: usize,
3933    n_head: usize,
3934    n_head_kv: usize,
3935    t: usize,
3936    t_kv: usize,
3937    scale: f32,
3938) -> Res<()> {
3939    if t_kv * 4 > 48 * 1024 {
3940        return Err(
3941            "sdpa_naive_mask_f32: T_kv exceeds the smem bound; the gmem twin is perf-lane work"
3942                .into(),
3943        );
3944    }
3945    let f = e.func("sdpa_naive_mask_f32");
3946    let cfg = LaunchConfig {
3947        grid_dim: (n_head as u32, t as u32, 1),
3948        block_dim: (128, 1, 1),
3949        shared_mem_bytes: (t_kv * 4) as u32,
3950    };
3951    let (hd, nh, nkv, ti, tkvi) = (
3952        head_dim as i32,
3953        n_head as i32,
3954        n_head_kv as i32,
3955        t as i32,
3956        t_kv as i32,
3957    );
3958    let stream = e.gpu.stream();
3959    let mut b = stream.launch_builder(&f);
3960    b.arg(q)
3961        .arg(k)
3962        .arg(v)
3963        .arg(o)
3964        .arg(mask)
3965        .arg(&hd)
3966        .arg(&nh)
3967        .arg(&nkv)
3968        .arg(&ti)
3969        .arg(&tkvi)
3970        .arg(&scale);
3971    unsafe {
3972        b.launch(cfg)?;
3973    }
3974    Ok(())
3975}
3976
3977/// Block-list QSA attention (long-context form): per query row, attend the row's own
3978/// ASCENDING position list (`rowsel_positions`) — smem scales with the bounded per-row
3979/// selection (<= 2052 on real geometry), never with t_kv. BIT-IDENTICAL to
3980/// `sdpa_naive_mask_f32` on the same selection: masked entries there contribute exact
3981/// 0.0 softmax/V terms in the same ascending order (gate arm + kernel oracle).
3982#[allow(clippy::too_many_arguments)]
3983fn launch_sdpa_blocklist(
3984    e: &Engine,
3985    q: &CudaSlice<f32>,
3986    k: &CudaView<'_, f32>,
3987    v: &CudaView<'_, f32>,
3988    o: &mut CudaSlice<f32>,
3989    pos: &CudaSlice<i32>,
3990    meta: &CudaSlice<i32>,
3991    head_dim: usize,
3992    n_head: usize,
3993    n_head_kv: usize,
3994    t: usize,
3995    max_count: usize,
3996    scale: f32,
3997) -> Res<()> {
3998    // positions (i32) + scores (f32) per selected entry. Production rows are bounded by
3999    // budget*block + block = 2052 entries (16.4 KB); 48 KB is the no-attribute smem cap.
4000    let smem = (max_count * 8) as u32;
4001    if smem > 48 * 1024 {
4002        return Err("sdpa_blocklist_f32: selection exceeds the smem budget".into());
4003    }
4004    let f = e.func("sdpa_blocklist_f32");
4005    let cfg = LaunchConfig {
4006        grid_dim: (n_head as u32, t as u32, 1),
4007        block_dim: (128, 1, 1),
4008        shared_mem_bytes: smem,
4009    };
4010    let (hd, nh, nkv, ti, mc) = (
4011        head_dim as i32,
4012        n_head as i32,
4013        n_head_kv as i32,
4014        t as i32,
4015        max_count as i32,
4016    );
4017    let stream = e.gpu.stream();
4018    let mut b = stream.launch_builder(&f);
4019    b.arg(q)
4020        .arg(k)
4021        .arg(v)
4022        .arg(o)
4023        .arg(pos)
4024        .arg(meta)
4025        .arg(&hd)
4026        .arg(&nh)
4027        .arg(&nkv)
4028        .arg(&ti)
4029        .arg(&mc)
4030        .arg(&scale);
4031    unsafe {
4032        b.launch(cfg)?;
4033    }
4034    Ok(())
4035}
4036
4037/// Append-quantize `t` post-RoPE K/V rows into the byte caches at slots
4038/// [base_pos, base_pos + t) (kvq lane; K=q8_0, V=q5_1).
4039#[allow(clippy::too_many_arguments)]
4040fn launch_q4e_kv_append(
4041    e: &Engine,
4042    k_rows: &CudaSlice<f32>,
4043    v_rows: &CudaSlice<f32>,
4044    k: &mut CudaSlice<u8>,
4045    v: &mut CudaSlice<u8>,
4046    base_pos: usize,
4047    t: usize,
4048    kv_dim: usize,
4049) -> Res<()> {
4050    let f = e.func("q4e_kv_append_q8q5_rows");
4051    let blocks = kv_dim.div_ceil(32);
4052    let cfg = LaunchConfig {
4053        grid_dim: (blocks as u32, t as u32, 1),
4054        block_dim: (32, 1, 1),
4055        shared_mem_bytes: 0,
4056    };
4057    let (t0, dk, dv) = (base_pos as i32, kv_dim as i32, kv_dim as i32);
4058    let (ktb, vtb) = (q8_row_bytes(kv_dim) as i64, q5_row_bytes(kv_dim) as i64);
4059    let stream = e.gpu.stream();
4060    let mut b = stream.launch_builder(&f);
4061    b.arg(k_rows)
4062        .arg(v_rows)
4063        .arg(k)
4064        .arg(v)
4065        .arg(&t0)
4066        .arg(&dk)
4067        .arg(&dv)
4068        .arg(&ktb)
4069        .arg(&vtb);
4070    unsafe {
4071        b.launch(cfg)?;
4072    }
4073    Ok(())
4074}
4075
4076/// Dequant cache rows [r0, r0+rows) into f32 buffers (gates + TP2 migration seam).
4077#[allow(clippy::too_many_arguments)]
4078fn launch_q4e_kv_dequant_rows(
4079    e: &Engine,
4080    k: &CudaSlice<u8>,
4081    v: &CudaSlice<u8>,
4082    k_out: &mut CudaSlice<f32>,
4083    v_out: &mut CudaSlice<f32>,
4084    r0: usize,
4085    rows: usize,
4086    kv_dim: usize,
4087) -> Res<()> {
4088    let f = e.func("q4e_kv_dequant_rows");
4089    let blocks = kv_dim.div_ceil(32);
4090    let cfg = LaunchConfig {
4091        grid_dim: (blocks as u32, rows as u32, 1),
4092        block_dim: (32, 1, 1),
4093        shared_mem_bytes: 0,
4094    };
4095    let (r0i, dk, dv) = (r0 as i32, kv_dim as i32, kv_dim as i32);
4096    let (ktb, vtb) = (q8_row_bytes(kv_dim) as i64, q5_row_bytes(kv_dim) as i64);
4097    let stream = e.gpu.stream();
4098    let mut b = stream.launch_builder(&f);
4099    b.arg(k)
4100        .arg(v)
4101        .arg(k_out)
4102        .arg(v_out)
4103        .arg(&r0i)
4104        .arg(&dk)
4105        .arg(&dv)
4106        .arg(&ktb)
4107        .arg(&vtb);
4108    unsafe {
4109        b.launch(cfg)?;
4110    }
4111    Ok(())
4112}
4113
4114/// Block-list QSA attention over the QUANTIZED cache (kvq lane) — the f32 launcher's
4115/// twin with byte-cache K/V and their row strides.
4116#[allow(clippy::too_many_arguments)]
4117fn launch_q4e_sdpa_blocklist_q8q5(
4118    e: &Engine,
4119    q: &CudaSlice<f32>,
4120    k: &CudaSlice<u8>,
4121    v: &CudaSlice<u8>,
4122    o: &mut CudaSlice<f32>,
4123    pos: &CudaSlice<i32>,
4124    meta: &CudaSlice<i32>,
4125    head_dim: usize,
4126    n_head: usize,
4127    n_head_kv: usize,
4128    t: usize,
4129    max_count: usize,
4130    scale: f32,
4131) -> Res<()> {
4132    let smem = (max_count * 8) as u32;
4133    if smem > 48 * 1024 {
4134        return Err("q4e_sdpa_blocklist_q8q5: selection exceeds the smem budget".into());
4135    }
4136    // `kvhoist`: the scale-hoisted twin, bit-identical, selected by seam (see KV_HOIST_DEFAULT).
4137    let f = e.func(if kv_hoist_on() {
4138        "q4e_sdpa_blocklist_q8q5_hoist"
4139    } else {
4140        "q4e_sdpa_blocklist_q8q5"
4141    });
4142    let cfg = LaunchConfig {
4143        grid_dim: (n_head as u32, t as u32, 1),
4144        block_dim: (128, 1, 1),
4145        shared_mem_bytes: smem,
4146    };
4147    let kv_dim = n_head_kv * head_dim;
4148    let (hd, nh, nkv, ti, mc) = (
4149        head_dim as i32,
4150        n_head as i32,
4151        n_head_kv as i32,
4152        t as i32,
4153        max_count as i32,
4154    );
4155    let (ktb, vtb) = (q8_row_bytes(kv_dim) as i64, q5_row_bytes(kv_dim) as i64);
4156    let stream = e.gpu.stream();
4157    let mut b = stream.launch_builder(&f);
4158    b.arg(q)
4159        .arg(k)
4160        .arg(v)
4161        .arg(o)
4162        .arg(pos)
4163        .arg(meta)
4164        .arg(&hd)
4165        .arg(&nh)
4166        .arg(&nkv)
4167        .arg(&ti)
4168        .arg(&mc)
4169        .arg(&scale)
4170        .arg(&ktb)
4171        .arg(&vtb);
4172    unsafe {
4173        b.launch(cfg)?;
4174    }
4175    Ok(())
4176}
4177
4178/// Quantize-append the k-part columns of `rows` idx_proj rows into the q8_0 device
4179/// raw-key cache (idxq=q8 x idxcache).
4180#[allow(clippy::too_many_arguments)]
4181fn launch_q4e_idx_append_q8(
4182    e: &Engine,
4183    src: &CudaSlice<f32>,
4184    dst: &mut CudaSlice<u8>,
4185    rows: usize,
4186    width: usize,
4187    src_stride: usize,
4188    src_col: usize,
4189    dst_row: usize,
4190) -> Res<()> {
4191    let f = e.func("q4e_idx_append_q8");
4192    let cfg = LaunchConfig {
4193        grid_dim: (width.div_ceil(32) as u32, rows as u32, 1),
4194        block_dim: (32, 1, 1),
4195        shared_mem_bytes: 0,
4196    };
4197    let (r, w) = (rows as i32, width as i32);
4198    let (ss, sc, dr) = (src_stride as i64, src_col as i64, dst_row as i64);
4199    let stream = e.gpu.stream();
4200    let mut b = stream.launch_builder(&f);
4201    b.arg(src)
4202        .arg(dst)
4203        .arg(&r)
4204        .arg(&w)
4205        .arg(&ss)
4206        .arg(&sc)
4207        .arg(&dr);
4208    unsafe {
4209        b.launch(cfg)?;
4210    }
4211    Ok(())
4212}
4213
4214/// Convert-append (bf16 RNE) the k-part columns into the bf16 device raw-key cache.
4215#[allow(clippy::too_many_arguments)]
4216fn launch_q4e_idx_append_bf16(
4217    e: &Engine,
4218    src: &CudaSlice<f32>,
4219    dst: &mut CudaSlice<u16>,
4220    rows: usize,
4221    width: usize,
4222    src_stride: usize,
4223    src_col: usize,
4224    dst_row: usize,
4225) -> Res<()> {
4226    let f = e.func("q4e_idx_append_bf16");
4227    let total = rows * width;
4228    let cfg = LaunchConfig {
4229        grid_dim: (total.div_ceil(256) as u32, 1, 1),
4230        block_dim: (256, 1, 1),
4231        shared_mem_bytes: 0,
4232    };
4233    let (r, w) = (rows as i32, width as i32);
4234    let (ss, sc, dr) = (src_stride as i64, src_col as i64, dst_row as i64);
4235    let stream = e.gpu.stream();
4236    let mut b = stream.launch_builder(&f);
4237    b.arg(src)
4238        .arg(dst)
4239        .arg(&r)
4240        .arg(&w)
4241        .arg(&ss)
4242        .arg(&sc)
4243        .arg(&dr);
4244    unsafe {
4245        b.launch(cfg)?;
4246    }
4247    Ok(())
4248}
4249
4250#[allow(clippy::too_many_arguments)]
4251fn launch_gdn_scan(
4252    e: &Engine,
4253    qkv: &CudaSlice<f32>,
4254    g_log: &CudaSlice<f32>,
4255    beta_raw: &CudaSlice<f32>,
4256    state: &mut CudaSlice<f32>,
4257    o: &mut CudaSlice<f32>,
4258    nk: usize,
4259    nv: usize,
4260    hk: usize,
4261    hv: usize,
4262    t: usize,
4263    scale: f32,
4264    eps: f32,
4265) -> Res<()> {
4266    if hk > 128 {
4267        return Err("gdn_scan_naive_f32: hk > 128".into());
4268    }
4269    let f = e.func("gdn_scan_naive_f32");
4270    let cfg = LaunchConfig {
4271        grid_dim: (nv as u32, 1, 1),
4272        block_dim: (hv as u32, 1, 1),
4273        shared_mem_bytes: ((2 * hk + 2) * 4) as u32,
4274    };
4275    let (nki, nvi, hki, hvi, ti) = (nk as i32, nv as i32, hk as i32, hv as i32, t as i32);
4276    let stream = e.gpu.stream();
4277    let mut b = stream.launch_builder(&f);
4278    b.arg(qkv)
4279        .arg(g_log)
4280        .arg(beta_raw)
4281        .arg(state)
4282        .arg(o)
4283        .arg(&nki)
4284        .arg(&nvi)
4285        .arg(&hki)
4286        .arg(&hvi)
4287        .arg(&ti)
4288        .arg(&scale)
4289        .arg(&eps);
4290    unsafe {
4291        b.launch(cfg)?;
4292    }
4293    Ok(())
4294}
4295
4296/// One launch of the decode-step scan twin (`gdn_scan_step_f32`, t == 1): grid
4297/// (nv, hv), block hk — one state element per thread (see the kernel doc; the
4298/// accumulation class vs the naive kernel's sequential row sums).
4299#[allow(clippy::too_many_arguments)]
4300fn launch_gdn_scan_step(
4301    e: &Engine,
4302    qkv: &CudaSlice<f32>,
4303    g_log: &CudaSlice<f32>,
4304    beta_raw: &CudaSlice<f32>,
4305    state: &mut CudaSlice<f32>,
4306    o: &mut CudaSlice<f32>,
4307    nk: usize,
4308    nv: usize,
4309    hk: usize,
4310    hv: usize,
4311    scale: f32,
4312    eps: f32,
4313) -> Res<()> {
4314    if hk % 32 != 0 || hk > 1024 {
4315        return Err("gdn_scan_step_f32: hk must be a multiple of 32 and <= 1024".into());
4316    }
4317    let f = e.func("gdn_scan_step_f32");
4318    let cfg = LaunchConfig {
4319        grid_dim: (nv as u32, hv as u32, 1),
4320        block_dim: (hk as u32, 1, 1),
4321        shared_mem_bytes: 0,
4322    };
4323    let (nki, nvi, hki, hvi) = (nk as i32, nv as i32, hk as i32, hv as i32);
4324    let stream = e.gpu.stream();
4325    let mut b = stream.launch_builder(&f);
4326    b.arg(qkv)
4327        .arg(g_log)
4328        .arg(beta_raw)
4329        .arg(state)
4330        .arg(o)
4331        .arg(&nki)
4332        .arg(&nvi)
4333        .arg(&hki)
4334        .arg(&hvi)
4335        .arg(&scale)
4336        .arg(&eps);
4337    unsafe {
4338        b.launch(cfg)?;
4339    }
4340    Ok(())
4341}
4342
4343/// Per-token step-scan launch at COLUMN `tok` of a chunk (verify-exact rows): views of
4344/// the token's post-conv row / g_log / beta / output row, the SAME kernel and grid as
4345/// the decode step — each column is bit-identical to the t == 1 decode launch.
4346#[allow(clippy::too_many_arguments)]
4347fn launch_gdn_scan_step_at(
4348    e: &Engine,
4349    conv_out: &CudaSlice<f32>,
4350    g_log: &CudaSlice<f32>,
4351    beta_raw: &CudaSlice<f32>,
4352    state: &mut CudaSlice<f32>,
4353    o: &mut CudaSlice<f32>,
4354    tok: usize,
4355    nk: usize,
4356    nv: usize,
4357    hk: usize,
4358    hv: usize,
4359    scale: f32,
4360    eps: f32,
4361) -> Res<()> {
4362    if hk % 32 != 0 || hk > 1024 {
4363        return Err("gdn_scan_step_f32: hk must be a multiple of 32 and <= 1024".into());
4364    }
4365    let conv_dim = 2 * nk * hk + nv * hv;
4366    let qv = conv_out.slice(tok * conv_dim..(tok + 1) * conv_dim);
4367    let gv = g_log.slice(tok * nv..(tok + 1) * nv);
4368    let bv = beta_raw.slice(tok * nv..(tok + 1) * nv);
4369    let mut ov = o.slice_mut(tok * nv * hv..(tok + 1) * nv * hv);
4370    let f = e.func("gdn_scan_step_f32");
4371    let cfg = LaunchConfig {
4372        grid_dim: (nv as u32, hv as u32, 1),
4373        block_dim: (hk as u32, 1, 1),
4374        shared_mem_bytes: 0,
4375    };
4376    let (nki, nvi, hki, hvi) = (nk as i32, nv as i32, hk as i32, hv as i32);
4377    let stream = e.gpu.stream();
4378    let mut b = stream.launch_builder(&f);
4379    b.arg(&qv)
4380        .arg(&gv)
4381        .arg(&bv)
4382        .arg(&mut *state)
4383        .arg(&mut ov)
4384        .arg(&nki)
4385        .arg(&nvi)
4386        .arg(&hki)
4387        .arg(&hvi)
4388        .arg(&scale)
4389        .arg(&eps);
4390    unsafe {
4391        b.launch(cfg)?;
4392    }
4393    Ok(())
4394}
4395
4396/// Per-token NAIVE-scan launch at column `tok` (t == 1 views) — the exact-verify twin
4397/// for geometries the step kernel refuses (tiny hk): identical to the t == 1 decode
4398/// dispatch on those plans.
4399#[allow(clippy::too_many_arguments)]
4400fn launch_gdn_scan_at(
4401    e: &Engine,
4402    conv_out: &CudaSlice<f32>,
4403    g_log: &CudaSlice<f32>,
4404    beta_raw: &CudaSlice<f32>,
4405    state: &mut CudaSlice<f32>,
4406    o: &mut CudaSlice<f32>,
4407    tok: usize,
4408    nk: usize,
4409    nv: usize,
4410    hk: usize,
4411    hv: usize,
4412    scale: f32,
4413    eps: f32,
4414) -> Res<()> {
4415    if hk > 128 {
4416        return Err("gdn_scan_naive_f32: hk > 128".into());
4417    }
4418    let conv_dim = 2 * nk * hk + nv * hv;
4419    let qv = conv_out.slice(tok * conv_dim..(tok + 1) * conv_dim);
4420    let gv = g_log.slice(tok * nv..(tok + 1) * nv);
4421    let bv = beta_raw.slice(tok * nv..(tok + 1) * nv);
4422    let mut ov = o.slice_mut(tok * nv * hv..(tok + 1) * nv * hv);
4423    let f = e.func("gdn_scan_naive_f32");
4424    let cfg = LaunchConfig {
4425        grid_dim: (nv as u32, 1, 1),
4426        block_dim: (hv as u32, 1, 1),
4427        shared_mem_bytes: ((2 * hk + 2) * 4) as u32,
4428    };
4429    let (nki, nvi, hki, hvi, ti) = (nk as i32, nv as i32, hk as i32, hv as i32, 1i32);
4430    let stream = e.gpu.stream();
4431    let mut b = stream.launch_builder(&f);
4432    b.arg(&qv)
4433        .arg(&gv)
4434        .arg(&bv)
4435        .arg(&mut *state)
4436        .arg(&mut ov)
4437        .arg(&nki)
4438        .arg(&nvi)
4439        .arg(&hki)
4440        .arg(&hvi)
4441        .arg(&ti)
4442        .arg(&scale)
4443        .arg(&eps);
4444    unsafe {
4445        b.launch(cfg)?;
4446    }
4447    Ok(())
4448}
4449
4450/// One launch of the fused GDN norm+gate (`rms_sigmul_f32`): dst = rms_norm(x, w) *
4451/// sigmoid(z) over `nrows` rows of `ncols` — bit-identical to the rms_norm + sigmoid +
4452/// mul chain (kernel doc).
4453#[allow(clippy::too_many_arguments)]
4454fn launch_rms_sigmul(
4455    e: &Engine,
4456    x: &CudaSlice<f32>,
4457    w: &CudaSlice<f32>,
4458    z: &CudaSlice<f32>,
4459    dst: &mut CudaSlice<f32>,
4460    ncols: usize,
4461    nrows: usize,
4462    eps: f32,
4463) -> Res<()> {
4464    let f = e.func("rms_sigmul_f32");
4465    let cfg = LaunchConfig {
4466        grid_dim: (nrows as u32, 1, 1),
4467        block_dim: (crate::rms_block(), 1, 1),
4468        shared_mem_bytes: 0,
4469    };
4470    let (nc, ep) = (ncols as i32, eps);
4471    let stream = e.gpu.stream();
4472    let mut b = stream.launch_builder(&f);
4473    b.arg(x).arg(w).arg(z).arg(dst).arg(&nc).arg(&ep);
4474    unsafe {
4475        b.launch(cfg)?;
4476    }
4477    Ok(())
4478}
4479
4480#[allow(clippy::too_many_arguments)]
4481fn launch_dwconv(
4482    e: &Engine,
4483    x: &CudaSlice<f32>,
4484    hist: &CudaSlice<f32>,
4485    w: &CudaSlice<f32>,
4486    y: &mut CudaSlice<f32>,
4487    t: usize,
4488    th: usize,
4489    c: usize,
4490    k: usize,
4491    dilation: usize,
4492    mode: i32,
4493) -> Res<()> {
4494    let f = e.func("dwconv_causal_f32");
4495    let cfg = LaunchConfig::for_num_elems((t * c) as u32);
4496    let (ti, thi, ci, ki, di) = (t as i32, th as i32, c as i32, k as i32, dilation as i32);
4497    let stream = e.gpu.stream();
4498    let mut b = stream.launch_builder(&f);
4499    b.arg(x)
4500        .arg(hist)
4501        .arg(w)
4502        .arg(y)
4503        .arg(&ti)
4504        .arg(&thi)
4505        .arg(&ci)
4506        .arg(&ki)
4507        .arg(&di)
4508        .arg(&mode);
4509    unsafe {
4510        b.launch(cfg)?;
4511    }
4512    Ok(())
4513}
4514
4515/// One routed expert's SwiGLU: gate/up GEMMs on the gathered token rows, silu_mul, down.
4516#[allow(clippy::too_many_arguments)]
4517fn run_routed_expert(
4518    e: &Engine,
4519    xg: &CudaSlice<f32>,
4520    gate: &CudaView<'_, f32>,
4521    up: &CudaView<'_, f32>,
4522    down: &CudaView<'_, f32>,
4523    m_e: usize,
4524    hidden: usize,
4525    ff: usize,
4526) -> Res<CudaSlice<f32>> {
4527    let xg_view = xg.slice(0..m_e * hidden);
4528    let mut gate_out = e.uninit(m_e * ff)?;
4529    e.linear_device_into(&xg_view, gate, &mut gate_out, m_e, hidden, ff)?;
4530    let mut up_out = e.uninit(m_e * ff)?;
4531    e.linear_device_into(&xg_view, up, &mut up_out, m_e, hidden, ff)?;
4532    let mut act = e.uninit(m_e * ff)?;
4533    e.silu_mul(&gate_out, &up_out, &mut act, m_e * ff)?;
4534    let mut down_out = e.uninit(m_e * hidden)?;
4535    e.linear_device_into(
4536        &act.slice(0..m_e * ff),
4537        down,
4538        &mut down_out,
4539        m_e,
4540        ff,
4541        hidden,
4542    )?;
4543    Ok(down_out)
4544}
4545
4546/// View-destination twin of `Engine::rms_norm` — same kernel, same block size, same args,
4547/// so BIT-IDENTICAL; it exists only so the gate can normalize into one contiguous
4548/// stream-major buffer instead of `streams` separate allocations (the fused gate kernels
4549/// need every stream in one launch). PDL is skipped: dependent launch changes scheduling,
4550/// not arithmetic.
4551fn launch_rms_norm_into_view(
4552    e: &Engine,
4553    x: &CudaSlice<f32>,
4554    w: &CudaSlice<f32>,
4555    dst: &mut cudarc::driver::CudaViewMut<'_, f32>,
4556    ncols: usize,
4557    nrows: usize,
4558    eps: f32,
4559) -> Res<()> {
4560    let kname = if Engine::norm_ilp_on() {
4561        "rms_norm_f32_v2"
4562    } else {
4563        "rms_norm_f32"
4564    };
4565    let f = e.func(kname);
4566    let cfg = LaunchConfig {
4567        grid_dim: (nrows as u32, 1, 1),
4568        block_dim: (crate::rms_block(), 1, 1),
4569        shared_mem_bytes: 0,
4570    };
4571    let (nc, ep) = (ncols as i32, eps);
4572    let stream = e.gpu.stream();
4573    let mut b = stream.launch_builder(&f);
4574    b.arg(x).arg(w).arg(dst).arg(&nc).arg(&ep);
4575    unsafe {
4576        b.launch(cfg)?;
4577    }
4578    Ok(())
4579}
4580
4581/// `hc_lowrank_reduce_f32`: low_act[t, rank] = silu(inv_streams · Σ_s parts[s, t, rank]).
4582fn launch_hc_lowrank_reduce(
4583    e: &Engine,
4584    parts: &CudaSlice<f32>,
4585    low_act: &mut CudaSlice<f32>,
4586    streams: usize,
4587    t: usize,
4588    rank: usize,
4589) -> Res<()> {
4590    let f = e.func("hc_lowrank_reduce_f32");
4591    let cfg = LaunchConfig::for_num_elems((t * rank) as u32);
4592    let (si, ti, ri) = (streams as i32, t as i32, rank as i32);
4593    let inv = 1.0f32 / streams as f32;
4594    let stream = e.gpu.stream();
4595    let mut b = stream.launch_builder(&f);
4596    b.arg(parts)
4597        .arg(low_act)
4598        .arg(&si)
4599        .arg(&ti)
4600        .arg(&ri)
4601        .arg(&inv);
4602    unsafe {
4603        b.launch(cfg)?;
4604    }
4605    Ok(())
4606}
4607
4608/// `hc_mix_epilogue_f32`: mixed = inv_streams · Σ_s sigmoid(gates_s) ⊙ normed_s.
4609fn launch_hc_mix_epilogue(
4610    e: &Engine,
4611    gates: &CudaSlice<f32>,
4612    normed: &CudaSlice<f32>,
4613    mixed: &mut CudaSlice<f32>,
4614    streams: usize,
4615    t: usize,
4616    hidden: usize,
4617) -> Res<()> {
4618    let f = e.func("hc_mix_epilogue_f32");
4619    let cfg = LaunchConfig::for_num_elems((t * hidden) as u32);
4620    let (si, ti, hi) = (streams as i32, t as i32, hidden as i32);
4621    let inv = 1.0f32 / streams as f32;
4622    let stream = e.gpu.stream();
4623    let mut b = stream.launch_builder(&f);
4624    b.arg(gates)
4625        .arg(normed)
4626        .arg(mixed)
4627        .arg(&si)
4628        .arg(&ti)
4629        .arg(&hi)
4630        .arg(&inv);
4631    unsafe {
4632        b.launch(cfg)?;
4633    }
4634    Ok(())
4635}
4636
4637/// `hc_inject_gates_f32`: out[s, t] = 2·sigmoid(inv_streams · ⟨w_s, wide_normed_t⟩).
4638fn launch_hc_inject_gates(
4639    e: &Engine,
4640    normed: &CudaSlice<f32>,
4641    w: &CudaSlice<f32>,
4642    out: &mut CudaSlice<f32>,
4643    streams: usize,
4644    t: usize,
4645    hidden: usize,
4646) -> Res<()> {
4647    let f = e.func("hc_inject_gates_f32");
4648    let cfg = LaunchConfig {
4649        grid_dim: (streams as u32, t as u32, 1),
4650        block_dim: (256, 1, 1),
4651        shared_mem_bytes: 0,
4652    };
4653    let (si, ti, hi) = (streams as i32, t as i32, hidden as i32);
4654    let inv = 1.0f32 / streams as f32;
4655    let stream = e.gpu.stream();
4656    let mut b = stream.launch_builder(&f);
4657    b.arg(normed)
4658        .arg(w)
4659        .arg(out)
4660        .arg(&si)
4661        .arg(&ti)
4662        .arg(&hi)
4663        .arg(&inv);
4664    unsafe {
4665        b.launch(cfg)?;
4666    }
4667    Ok(())
4668}
4669
4670/// Inject scalars as either per-stream rows (the item-1-era plumbing, hcmicro OFF and
4671/// the legacy gate) or the [streams, t] slab straight out of the two-stage inject
4672/// (hcmicro ON — no per-stream d2d copies; `gate_write` consumes it in one launch).
4673enum InjectOut {
4674    Rows(Vec<CudaSlice<f32>>),
4675    Slab(CudaSlice<f32>),
4676}
4677
4678/// Park an inject result back into its slots (the form is flag-determined, so takes and
4679/// puts pair up step over step).
4680fn put_inject(ws: &mut StepPool, inject: InjectOut) {
4681    match inject {
4682        InjectOut::Rows(rows) => {
4683            for (s, row) in rows.into_iter().enumerate() {
4684                ws.put_f32(INJECT_SLOTS[s], row);
4685            }
4686        }
4687        InjectOut::Slab(slab) => ws.put_f32("hc.inj_all", slab),
4688    }
4689}
4690
4691/// Take the parked inject scalars in the form the current seams produce (graph driver's
4692/// MoE tail — the mlp read gate parked them in the interior segment).
4693fn take_inject(e: &Engine, ws: &mut StepPool, streams: usize, t: usize) -> Res<InjectOut> {
4694    // The diet emits the Slab form and requires micro_inj at dispatch, so this predicate
4695    // stays in lockstep with what gate_read parked.
4696    if micro_inj_on() && hc_fused_gate_on() {
4697        Ok(InjectOut::Slab(ws.take_f32(
4698            e,
4699            "hc.inj_all",
4700            streams * t,
4701            0,
4702        )?))
4703    } else {
4704        let mut rows = Vec::with_capacity(streams);
4705        for s in 0..streams {
4706            rows.push(ws.take_f32(e, INJECT_SLOTS[s], t, 0)?);
4707        }
4708        Ok(InjectOut::Rows(rows))
4709    }
4710}
4711
4712/// `hc_norm_planes_f32`: per-(stream, token) RMSNorm over the plane pointer table into
4713/// the stream-major normed slab — one launch for all streams (hcmicro seam).
4714#[allow(clippy::too_many_arguments)]
4715fn launch_hc_norm_planes(
4716    e: &Engine,
4717    ptrs: &CudaSlice<u64>,
4718    w_stack: &CudaSlice<f32>,
4719    dst: &mut CudaSlice<f32>,
4720    hidden: usize,
4721    t: usize,
4722    streams: usize,
4723    eps: f32,
4724) -> Res<()> {
4725    let f = e.func("hc_norm_planes_f32");
4726    let cfg = LaunchConfig {
4727        grid_dim: (t as u32, streams as u32, 1),
4728        block_dim: (256, 1, 1),
4729        shared_mem_bytes: 0,
4730    };
4731    let (hi, ti) = (hidden as i32, t as i32);
4732    let stream = e.gpu.stream();
4733    let mut b = stream.launch_builder(&f);
4734    b.arg(ptrs)
4735        .arg(w_stack)
4736        .arg(dst)
4737        .arg(&hi)
4738        .arg(&ti)
4739        .arg(&eps);
4740    unsafe {
4741        b.launch(cfg)?;
4742    }
4743    Ok(())
4744}
4745
4746/// Two-stage inject (hcmicro seam): chunked partial dots (fills the card; the
4747/// single-stage kernel ran `streams` blocks) then a sequential-order reduce + sigmoid.
4748/// Deterministic — no atomics (greedy replays must stay byte-stable).
4749#[allow(clippy::too_many_arguments)]
4750fn launch_hc_inject_two_stage(
4751    e: &Engine,
4752    normed: &CudaSlice<f32>,
4753    w_f32: &CudaSlice<f32>,
4754    w_b16: Option<&CudaSlice<u8>>,
4755    partials: &mut CudaSlice<f32>,
4756    out: &mut CudaSlice<f32>,
4757    streams: usize,
4758    t: usize,
4759    hidden: usize,
4760    chunks: usize,
4761) -> Res<()> {
4762    let cfg = LaunchConfig {
4763        grid_dim: (streams as u32, t as u32, chunks as u32),
4764        block_dim: (256, 1, 1),
4765        shared_mem_bytes: 0,
4766    };
4767    let (si, ti, hi, ci) = (streams as i32, t as i32, hidden as i32, chunks as i32);
4768    let stream = e.gpu.stream();
4769    if let Some(w) = w_b16 {
4770        let f = e.func("hc_inject_partials_bf16w_f32");
4771        let mut b = stream.launch_builder(&f);
4772        b.arg(normed)
4773            .arg(w)
4774            .arg(&mut *partials)
4775            .arg(&si)
4776            .arg(&ti)
4777            .arg(&hi)
4778            .arg(&ci);
4779        unsafe {
4780            b.launch(cfg)?;
4781        }
4782    } else {
4783        let f = e.func("hc_inject_partials_f32");
4784        let mut b = stream.launch_builder(&f);
4785        b.arg(normed)
4786            .arg(w_f32)
4787            .arg(&mut *partials)
4788            .arg(&si)
4789            .arg(&ti)
4790            .arg(&hi)
4791            .arg(&ci);
4792        unsafe {
4793            b.launch(cfg)?;
4794        }
4795    }
4796    let rows = (streams * t) as i32;
4797    let inv = 1.0f32 / streams as f32;
4798    let f = e.func("hc_inject_reduce_f32");
4799    let cfg = LaunchConfig::for_num_elems((streams * t) as u32);
4800    let mut b = stream.launch_builder(&f);
4801    b.arg(&*partials).arg(out).arg(&rows).arg(&ci).arg(&inv);
4802    unsafe {
4803        b.launch(cfg)?;
4804    }
4805    Ok(())
4806}
4807
4808/// hc-diet stage 1 (`hc_diet_stage1_f32`): per (row-chunk, stream) block — RMS recompute
4809/// from the raw plane, normed row in smem, this chunk's down rows + inject partial rows.
4810/// Emits parts [S, rank], inj_parts [n_inj, S], inv [S].
4811#[allow(clippy::too_many_arguments)]
4812#[allow(clippy::too_many_arguments)]
4813fn launch_hc_diet_stage1(
4814    e: &Engine,
4815    ptrs: &CudaSlice<u64>,
4816    nw_stack: &CudaSlice<f32>,
4817    wdown_b16: &CudaSlice<u8>,
4818    winj_b16: Option<&CudaSlice<u8>>,
4819    parts: &mut CudaSlice<f32>,
4820    inj_parts: &mut CudaSlice<f32>,
4821    inv_out: &mut CudaSlice<f32>,
4822    hidden: usize,
4823    rank: usize,
4824    streams: usize,
4825    t: usize,
4826    eps: f32,
4827) -> Res<()> {
4828    if hidden % 8 != 0 {
4829        return Err("hc_diet_stage1_f32: hidden % 8 != 0".into());
4830    }
4831    let n_inj = if winj_b16.is_some() { streams } else { 0 };
4832    const ROWS_PB: usize = 4;
4833    let total_rows = rank + n_inj;
4834    if parts.len() < t * streams * rank
4835        || (n_inj > 0 && inj_parts.len() < t * n_inj * streams)
4836        || inv_out.len() < t * streams
4837    {
4838        return Err("hc_diet_stage1_f32: output buffers too short".into());
4839    }
4840    let f = e.func("hc_diet_stage1_f32");
4841    let cfg = LaunchConfig {
4842        grid_dim: (
4843            total_rows.div_ceil(ROWS_PB) as u32,
4844            t as u32,
4845            streams as u32,
4846        ),
4847        block_dim: (256, 1, 1),
4848        shared_mem_bytes: (hidden * 4) as u32,
4849    };
4850    let (hi, ri, si, nji, rpb) = (
4851        hidden as i32,
4852        rank as i32,
4853        streams as i32,
4854        n_inj as i32,
4855        ROWS_PB as i32,
4856    );
4857    let winj = winj_b16.unwrap_or(wdown_b16); // unread when n_inj == 0
4858    let stream = e.gpu.stream();
4859    let mut b = stream.launch_builder(&f);
4860    b.arg(ptrs)
4861        .arg(nw_stack)
4862        .arg(wdown_b16)
4863        .arg(winj)
4864        .arg(&mut *parts)
4865        .arg(&mut *inj_parts)
4866        .arg(&mut *inv_out)
4867        .arg(&hi)
4868        .arg(&ri)
4869        .arg(&si)
4870        .arg(&nji)
4871        .arg(&rpb)
4872        .arg(&eps);
4873    unsafe {
4874        b.launch(cfg)?;
4875    }
4876    Ok(())
4877}
4878
4879/// hc-diet stage 2 (`hc_diet_stage2_f32`): low_act = silu(mean_s parts) (the
4880/// hc_lowrank_reduce association verbatim) + inj = 2*sigmoid(mean_s2 inj_parts).
4881#[allow(clippy::too_many_arguments)]
4882#[allow(clippy::too_many_arguments)]
4883fn launch_hc_diet_stage2(
4884    e: &Engine,
4885    parts: &CudaSlice<f32>,
4886    inj_parts: &CudaSlice<f32>,
4887    low_act: &mut CudaSlice<f32>,
4888    inj_all: &mut CudaSlice<f32>,
4889    rank: usize,
4890    streams: usize,
4891    t: usize,
4892    with_inject: bool,
4893) -> Res<()> {
4894    let n_inj = if with_inject { streams } else { 0 };
4895    if low_act.len() < t * rank || (n_inj > 0 && inj_all.len() < n_inj * t) {
4896        return Err("hc_diet_stage2_f32: output buffers too short".into());
4897    }
4898    let f = e.func("hc_diet_stage2_f32");
4899    let cfg = LaunchConfig {
4900        grid_dim: (((rank + n_inj) as u32).div_ceil(256), t as u32, 1),
4901        block_dim: (256, 1, 1),
4902        shared_mem_bytes: 0,
4903    };
4904    let (ri, si, nji, ti) = (rank as i32, streams as i32, n_inj as i32, t as i32);
4905    let inv = 1.0f32 / streams as f32;
4906    let stream = e.gpu.stream();
4907    let mut b = stream.launch_builder(&f);
4908    b.arg(parts)
4909        .arg(inj_parts)
4910        .arg(&mut *low_act)
4911        .arg(&mut *inj_all)
4912        .arg(&ri)
4913        .arg(&si)
4914        .arg(&nji)
4915        .arg(&ti)
4916        .arg(&inv);
4917    unsafe {
4918        b.launch(cfg)?;
4919    }
4920    Ok(())
4921}
4922
4923/// hc-diet stage 3 (`hc_diet_stage3_f32`): per dim-chunk block — the up dots for all
4924/// streams from a smem low_act copy, then the mix epilogue from the stage-1 inv scalars.
4925#[allow(clippy::too_many_arguments)]
4926fn launch_hc_diet_stage3(
4927    e: &Engine,
4928    ptrs: &CudaSlice<u64>,
4929    nw_stack: &CudaSlice<f32>,
4930    inv_in: &CudaSlice<f32>,
4931    wup_b16: &CudaSlice<u8>,
4932    low_act: &CudaSlice<f32>,
4933    mixed: &mut CudaSlice<f32>,
4934    hidden: usize,
4935    rank: usize,
4936    streams: usize,
4937    t: usize,
4938) -> Res<()> {
4939    const DIMS_PB: usize = 8;
4940    if mixed.len() < t * hidden {
4941        return Err("hc_diet_stage3_f32: output buffer too short".into());
4942    }
4943    let f = e.func("hc_diet_stage3_f32");
4944    let cfg = LaunchConfig {
4945        grid_dim: (hidden.div_ceil(DIMS_PB) as u32, t as u32, 1),
4946        block_dim: (256, 1, 1),
4947        shared_mem_bytes: ((rank + DIMS_PB * streams) * 4) as u32,
4948    };
4949    let (hi, ri, si, dpb) = (hidden as i32, rank as i32, streams as i32, DIMS_PB as i32);
4950    let inv_streams = 1.0f32 / streams as f32;
4951    let stream = e.gpu.stream();
4952    let mut b = stream.launch_builder(&f);
4953    b.arg(ptrs)
4954        .arg(nw_stack)
4955        .arg(inv_in)
4956        .arg(wup_b16)
4957        .arg(low_act)
4958        .arg(&mut *mixed)
4959        .arg(&hi)
4960        .arg(&ri)
4961        .arg(&si)
4962        .arg(&dpb)
4963        .arg(&inv_streams);
4964    unsafe {
4965        b.launch(cfg)?;
4966    }
4967    Ok(())
4968}
4969
4970/// hc-diet MT stage 0 (`hc_diet_stage0_mt_f32`): the stage-1 RMS reduce EXACTLY, per
4971/// (token, stream) — bit-equal inv scalars for the weight-shared stages.
4972fn launch_hc_diet_stage0_mt(
4973    e: &Engine,
4974    ptrs: &CudaSlice<u64>,
4975    inv_out: &mut CudaSlice<f32>,
4976    hidden: usize,
4977    streams: usize,
4978    t: usize,
4979    eps: f32,
4980) -> Res<()> {
4981    if inv_out.len() < t * streams {
4982        return Err("hc_diet_stage0_mt_f32: inv buffer too short".into());
4983    }
4984    let f = e.func("hc_diet_stage0_mt_f32");
4985    let cfg = LaunchConfig {
4986        grid_dim: (t as u32, streams as u32, 1),
4987        block_dim: (256, 1, 1),
4988        shared_mem_bytes: 0,
4989    };
4990    let (hi, si, ti) = (hidden as i32, streams as i32, t as i32);
4991    let stream = e.gpu.stream();
4992    let mut b = stream.launch_builder(&f);
4993    b.arg(ptrs)
4994        .arg(&mut *inv_out)
4995        .arg(&hi)
4996        .arg(&si)
4997        .arg(&ti)
4998        .arg(&eps);
4999    unsafe {
5000        b.launch(cfg)?;
5001    }
5002    Ok(())
5003}
5004
5005/// hc-diet MT stage 1: weight rows read ONCE, tokens iterated inside with inline
5006/// normalization — per-(row, token) chains VERBATIM vs the token-grid stage 1.
5007#[allow(clippy::too_many_arguments)]
5008fn launch_hc_diet_stage1_mt(
5009    e: &Engine,
5010    ptrs: &CudaSlice<u64>,
5011    nw_stack: &CudaSlice<f32>,
5012    inv_in: &CudaSlice<f32>,
5013    wdown_b16: &CudaSlice<u8>,
5014    winj_b16: Option<&CudaSlice<u8>>,
5015    parts: &mut CudaSlice<f32>,
5016    inj_parts: &mut CudaSlice<f32>,
5017    hidden: usize,
5018    rank: usize,
5019    streams: usize,
5020    t: usize,
5021) -> Res<()> {
5022    if hidden % 8 != 0 || !(2..=12).contains(&t) {
5023        return Err("hc_diet_stage1_mt_f32: geometry".into());
5024    }
5025    let n_inj = if winj_b16.is_some() { streams } else { 0 };
5026    const ROWS_PB: usize = 4;
5027    let total_rows = rank + n_inj;
5028    if parts.len() < t * streams * rank || (n_inj > 0 && inj_parts.len() < t * n_inj * streams) {
5029        return Err("hc_diet_stage1_mt_f32: output buffers too short".into());
5030    }
5031    let f = e.func("hc_diet_stage1_mt_f32");
5032    let cfg = LaunchConfig {
5033        grid_dim: (total_rows.div_ceil(ROWS_PB) as u32, 1, streams as u32),
5034        block_dim: (256, 1, 1),
5035        shared_mem_bytes: 0,
5036    };
5037    let (hi, ri, si, nji, rpb, ti) = (
5038        hidden as i32,
5039        rank as i32,
5040        streams as i32,
5041        n_inj as i32,
5042        ROWS_PB as i32,
5043        t as i32,
5044    );
5045    let winj = winj_b16.unwrap_or(wdown_b16);
5046    let stream = e.gpu.stream();
5047    let mut b = stream.launch_builder(&f);
5048    b.arg(ptrs)
5049        .arg(nw_stack)
5050        .arg(inv_in)
5051        .arg(wdown_b16)
5052        .arg(winj)
5053        .arg(&mut *parts)
5054        .arg(&mut *inj_parts)
5055        .arg(&hi)
5056        .arg(&ri)
5057        .arg(&si)
5058        .arg(&nji)
5059        .arg(&rpb)
5060        .arg(&ti);
5061    unsafe {
5062        b.launch(cfg)?;
5063    }
5064    Ok(())
5065}
5066
5067/// hc-diet MT stage 3: up rows read once, all T low_act rows resident in smem.
5068#[allow(clippy::too_many_arguments)]
5069fn launch_hc_diet_stage3_mt(
5070    e: &Engine,
5071    ptrs: &CudaSlice<u64>,
5072    nw_stack: &CudaSlice<f32>,
5073    inv_in: &CudaSlice<f32>,
5074    wup_b16: &CudaSlice<u8>,
5075    low_act: &CudaSlice<f32>,
5076    mixed: &mut CudaSlice<f32>,
5077    hidden: usize,
5078    rank: usize,
5079    streams: usize,
5080    t: usize,
5081) -> Res<()> {
5082    const DIMS_PB: usize = 8;
5083    if !(2..=12).contains(&t) || mixed.len() < t * hidden {
5084        return Err("hc_diet_stage3_mt_f32: geometry".into());
5085    }
5086    let smem = ((t * rank + DIMS_PB * streams * t) * 4) as u32;
5087    if smem > 96 * 1024 {
5088        return Err("hc_diet_stage3_mt_f32: smem over budget".into());
5089    }
5090    let f = e.func("hc_diet_stage3_mt_f32");
5091    let cfg = LaunchConfig {
5092        grid_dim: (hidden.div_ceil(DIMS_PB) as u32, 1, 1),
5093        block_dim: (256, 1, 1),
5094        shared_mem_bytes: smem,
5095    };
5096    let (hi, ri, si, dpb, ti) = (
5097        hidden as i32,
5098        rank as i32,
5099        streams as i32,
5100        DIMS_PB as i32,
5101        t as i32,
5102    );
5103    let inv_streams = 1.0f32 / streams as f32;
5104    let stream = e.gpu.stream();
5105    let mut b = stream.launch_builder(&f);
5106    b.arg(ptrs)
5107        .arg(nw_stack)
5108        .arg(inv_in)
5109        .arg(wup_b16)
5110        .arg(low_act)
5111        .arg(&mut *mixed)
5112        .arg(&hi)
5113        .arg(&ri)
5114        .arg(&si)
5115        .arg(&dpb)
5116        .arg(&ti)
5117        .arg(&inv_streams);
5118    unsafe {
5119        b.launch(cfg)?;
5120    }
5121    Ok(())
5122}
5123
5124/// `hc_write_planes_f32`: plane_s += block_out ⊗ inj[s] for every stream in one launch
5125/// over the plane pointer table (hcmicro seam).
5126fn launch_hc_write_planes(
5127    e: &Engine,
5128    ptrs: &CudaSlice<u64>,
5129    block_out: &CudaSlice<f32>,
5130    inj: &CudaSlice<f32>,
5131    hidden: usize,
5132    t: usize,
5133    streams: usize,
5134) -> Res<()> {
5135    let f = e.func("hc_write_planes_f32");
5136    let n = (t * hidden) as u32;
5137    let cfg = LaunchConfig {
5138        grid_dim: (n.div_ceil(256), streams as u32, 1),
5139        block_dim: (256, 1, 1),
5140        shared_mem_bytes: 0,
5141    };
5142    let (hi, ti) = (hidden as i32, t as i32);
5143    let stream = e.gpu.stream();
5144    let mut b = stream.launch_builder(&f);
5145    b.arg(ptrs).arg(block_out).arg(inj).arg(&hi).arg(&ti);
5146    unsafe {
5147        b.launch(cfg)?;
5148    }
5149    Ok(())
5150}
5151
5152/// `hc_inject_gates_bf16w_f32`: the bf16-weight twin of `launch_hc_inject_gates` — same
5153/// grid, same loop order, same reduction tree, exact bf16→f32 widening, so BIT-IDENTICAL
5154/// to the f32 arm when the resident bytes match (the `bf16_twin` representability guard).
5155fn launch_hc_inject_gates_b16(
5156    e: &Engine,
5157    normed: &CudaSlice<f32>,
5158    w: &CudaSlice<u8>,
5159    out: &mut CudaSlice<f32>,
5160    streams: usize,
5161    t: usize,
5162    hidden: usize,
5163) -> Res<()> {
5164    let f = e.func("hc_inject_gates_bf16w_f32");
5165    let cfg = LaunchConfig {
5166        grid_dim: (streams as u32, t as u32, 1),
5167        block_dim: (256, 1, 1),
5168        shared_mem_bytes: 0,
5169    };
5170    let (si, ti, hi) = (streams as i32, t as i32, hidden as i32);
5171    let inv = 1.0f32 / streams as f32;
5172    let stream = e.gpu.stream();
5173    let mut b = stream.launch_builder(&f);
5174    b.arg(normed)
5175        .arg(w)
5176        .arg(out)
5177        .arg(&si)
5178        .arg(&ti)
5179        .arg(&hi)
5180        .arg(&inv);
5181    unsafe {
5182        b.launch(cfg)?;
5183    }
5184    Ok(())
5185}
5186
5187/// bf16 trunk-residency twin builder (load time). Returns the packed bf16 device bytes
5188/// iff BOTH guards pass: in_f % 8 == 0 (the kernel's uint4 vector width — geometry, not
5189/// policy) and every value is exactly bf16-representable (low 16 mantissa bits zero —
5190/// true whenever the checkpoint row was BF16, since dequant is an exact widening; the
5191/// f32 tiny fixture fails this and keeps its f32-only residency).
5192fn bf16_twin(e: &Engine, data: &[f32], in_f: usize) -> Res<Option<CudaSlice<u8>>> {
5193    if in_f % 8 != 0 {
5194        return Ok(None);
5195    }
5196    let mut bytes = Vec::with_capacity(data.len() * 2);
5197    for &v in data {
5198        let bits = v.to_bits();
5199        if bits & 0xFFFF != 0 {
5200            return Ok(None);
5201        }
5202        bytes.extend_from_slice(&((bits >> 16) as u16).to_le_bytes());
5203    }
5204    Ok(Some(e.htod_bytes(&bytes)?))
5205}
5206
5207/// One launch of `qmatvec_bf16w_f32`: y[b, tok, :out_f] = W_b(bf16) @ x_{b,tok}, f32
5208/// accumulate. Strides in ELEMENTS; `x_bstride == 0` shares one activation across the
5209/// batch (the read gate's up projection). Products are exact (bf16→f32 widening); only
5210/// the reduction tree differs from cuBLASLt — the accumulation class.
5211#[allow(clippy::too_many_arguments)]
5212fn launch_qmatvec_bf16w(
5213    e: &Engine,
5214    w: &CudaSlice<u8>,
5215    x: &CudaSlice<f32>,
5216    y: &mut CudaSlice<f32>,
5217    in_f: usize,
5218    out_f: usize,
5219    t: usize,
5220    batch: usize,
5221    w_bstride: usize,
5222    x_bstride: usize,
5223    x_tstride: usize,
5224    y_bstride: usize,
5225) -> Res<()> {
5226    if in_f % 8 != 0 || x_bstride % 8 != 0 || x_tstride % 8 != 0 {
5227        return Err("qmatvec_bf16w_f32: stride breaks the uint4/float4 vector width".into());
5228    }
5229    if y.len() < (batch - 1) * y_bstride + t * out_f {
5230        return Err("qmatvec_bf16w_f32: output buffer too short".into());
5231    }
5232    let f = e.func("qmatvec_bf16w_f32");
5233    let cfg = LaunchConfig {
5234        grid_dim: (out_f as u32, t as u32, batch as u32),
5235        block_dim: (128, 1, 1),
5236        shared_mem_bytes: 0,
5237    };
5238    let (inf, outf, ti) = (in_f as i32, out_f as i32, t as i32);
5239    let (wb, xb, xt, yb) = (
5240        w_bstride as i64,
5241        x_bstride as i64,
5242        x_tstride as i64,
5243        y_bstride as i64,
5244    );
5245    let stream = e.gpu.stream();
5246    let mut b = stream.launch_builder(&f);
5247    b.arg(w)
5248        .arg(x)
5249        .arg(y)
5250        .arg(&inf)
5251        .arg(&outf)
5252        .arg(&ti)
5253        .arg(&wb)
5254        .arg(&xb)
5255        .arg(&xt)
5256        .arg(&yb);
5257    unsafe {
5258        b.launch(cfg)?;
5259    }
5260    Ok(())
5261}
5262
5263/// Stacked bf16 twin over several same-in_f projections (the proj-stack seam): concat
5264/// the host f32 rows and build one packed twin. `None` under the same guards as
5265/// `bf16_twin` (in_f % 8, exact representability of EVERY part). The stack REPLACES the
5266/// per-mat twins (VRAM-neutral): the per-mat arm launches against row-offset VIEWS of
5267/// the stack — same bytes, same kernel, bit-identical to separate residency.
5268fn bf16_stack_twin(e: &Engine, parts: &[&[f32]], in_f: usize) -> Res<Option<CudaSlice<u8>>> {
5269    let mut cat: Vec<f32> = Vec::with_capacity(parts.iter().map(|p| p.len()).sum());
5270    for p in parts {
5271        cat.extend_from_slice(p);
5272    }
5273    bf16_twin(e, &cat, in_f)
5274}
5275
5276/// Required-stack twin (the TP2 `need_twin` posture).
5277fn need_stack_twin(e: &Engine, parts: &[&[f32]], in_f: usize, what: &str) -> Res<CudaSlice<u8>> {
5278    bf16_stack_twin(e, parts, in_f)?.ok_or_else(|| {
5279        format!("qwen4exp_gpu tp2: {what} has no exact bf16 stack twin (in_f {in_f})").into()
5280    })
5281}
5282
5283/// One `qmatvec_bf16w_f32` launch against a ROW-OFFSET VIEW of a stacked twin (the
5284/// per-mat arm of the proj-stack seam): W = stack rows [row_off, row_off+out_f), batch 1.
5285/// Identical kernel, grid, and bytes as a separately-resident twin => bit-identical.
5286#[allow(clippy::too_many_arguments)]
5287fn launch_qmatvec_bf16w_off(
5288    e: &Engine,
5289    w_stack: &CudaSlice<u8>,
5290    row_off: usize,
5291    x: &CudaSlice<f32>,
5292    y: &mut CudaSlice<f32>,
5293    in_f: usize,
5294    out_f: usize,
5295    t: usize,
5296) -> Res<()> {
5297    if in_f % 8 != 0 {
5298        return Err("qmatvec_bf16w_f32: stride breaks the uint4/float4 vector width".into());
5299    }
5300    if y.len() < t * out_f {
5301        return Err("qmatvec_bf16w_f32: output buffer too short".into());
5302    }
5303    let byte_off = row_off * in_f * 2;
5304    if w_stack.len() < byte_off + out_f * in_f * 2 {
5305        return Err("qmatvec_bf16w_f32: stacked twin shorter than the row window".into());
5306    }
5307    let wv = w_stack.slice(byte_off..w_stack.len());
5308    let f = e.func("qmatvec_bf16w_f32");
5309    let cfg = LaunchConfig {
5310        grid_dim: (out_f as u32, t as u32, 1),
5311        block_dim: (128, 1, 1),
5312        shared_mem_bytes: 0,
5313    };
5314    let (inf, outf, ti) = (in_f as i32, out_f as i32, t as i32);
5315    let (wb, xb, xt, yb) = (0i64, 0i64, in_f as i64, 0i64);
5316    let stream = e.gpu.stream();
5317    let mut b = stream.launch_builder(&f);
5318    b.arg(&wv)
5319        .arg(x)
5320        .arg(y)
5321        .arg(&inf)
5322        .arg(&outf)
5323        .arg(&ti)
5324        .arg(&wb)
5325        .arg(&xb)
5326        .arg(&xt)
5327        .arg(&yb);
5328    unsafe {
5329        b.launch(cfg)?;
5330    }
5331    Ok(())
5332}
5333
5334/// `qmatvec_bf16w_f32` against row-offset W, x, and y VIEWS (t == 1): the per-selected-
5335/// expert arm of the DeviceBf16 draft bank (mtp-spec lane) — expert `e`'s projection is
5336/// rows [w_row_off, w_row_off+out_f) of the resident [E*out_f, in_f] bf16 stack. Same
5337/// kernel and per-row program as every other qmatvec_bf16w launch (exact-widening
5338/// products, block-128 reduce) => rows are bit-identical to a separately-resident twin.
5339#[allow(clippy::too_many_arguments)]
5340fn launch_qmatvec_bf16w_off_into(
5341    e: &Engine,
5342    w_stack: &CudaSlice<u8>,
5343    w_row_off: usize,
5344    x: &CudaSlice<f32>,
5345    x_off: usize,
5346    y: &mut CudaSlice<f32>,
5347    y_off: usize,
5348    in_f: usize,
5349    out_f: usize,
5350) -> Res<()> {
5351    if in_f % 8 != 0 {
5352        return Err("qmatvec_bf16w_f32: stride breaks the uint4/float4 vector width".into());
5353    }
5354    let byte_off = w_row_off * in_f * 2;
5355    if w_stack.len() < byte_off + out_f * in_f * 2 {
5356        return Err("qmatvec_bf16w_f32: bank shorter than the expert row window".into());
5357    }
5358    if x.len() < x_off + in_f || y.len() < y_off + out_f {
5359        return Err("qmatvec_bf16w_f32: operand views out of range".into());
5360    }
5361    let wv = w_stack.slice(byte_off..w_stack.len());
5362    let xv = x.slice(x_off..x_off + in_f);
5363    let mut yv = y.slice_mut(y_off..y_off + out_f);
5364    let f = e.func("qmatvec_bf16w_f32");
5365    let cfg = LaunchConfig {
5366        grid_dim: (out_f as u32, 1, 1),
5367        block_dim: (128, 1, 1),
5368        shared_mem_bytes: 0,
5369    };
5370    let (inf, outf, ti) = (in_f as i32, out_f as i32, 1i32);
5371    let (wb, xb, xt, yb) = (0i64, 0i64, in_f as i64, 0i64);
5372    let stream = e.gpu.stream();
5373    let mut b = stream.launch_builder(&f);
5374    b.arg(&wv)
5375        .arg(&xv)
5376        .arg(&mut yv)
5377        .arg(&inf)
5378        .arg(&outf)
5379        .arg(&ti)
5380        .arg(&wb)
5381        .arg(&xb)
5382        .arg(&xt)
5383        .arg(&yb);
5384    unsafe {
5385        b.launch(cfg)?;
5386    }
5387    Ok(())
5388}
5389
5390/// Device-selected expert launch over a DeviceBf16 bank (`qmatvec_bf16w_sel_f32`,
5391/// devtwin lane): one launch per projection covers every routed expert — slot s reads
5392/// its expert id from the DEVICE `sel` array at `sel_off + s` and writes y at s*out_f.
5393/// Per-row program qmatvec_bf16w_f32 VERBATIM => bit-identical to the per-slot
5394/// `launch_qmatvec_bf16w_off_into` chain (asserted by the bf16 oracle's sel mode).
5395#[allow(clippy::too_many_arguments)]
5396fn launch_qmatvec_bf16w_sel(
5397    e: &Engine,
5398    bank: &CudaSlice<u8>,
5399    sel: &CudaSlice<i32>,
5400    sel_off: usize,
5401    x: &CudaSlice<f32>,
5402    x_off: usize,
5403    // Per-slot activation stride in elements: 0 = shared row (gate/up), in_f = each
5404    // slot its own row (down over the act slab).
5405    x_sstride: usize,
5406    y: &mut CudaSlice<f32>,
5407    n_sel: usize,
5408    in_f: usize,
5409    out_f: usize,
5410) -> Res<()> {
5411    if in_f % 8 != 0 {
5412        return Err("qmatvec_bf16w_sel_f32: stride breaks the uint4/float4 vector width".into());
5413    }
5414    if sel.len() < sel_off + n_sel
5415        || x.len() < x_off + (n_sel - 1) * x_sstride + in_f
5416        || y.len() < n_sel * out_f
5417        || n_sel == 0
5418    {
5419        return Err("qmatvec_bf16w_sel_f32: operand views out of range".into());
5420    }
5421    let sv = sel.slice(sel_off..sel_off + n_sel);
5422    let xv = x.slice(x_off..x.len());
5423    let f = e.func("qmatvec_bf16w_sel_f32");
5424    let cfg = LaunchConfig {
5425        grid_dim: (out_f as u32, 1, n_sel as u32),
5426        block_dim: (128, 1, 1),
5427        shared_mem_bytes: 0,
5428    };
5429    let (inf, outf, ns) = (in_f as i32, out_f as i32, n_sel as i32);
5430    let xs = x_sstride as i64;
5431    let stream = e.gpu.stream();
5432    let mut b = stream.launch_builder(&f);
5433    b.arg(bank)
5434        .arg(&sv)
5435        .arg(&xv)
5436        .arg(&mut *y)
5437        .arg(&inf)
5438        .arg(&outf)
5439        .arg(&ns)
5440        .arg(&xs);
5441    unsafe {
5442        b.launch(cfg)?;
5443    }
5444    Ok(())
5445}
5446
5447/// Multi-token weight-shared launch (`qmatvec_bf16w_mt_f32`, mtp-spec verify): one
5448/// block per output row reads W once and fills EVERY token's output — per (row, token)
5449/// bit-identical to the per-token grid (kernel doc). 2 <= t <= 12; `w_row_off` selects
5450/// a row window of a stacked twin.
5451#[allow(clippy::too_many_arguments)]
5452fn launch_qmatvec_bf16w_mt(
5453    e: &Engine,
5454    w_stack: &CudaSlice<u8>,
5455    w_row_off: usize,
5456    x: &CudaSlice<f32>,
5457    y: &mut CudaSlice<f32>,
5458    in_f: usize,
5459    out_f: usize,
5460    t: usize,
5461) -> Res<()> {
5462    if in_f % 8 != 0 {
5463        return Err("qmatvec_bf16w_mt_f32: in_f % 8 != 0".into());
5464    }
5465    if !(2..=12).contains(&t) {
5466        return Err("qmatvec_bf16w_mt_f32: t out of range (2..=12)".into());
5467    }
5468    let byte_off = w_row_off * in_f * 2;
5469    if w_stack.len() < byte_off + out_f * in_f * 2 || y.len() < t * out_f || x.len() < t * in_f {
5470        return Err("qmatvec_bf16w_mt_f32: operands out of range".into());
5471    }
5472    let wv = w_stack.slice(byte_off..w_stack.len());
5473    let f = e.func("qmatvec_bf16w_mt_f32");
5474    let cfg = LaunchConfig {
5475        grid_dim: (out_f as u32, 1, 1),
5476        block_dim: (128, 1, 1),
5477        shared_mem_bytes: 0,
5478    };
5479    let (inf, outf, ti) = (in_f as i32, out_f as i32, t as i32);
5480    let (wb, xb, xt, yb) = (0i64, 0i64, in_f as i64, 0i64);
5481    let stream = e.gpu.stream();
5482    let mut b = stream.launch_builder(&f);
5483    b.arg(&wv)
5484        .arg(x)
5485        .arg(y)
5486        .arg(&inf)
5487        .arg(&outf)
5488        .arg(&ti)
5489        .arg(&wb)
5490        .arg(&xb)
5491        .arg(&xt)
5492        .arg(&yb);
5493    unsafe {
5494        b.launch(cfg)?;
5495    }
5496    Ok(())
5497}
5498
5499/// Trunk dense linear off a STACKED bf16 twin (proj-stack residency): the bf16 arm is a
5500/// row-offset view launch when the twin exists and the trunk seam is on, else the f32
5501/// cuBLASLt path.
5502#[allow(clippy::too_many_arguments)]
5503fn linear_trunk_stacked_into(
5504    e: &Engine,
5505    w_f32: &CudaSlice<f32>,
5506    stack_b16: &Option<CudaSlice<u8>>,
5507    row_off: usize,
5508    x: &CudaSlice<f32>,
5509    y: &mut CudaSlice<f32>,
5510    t: usize,
5511    in_f: usize,
5512    out_f: usize,
5513) -> Res<()> {
5514    if trunk_bf16_on() {
5515        if let Some(w) = stack_b16 {
5516            if (2..=12).contains(&t) && verify_mt_on() {
5517                return launch_qmatvec_bf16w_mt(e, w, row_off, x, y, in_f, out_f, t);
5518            }
5519            return launch_qmatvec_bf16w_off(e, w, row_off, x, y, in_f, out_f, t);
5520        }
5521    }
5522    if w_f32.len() < in_f * out_f {
5523        return Err(
5524            "qwen4exp_gpu: trunk f32 original dropped (trunk_f32_diet) — the bf16 \
5525                    twin path is required (keep trunk seams ON)"
5526                .into(),
5527        );
5528    }
5529    e.linear_device_into(x, w_f32, y, t, in_f, out_f)
5530}
5531
5532/// One launch of `qmatvec_bf16w_multi4_f32`: the row-stacked twin against ONE t==1
5533/// activation, each output row routed into its original destination buffer by row range
5534/// (raw device pointers — no copies). Per-row math is qmatvec_bf16w_f32 VERBATIM, so
5535/// outputs are BIT-IDENTICAL to the per-mat launches this replaces.
5536fn launch_qmatvec_bf16w_multi4(
5537    e: &Engine,
5538    w_stack: &CudaSlice<u8>,
5539    x: &CudaSlice<f32>,
5540    parts: &[(&CudaSlice<f32>, usize)],
5541    in_f: usize,
5542) -> Res<()> {
5543    if in_f % 8 != 0 {
5544        return Err("qmatvec_bf16w_multi4_f32: in_f % 8 != 0".into());
5545    }
5546    if parts.is_empty() || parts.len() > 4 {
5547        return Err("qmatvec_bf16w_multi4_f32: 1..=4 parts".into());
5548    }
5549    let total: usize = parts.iter().map(|&(_, r)| r).sum();
5550    if w_stack.len() < total * in_f * 2 {
5551        return Err("qmatvec_bf16w_multi4_f32: stacked twin shorter than the row plan".into());
5552    }
5553    let stream = e.gpu.stream();
5554    let mut ptrs = [0u64; 4];
5555    let mut rows = [0i32; 4];
5556    for (i, &(buf, r)) in parts.iter().enumerate() {
5557        if buf.len() < r {
5558            return Err("qmatvec_bf16w_multi4_f32: destination shorter than its rows".into());
5559        }
5560        ptrs[i] = buf.device_ptr(&stream).0;
5561        rows[i] = r as i32;
5562    }
5563    let f = e.func("qmatvec_bf16w_multi4_f32");
5564    let cfg = LaunchConfig {
5565        grid_dim: (total as u32, 1, 1),
5566        block_dim: (128, 1, 1),
5567        shared_mem_bytes: 0,
5568    };
5569    let inf = in_f as i32;
5570    let mut b = stream.launch_builder(&f);
5571    b.arg(w_stack)
5572        .arg(x)
5573        .arg(&ptrs[0])
5574        .arg(&rows[0])
5575        .arg(&ptrs[1])
5576        .arg(&rows[1])
5577        .arg(&ptrs[2])
5578        .arg(&rows[2])
5579        .arg(&ptrs[3])
5580        .arg(&rows[3])
5581        .arg(&inf);
5582    unsafe {
5583        b.launch(cfg)?;
5584    }
5585    Ok(())
5586}
5587
5588/// Trunk dense linear into a caller-provided buffer: the bf16 twin (one
5589/// `qmatvec_bf16w_f32` launch) when resident and the seam is on, else the f32
5590/// cuBLASLt path — the A/B twin (the step-workspace form, item 2a).
5591#[allow(clippy::too_many_arguments)]
5592fn linear_trunk_into(
5593    e: &Engine,
5594    w_f32: &CudaSlice<f32>,
5595    w_b16: &Option<CudaSlice<u8>>,
5596    x: &CudaSlice<f32>,
5597    y: &mut CudaSlice<f32>,
5598    t: usize,
5599    in_f: usize,
5600    out_f: usize,
5601) -> Res<()> {
5602    if trunk_bf16_on() {
5603        if let Some(w) = w_b16 {
5604            if (2..=12).contains(&t) && verify_mt_on() {
5605                return launch_qmatvec_bf16w_mt(e, w, 0, x, y, in_f, out_f, t);
5606            }
5607            return launch_qmatvec_bf16w(e, w, x, y, in_f, out_f, t, 1, 0, 0, in_f, 0);
5608        }
5609    }
5610    if w_f32.len() < in_f * out_f {
5611        return Err(
5612            "qwen4exp_gpu: trunk f32 original dropped (trunk_f32_diet) — the bf16 \
5613                    twin path is required (keep trunk seams ON)"
5614                .into(),
5615        );
5616    }
5617    e.linear_device_into(x, w_f32, y, t, in_f, out_f)
5618}
5619
5620/// One launch of the grouped selected-experts matvec: y[slot, :out_f] =
5621/// macros[sel[slot]] × (W_{sel[slot]} @ x_slot) over the AS-STORED modelopt bank (no
5622/// repack). `x_stride` = 0 shares one activation row across slots (gate/up); = in_f
5623/// reads per-slot rows (down). Dispatches the v2 kernel (uint4 code loads + 2 rows per
5624/// warp — perf lane item 3) when the seam is on and the geometry admits it
5625/// (in_f % 32 == 0, out_f % 2 == 0); v1 is the fallback and the A/B twin. Round 3 adds
5626/// the v3 kernel (4 rows/warp, `set_sel_v3`, out_f % 4 == 0) ahead of v2 in the chain.
5627#[allow(clippy::too_many_arguments)]
5628fn launch_nvfp4_sel_matvec(
5629    e: &Engine,
5630    codes: &CudaSlice<u8>,
5631    scales: &CudaSlice<u8>,
5632    macros_dev: &CudaSlice<f32>,
5633    sel: &CudaSlice<i32>,
5634    x: &CudaSlice<f32>,
5635    y: &mut CudaSlice<f32>,
5636    n_sel: usize,
5637    in_f: usize,
5638    out_f: usize,
5639    x_stride: usize,
5640) -> Res<()> {
5641    if in_f % 16 != 0 {
5642        return Err("qmatvec_nvfp4_modelopt_sel_f32: in_f % 16 != 0".into());
5643    }
5644    if y.len() < n_sel * out_f {
5645        return Err("qmatvec_nvfp4_modelopt_sel_f32: output shorter than n_sel*out_f".into());
5646    }
5647    let v3 = sel_v3_on() && in_f % 32 == 0 && out_f % 4 == 0;
5648    let v2 = !v3 && sel_v2_on() && in_f % 32 == 0 && out_f % 2 == 0;
5649    let f = e.func(if v3 {
5650        "qmatvec_nvfp4_modelopt_sel_f32_v3"
5651    } else if v2 {
5652        "qmatvec_nvfp4_modelopt_sel_f32_v2"
5653    } else {
5654        "qmatvec_nvfp4_modelopt_sel_f32"
5655    });
5656    // Warp packing (4 warps/block) was tried here and REVERTED: measured NEGATIVE on
5657    // decode (plain arm 14.38 -> 15.13 ms) and flat on verify sel (mtp6 battery,
5658    // spec/mtp6) — the sel slice is not SM-block-slot-limited. The kernels keep the
5659    // lane-based indexing (identical at block 32); launch stays one warp per block.
5660    let grid_x = if v3 {
5661        out_f / 4
5662    } else if v2 {
5663        out_f / 2
5664    } else {
5665        out_f
5666    };
5667    let cfg = LaunchConfig {
5668        grid_dim: (grid_x as u32, n_sel as u32, 1),
5669        block_dim: (32, 1, 1),
5670        shared_mem_bytes: 0,
5671    };
5672    let (inf, outf) = (in_f as i32, out_f as i32);
5673    let xs = x_stride as i64;
5674    let stream = e.gpu.stream();
5675    let mut b = stream.launch_builder(&f);
5676    b.arg(codes)
5677        .arg(scales)
5678        .arg(macros_dev)
5679        .arg(sel)
5680        .arg(x)
5681        .arg(y)
5682        .arg(&inf)
5683        .arg(&outf)
5684        .arg(&xs);
5685    unsafe {
5686        b.launch(cfg)?;
5687    }
5688    Ok(())
5689}
5690
5691/// One launch of the fused gate+up+silu sel matvec
5692/// (`qmatvec_nvfp4_modelopt_sel_gu_silu_f32`): act[slot, :ff] = silu(gate) * up over
5693/// the shared activation row. `sel`/`pack_raw` pick the addressing mode (host sel
5694/// array vs the TP2 count-gated pack blob). Bit-identical to the v3 gate + v3 up +
5695/// silu_mul chain (kernel doc).
5696#[allow(clippy::too_many_arguments)]
5697#[allow(clippy::too_many_arguments)]
5698fn launch_nvfp4_sel_gu_silu(
5699    e: &Engine,
5700    gate: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
5701    up: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
5702    sel: Option<&CudaSlice<i32>>,
5703    pack_raw: u64,
5704    n_sel: usize,
5705    x: &CudaSlice<f32>,
5706    act: &mut CudaSlice<f32>,
5707    in_f: usize,
5708    ff: usize,
5709    // (slot -> token map, x token stride): ONE launch over every verify column's
5710    // routed experts (per-slot program unchanged — bit-identical). None = shared x.
5711    tok: Option<(&CudaSlice<i32>, usize)>,
5712) -> Res<()> {
5713    if in_f % 32 != 0 || ff % 4 != 0 {
5714        return Err("qmatvec_nvfp4_modelopt_sel_gu_silu_f32: geometry".into());
5715    }
5716    if act.len() < n_sel * ff {
5717        return Err("qmatvec_nvfp4_modelopt_sel_gu_silu_f32: act buffer too short".into());
5718    }
5719    if sel.is_none() == (pack_raw == 0) {
5720        return Err("qmatvec_nvfp4_modelopt_sel_gu_silu_f32: exactly one of sel/pack".into());
5721    }
5722    let f = e.func("qmatvec_nvfp4_modelopt_sel_gu_silu_f32");
5723    // Warp packing reverted (see launch_nvfp4_sel_matvec): one warp per block.
5724    let cfg = LaunchConfig {
5725        grid_dim: ((ff / 4) as u32, n_sel as u32, 1),
5726        block_dim: (32, 1, 1),
5727        shared_mem_bytes: 0,
5728    };
5729    let (inf, ffi, ms) = (in_f as i32, ff as i32, n_sel as i32);
5730    let stream = e.gpu.stream();
5731    let mut b = stream.launch_builder(&f);
5732    b.arg(gate.0)
5733        .arg(gate.1)
5734        .arg(gate.2)
5735        .arg(up.0)
5736        .arg(up.1)
5737        .arg(up.2);
5738    match sel {
5739        Some(s) => {
5740            b.arg(s);
5741        }
5742        None => {
5743            // unread in pack mode; any live device pointer keeps the arg slot filled
5744            b.arg(gate.2);
5745        }
5746    }
5747    let stream2 = e.gpu.stream();
5748    let (tok_raw, x_tstride) = match tok {
5749        Some((tm, stride)) => (tm.device_ptr(&stream2).0, stride as i64),
5750        None => (0u64, 0i64),
5751    };
5752    b.arg(&pack_raw)
5753        .arg(&ms)
5754        .arg(x)
5755        .arg(&mut *act)
5756        .arg(&inf)
5757        .arg(&ffi)
5758        .arg(&tok_raw)
5759        .arg(&x_tstride);
5760    unsafe {
5761        b.launch(cfg)?;
5762    }
5763    Ok(())
5764}
5765
5766/// Sequential slot-combine over a WINDOW of a taller partial slab (mtp-spec verify):
5767/// rows [x_row0, x_row0+n_rows) x weights [w_off..] into y row `y_row` — the
5768/// axpy_rows_seq_f32 chain VERBATIM over that window (per-token combine order equals
5769/// the decode combine).
5770#[allow(clippy::too_many_arguments)]
5771fn launch_axpy_rows_seq_at(
5772    e: &Engine,
5773    x: &CudaSlice<f32>,
5774    x_row0: usize,
5775    w: &CudaSlice<f32>,
5776    w_off: usize,
5777    y: &mut CudaSlice<f32>,
5778    y_row: usize,
5779    width: usize,
5780    n_rows: usize,
5781) -> Res<()> {
5782    if x.len() < (x_row0 + n_rows) * width
5783        || w.len() < w_off + n_rows
5784        || y.len() < (y_row + 1) * width
5785    {
5786        return Err("axpy_rows_seq_f32: window out of range".into());
5787    }
5788    let xv = x.slice(x_row0 * width..(x_row0 + n_rows) * width);
5789    let wv = w.slice(w_off..w_off + n_rows);
5790    let mut yv = y.slice_mut(y_row * width..(y_row + 1) * width);
5791    let f = e.func("axpy_rows_seq_f32");
5792    let cfg = LaunchConfig::for_num_elems(width as u32);
5793    let (wi, nr) = (width as i32, n_rows as i32);
5794    let stream = e.gpu.stream();
5795    let mut b = stream.launch_builder(&f);
5796    b.arg(&xv).arg(&wv).arg(&mut yv).arg(&wi).arg(&nr);
5797    unsafe {
5798        b.launch(cfg)?;
5799    }
5800    Ok(())
5801}
5802
5803/// Kernel-vs-host oracle for the grouped decode kernel (`qmatvec_nvfp4_modelopt_sel_f32`).
5804/// The tiny four-arm gate cannot reach that kernel (the tiny down projection is BF16 by
5805/// geometry, so the grouped path never engages there); this synthetic arm gates the
5806/// kernel directly against the host decoder chain (`dsv4::dequant_nvfp4_expert` + host
5807/// f32 matvec): deterministic codes/scales including planted NaN scale bytes (modelopt
5808/// NaN -> 0.0) , mixed pow2/non-pow2 macros (the real mint's class), duplicate slots in
5809/// `sel`, and BOTH x_stride modes (shared gate/up row, per-slot down rows). Products are
5810/// exact; only summation order differs from the host chain — tolerance 1e-5 rel.
5811pub fn gate_nvfp4_sel_matvec(e: &Engine) -> Res<String> {
5812    let mut lcg = 0x2545_f491_u64;
5813    let mut next_u32 = move || -> u32 {
5814        lcg = lcg
5815            .wrapping_mul(6364136223846793005)
5816            .wrapping_add(1442695040888963407);
5817        (lcg >> 33) as u32
5818    };
5819    let macros = [
5820        1.0f32,
5821        0.5,
5822        5.9945243e-5, // the measured non-pow2 mint class
5823        2.0,
5824        0.25,
5825        3.7e-3,
5826        1.0,
5827        8.0,
5828    ];
5829    let sel_host: Vec<i32> = vec![3, 5, 3, 0]; // duplicate slot on purpose
5830    let n_sel = sel_host.len();
5831    let mut worst = (0.0f32, 0.0f32); // (max_abs, max_rel)
5832    // Shapes + per-mode seam forcing pick the dispatched kernel: v3 modes force the
5833    // 4-row kernel (its guard is out_f % 4 == 0, which the v2 shapes also satisfy, so
5834    // the seam is toggled per mode and restored to the shipped default after); v2
5835    // shapes take the 2-row kernel with v3 off; in_f 48 and the odd out_f take the v1
5836    // fallback — all three kernels and every geometry guard are gated in one pass.
5837    for (mode, out_f, in_f) in [
5838        ("gate_up_v1", 16usize, 48usize),
5839        ("down_v1", 32, 16),
5840        ("gate_up_v1_oddrows", 7, 64),
5841        ("gate_up_v2", 16, 64),
5842        ("down_v2", 32, 32),
5843        ("gate_up_v3", 16, 64),
5844        ("down_v3", 32, 32),
5845        ("gate_up_v3_v2rows", 6, 64), // out_f % 4 != 0 falls v3 -> v2 under the v3 seam
5846    ] {
5847        set_sel_v3(mode.contains("v3"));
5848        let n_expert = macros.len();
5849        let mut codes = vec![0u8; n_expert * out_f * in_f / 2];
5850        for byte in &mut codes {
5851            *byte = next_u32() as u8;
5852        }
5853        let mut scales = vec![0u8; n_expert * out_f * in_f / 16];
5854        for byte in &mut scales {
5855            *byte = (next_u32() as u8) & 0xBF; // mag < 0x40 keeps magnitudes tame
5856        }
5857        scales[0] = 0x7F; // NaN code -> 0.0 (modelopt convention), pinned here
5858        scales[3] = 0xFF; // signed NaN code -> 0.0 too
5859        let x_stride = if mode.starts_with("down") { in_f } else { 0 };
5860        let x_rows = if x_stride == 0 { 1 } else { n_sel };
5861        let x_host: Vec<f32> = (0..x_rows * in_f)
5862            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
5863            .collect();
5864        let codes_dev = e.htod_bytes(&codes)?;
5865        let scales_dev = e.htod_bytes(&scales)?;
5866        let macros_dev = e.htod(&macros)?;
5867        let sel_dev = e.htod_i32(&sel_host)?;
5868        let x_dev = e.htod(&x_host)?;
5869        let mut y_dev = e.uninit(n_sel * out_f)?;
5870        launch_nvfp4_sel_matvec(
5871            e,
5872            &codes_dev,
5873            &scales_dev,
5874            &macros_dev,
5875            &sel_dev,
5876            &x_dev,
5877            &mut y_dev,
5878            n_sel,
5879            in_f,
5880            out_f,
5881            x_stride,
5882        )?;
5883        let y = e.dtoh(&y_dev)?;
5884        let wbytes = out_f * in_f / 2;
5885        let sbytes = out_f * in_f / 16;
5886        for (slot, &expert) in sel_host.iter().enumerate() {
5887            let expert = expert as usize;
5888            let w = memra_gguf::dsv4::dequant_nvfp4_expert(
5889                &codes[expert * wbytes..(expert + 1) * wbytes],
5890                &scales[expert * sbytes..(expert + 1) * sbytes],
5891                macros[expert],
5892                out_f,
5893                in_f,
5894            );
5895            let xrow = &x_host[slot * x_stride..slot * x_stride + in_f];
5896            for o in 0..out_f {
5897                let mut want = 0.0f32;
5898                for i in 0..in_f {
5899                    want += w[o * in_f + i] * xrow[i];
5900                }
5901                let got = y[slot * out_f + o];
5902                let abs = (want - got).abs();
5903                let rel = abs / want.abs().max(1.0);
5904                if abs > worst.0 {
5905                    worst.0 = abs;
5906                }
5907                if rel > worst.1 {
5908                    worst.1 = rel;
5909                }
5910                if rel > 1e-5 {
5911                    return Err(format!(
5912                        "nvfp4-sel-matvec oracle: {mode} slot {slot} row {o}: want {want} \
5913                         got {got} (rel {rel:.3e})"
5914                    )
5915                    .into());
5916                }
5917            }
5918        }
5919    }
5920    set_sel_v3(SEL_V3_DEFAULT);
5921
5922    // gufuse mode: the fused gate+up+silu kernel must be BIT-IDENTICAL to the
5923    // v3 gate launch + v3 up launch + silu_mul chain (same per-row arithmetic, same
5924    // epilogue element form — kernel doc). Byte-compare, plus the count-gated pack
5925    // twin's dead-slot sentinel.
5926    {
5927        set_sel_v3(true);
5928        let (ff, in_f) = (16usize, 64usize);
5929        let n_expert = macros.len();
5930        let mut mk = |seed: u8| -> (Vec<u8>, Vec<u8>) {
5931            let mut codes = vec![0u8; n_expert * ff * in_f / 2];
5932            for byte in &mut codes {
5933                *byte = (next_u32() as u8) ^ seed;
5934            }
5935            let mut scales = vec![0u8; n_expert * ff * in_f / 16];
5936            for byte in &mut scales {
5937                *byte = (next_u32() as u8) & 0xBF;
5938            }
5939            scales[1] = 0x7F; // NaN scale byte -> 0.0
5940            (codes, scales)
5941        };
5942        let (g_codes, g_scales) = mk(0x00);
5943        let (u_codes, u_scales) = mk(0x5A);
5944        let gmac: Vec<f32> = macros.to_vec();
5945        let umac: Vec<f32> = macros.iter().map(|m| m * 0.5).collect();
5946        let x_host: Vec<f32> = (0..in_f)
5947            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
5948            .collect();
5949        let gc = e.htod_bytes(&g_codes)?;
5950        let gs = e.htod_bytes(&g_scales)?;
5951        let gm = e.htod(&gmac)?;
5952        let uc = e.htod_bytes(&u_codes)?;
5953        let us = e.htod_bytes(&u_scales)?;
5954        let um = e.htod(&umac)?;
5955        let sel_dev = e.htod_i32(&sel_host)?;
5956        let x_dev = e.htod(&x_host)?;
5957        // Chain arm: v3 gate + v3 up + silu_mul.
5958        let mut yg = e.uninit(n_sel * ff)?;
5959        let mut yu = e.uninit(n_sel * ff)?;
5960        launch_nvfp4_sel_matvec(
5961            e, &gc, &gs, &gm, &sel_dev, &x_dev, &mut yg, n_sel, in_f, ff, 0,
5962        )?;
5963        launch_nvfp4_sel_matvec(
5964            e, &uc, &us, &um, &sel_dev, &x_dev, &mut yu, n_sel, in_f, ff, 0,
5965        )?;
5966        let mut act_chain = e.zeros(n_sel * ff)?;
5967        e.silu_mul(&yg, &yu, &mut act_chain, n_sel * ff)?;
5968        // Fused arm.
5969        let mut act_fused = e.zeros(n_sel * ff)?;
5970        launch_nvfp4_sel_gu_silu(
5971            e,
5972            (&gc, &gs, &gm),
5973            (&uc, &us, &um),
5974            Some(&sel_dev),
5975            0,
5976            n_sel,
5977            &x_dev,
5978            &mut act_fused,
5979            in_f,
5980            ff,
5981            None,
5982        )?;
5983        let a = e.dtoh(&act_chain)?;
5984        let b = e.dtoh(&act_fused)?;
5985        for (i, (&x1, &x2)) in a.iter().zip(&b).enumerate() {
5986            if x1.to_bits() != x2.to_bits() {
5987                return Err(format!(
5988                    "nvfp4-sel-matvec oracle: gufuse idx {i} not bit-identical \
5989                     (chain {x1} fused {x2})"
5990                )
5991                .into());
5992            }
5993        }
5994        // Pack twin: live count 2 of 4 — live slots bit-match, dead slots keep the
5995        // sentinel.
5996        let pack_bytes = tp2_pack_bytes(&sel_host[..2], &[0.5, 0.25], n_sel);
5997        let pack = e.htod_bytes(&pack_bytes)?;
5998        let pack_raw = {
5999            let stream = e.gpu.stream();
6000            pack.device_ptr(&stream).0
6001        };
6002        let sentinel = vec![-777.0f32; n_sel * ff];
6003        let mut act_pack = e.htod(&sentinel)?;
6004        launch_nvfp4_sel_gu_silu(
6005            e,
6006            (&gc, &gs, &gm),
6007            (&uc, &us, &um),
6008            None,
6009            pack_raw,
6010            n_sel,
6011            &x_dev,
6012            &mut act_pack,
6013            in_f,
6014            ff,
6015            None,
6016        )?;
6017        let c = e.dtoh(&act_pack)?;
6018        for slot in 0..n_sel {
6019            for o in 0..ff {
6020                let got = c[slot * ff + o];
6021                if slot < 2 {
6022                    if got.to_bits() != a[slot * ff + o].to_bits() {
6023                        return Err(format!(
6024                            "nvfp4-sel-matvec oracle: gufuse pack slot {slot} o {o} \
6025                             not bit-identical"
6026                        )
6027                        .into());
6028                    }
6029                } else if got != -777.0 {
6030                    return Err(format!(
6031                        "nvfp4-sel-matvec oracle: gufuse pack dead slot {slot} written"
6032                    )
6033                    .into());
6034                }
6035            }
6036        }
6037        // tok_map twin (mtp-spec verify merge): TWO tokens' slots in ONE launch via the
6038        // slot->token map must bit-match per-token launches over each token's x row.
6039        {
6040            let t2 = 2usize;
6041            let x2_host: Vec<f32> = (0..t2 * in_f)
6042                .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
6043                .collect();
6044            let x2 = e.htod(&x2_host)?;
6045            let tok_host: Vec<i32> = (0..n_sel).map(|s| (s % t2) as i32).collect();
6046            let tokm = e.htod_i32(&tok_host)?;
6047            let mut act_map = e.zeros(n_sel * ff)?;
6048            launch_nvfp4_sel_gu_silu(
6049                e,
6050                (&gc, &gs, &gm),
6051                (&uc, &us, &um),
6052                Some(&sel_dev),
6053                0,
6054                n_sel,
6055                &x2,
6056                &mut act_map,
6057                in_f,
6058                ff,
6059                Some((&tokm, in_f)),
6060            )?;
6061            let got = e.dtoh(&act_map)?;
6062            for tok in 0..t2 {
6063                let slots: Vec<usize> = (0..n_sel).filter(|s| s % t2 == tok).collect();
6064                let sel_tok: Vec<i32> = slots.iter().map(|&s| sel_host[s]).collect();
6065                let sel_tok_dev = e.htod_i32(&sel_tok)?;
6066                let xrow = e.htod(&x2_host[tok * in_f..(tok + 1) * in_f])?;
6067                let mut act_tok = e.zeros(sel_tok.len() * ff)?;
6068                launch_nvfp4_sel_gu_silu(
6069                    e,
6070                    (&gc, &gs, &gm),
6071                    (&uc, &us, &um),
6072                    Some(&sel_tok_dev),
6073                    0,
6074                    sel_tok.len(),
6075                    &xrow,
6076                    &mut act_tok,
6077                    in_f,
6078                    ff,
6079                    None,
6080                )?;
6081                let want = e.dtoh(&act_tok)?;
6082                for (local, &slot) in slots.iter().enumerate() {
6083                    for o in 0..ff {
6084                        let a = got[slot * ff + o];
6085                        let b = want[local * ff + o];
6086                        if a.to_bits() != b.to_bits() {
6087                            return Err(format!(
6088                                "nvfp4-sel-matvec oracle: gufuse tok_map slot {slot} o {o} \
6089                                 not bit-identical (map {a} per-token {b})"
6090                            )
6091                            .into());
6092                        }
6093                    }
6094                }
6095            }
6096        }
6097        set_sel_v3(SEL_V3_DEFAULT);
6098    }
6099    Ok(format!(
6100        "nvfp4-sel-matvec kernel oracle: worst abs {:.3e} rel {:.3e} over gate_up+down \
6101         v1/v2/v3 modes, NaN scales + non-pow2 macros + duplicate slots; gufuse \
6102         BIT-IDENTICAL to the v3+silu chain incl. the count-gated pack twin + the \
6103         tok_map verify merge",
6104        worst.0, worst.1
6105    ))
6106}
6107
6108/// REAL-GEOMETRY oracle for the round-4 hyper-gate diet (the tiny plan's rank 4 fails
6109/// the %8 geometry guard, so the tiny arms never reach these kernels): the THREE-launch
6110/// diet chain (stage 1/2/3) vs the classic fused chain (hc_norm_planes + batched bf16w
6111/// down + lowrank reduce + batched bf16w up + mix epilogue + two-stage inject) on
6112/// IDENTICAL bf16 weights at streams 4, hidden 2560, rank 320, t 1. Tolerance class
6113/// (new reduce widths; 1e-4 rel, worst reported) over low_act, the inject slab, and
6114/// mixed.
6115pub fn gate_hc_diet_kernels(e: &Engine) -> Res<String> {
6116    let (streams, hidden, rank, t) = (4usize, 2560usize, 320usize, 1usize);
6117    let wide = streams * hidden;
6118    let mut lcg = 0x8badf00d_u64;
6119    let mut next_f32 = move || -> f32 {
6120        lcg = lcg
6121            .wrapping_mul(6364136223846793005)
6122            .wrapping_add(1442695040888963407);
6123        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
6124    };
6125    let mut rand_vec = |n: usize| -> Vec<f32> { (0..n).map(|_| next_f32()).collect() };
6126    // bf16-representable weights (truncate the low mantissa bits) so bf16_twin builds.
6127    let to_b16_vals = |v: Vec<f32>| -> Vec<f32> {
6128        v.into_iter()
6129            .map(|x| f32::from_bits(x.to_bits() & 0xFFFF_0000))
6130            .collect()
6131    };
6132    let planes_host: Vec<Vec<f32>> = (0..streams).map(|_| rand_vec(t * hidden)).collect();
6133    let planes: Vec<CudaSlice<f32>> = planes_host
6134        .iter()
6135        .map(|v| e.htod(v))
6136        .collect::<Result<_, _>>()?;
6137    let ptr_vals: Vec<u64> = {
6138        let stream = e.gpu.stream();
6139        planes.iter().map(|p| p.device_ptr(&stream).0).collect()
6140    };
6141    let ptrs = e.htod_u64(&ptr_vals)?;
6142    let norm_stack_host = rand_vec(wide);
6143    let norm_stack = e.htod(&norm_stack_host)?;
6144    let down_host = to_b16_vals(rand_vec(streams * rank * hidden));
6145    let up_host = to_b16_vals(rand_vec(streams * hidden * rank));
6146    let inj_host = to_b16_vals(rand_vec(streams * wide));
6147    let down_b16 = bf16_twin(e, &down_host, hidden)?.ok_or("hc-diet oracle: down twin")?;
6148    let up_b16 = bf16_twin(e, &up_host, rank)?.ok_or("hc-diet oracle: up twin")?;
6149    let inj_b16 = bf16_twin(e, &inj_host, hidden)?.ok_or("hc-diet oracle: inject twin")?;
6150    let inj_f32 = e.htod(&inj_host)?;
6151    let eps = 1e-6f32;
6152
6153    // Classic fused chain (the current default path) on the same operands.
6154    let mut normed = e.zeros(streams * t * hidden)?;
6155    launch_hc_norm_planes(e, &ptrs, &norm_stack, &mut normed, hidden, t, streams, eps)?;
6156    let mut parts_c = e.zeros(streams * t * rank)?;
6157    launch_qmatvec_bf16w(
6158        e,
6159        &down_b16,
6160        &normed,
6161        &mut parts_c,
6162        hidden,
6163        rank,
6164        t,
6165        streams,
6166        rank * hidden,
6167        t * hidden,
6168        hidden,
6169        t * rank,
6170    )?;
6171    let mut low_c = e.zeros(t * rank)?;
6172    launch_hc_lowrank_reduce(e, &parts_c, &mut low_c, streams, t, rank)?;
6173    let mut gates_c = e.zeros(streams * t * hidden)?;
6174    launch_qmatvec_bf16w(
6175        e,
6176        &up_b16,
6177        &low_c,
6178        &mut gates_c,
6179        rank,
6180        hidden,
6181        t,
6182        streams,
6183        hidden * rank,
6184        0,
6185        rank,
6186        t * hidden,
6187    )?;
6188    let mut mixed_c = e.zeros(t * hidden)?;
6189    launch_hc_mix_epilogue(e, &gates_c, &normed, &mut mixed_c, streams, t, hidden)?;
6190    let mut partials_c = e.zeros(streams * t * 16)?;
6191    let mut all_c = e.zeros(streams * t)?;
6192    launch_hc_inject_two_stage(
6193        e,
6194        &normed,
6195        &inj_f32,
6196        Some(&inj_b16),
6197        &mut partials_c,
6198        &mut all_c,
6199        streams,
6200        t,
6201        hidden,
6202        16,
6203    )?;
6204
6205    // Diet chain.
6206    let mut parts_d = e.zeros(streams * rank)?;
6207    let mut injp_d = e.zeros(streams * streams)?;
6208    let mut inv_d = e.zeros(streams)?;
6209    launch_hc_diet_stage1(
6210        e,
6211        &ptrs,
6212        &norm_stack,
6213        &down_b16,
6214        Some(&inj_b16),
6215        &mut parts_d,
6216        &mut injp_d,
6217        &mut inv_d,
6218        hidden,
6219        rank,
6220        streams,
6221        1,
6222        eps,
6223    )?;
6224    let mut low_d = e.zeros(rank)?;
6225    let mut all_d = e.zeros(streams)?;
6226    launch_hc_diet_stage2(
6227        e, &parts_d, &injp_d, &mut low_d, &mut all_d, rank, streams, 1, true,
6228    )?;
6229    let mut mixed_d = e.zeros(hidden)?;
6230    launch_hc_diet_stage3(
6231        e,
6232        &ptrs,
6233        &norm_stack,
6234        &inv_d,
6235        &up_b16,
6236        &low_d,
6237        &mut mixed_d,
6238        hidden,
6239        rank,
6240        streams,
6241        1,
6242    )?;
6243
6244    let mut worst = 0.0f32;
6245    let check = |name: &str, a: &[f32], b: &[f32], worst: &mut f32| -> Res<()> {
6246        for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
6247            let rel = (x - y).abs() / y.abs().max(1.0);
6248            if rel > *worst {
6249                *worst = rel;
6250            }
6251            if rel > 1e-4 {
6252                return Err(format!(
6253                    "hc-diet oracle: {name} idx {i}: diet {x} classic {y} (rel {rel:.3e})"
6254                )
6255                .into());
6256            }
6257        }
6258        Ok(())
6259    };
6260    check("low_act", &e.dtoh(&low_d)?, &e.dtoh(&low_c)?, &mut worst)?;
6261    check("inject", &e.dtoh(&all_d)?, &e.dtoh(&all_c)?, &mut worst)?;
6262    check("mixed", &e.dtoh(&mixed_d)?, &e.dtoh(&mixed_c)?, &mut worst)?;
6263
6264    // Token-dim extension (mtp-spec verify chunks): the SAME kernels at t = 3 must
6265    // produce per-token rows BIT-IDENTICAL to three t = 1 launches at plane offsets —
6266    // the spec byte-identity contract for the read gates.
6267    {
6268        let t3 = 3usize;
6269        let planes3_host: Vec<Vec<f32>> = (0..streams).map(|_| rand_vec(t3 * hidden)).collect();
6270        let planes3: Vec<CudaSlice<f32>> = planes3_host
6271            .iter()
6272            .map(|v| e.htod(v))
6273            .collect::<Result<_, _>>()?;
6274        let ptr_vals3: Vec<u64> = {
6275            let stream = e.gpu.stream();
6276            planes3.iter().map(|p| p.device_ptr(&stream).0).collect()
6277        };
6278        let ptrs3 = e.htod_u64(&ptr_vals3)?;
6279        let mut parts3 = e.zeros(t3 * streams * rank)?;
6280        let mut injp3 = e.zeros(t3 * streams * streams)?;
6281        let mut inv3 = e.zeros(t3 * streams)?;
6282        launch_hc_diet_stage1(
6283            e,
6284            &ptrs3,
6285            &norm_stack,
6286            &down_b16,
6287            Some(&inj_b16),
6288            &mut parts3,
6289            &mut injp3,
6290            &mut inv3,
6291            hidden,
6292            rank,
6293            streams,
6294            t3,
6295            eps,
6296        )?;
6297        let mut low3 = e.zeros(t3 * rank)?;
6298        let mut all3 = e.zeros(streams * t3)?;
6299        launch_hc_diet_stage2(
6300            e, &parts3, &injp3, &mut low3, &mut all3, rank, streams, t3, true,
6301        )?;
6302        let mut mixed3 = e.zeros(t3 * hidden)?;
6303        launch_hc_diet_stage3(
6304            e,
6305            &ptrs3,
6306            &norm_stack,
6307            &inv3,
6308            &up_b16,
6309            &low3,
6310            &mut mixed3,
6311            hidden,
6312            rank,
6313            streams,
6314            t3,
6315        )?;
6316        let low3_h = e.dtoh(&low3)?;
6317        let all3_h = e.dtoh(&all3)?;
6318        let mixed3_h = e.dtoh(&mixed3)?;
6319        // MT weight-shared stages (set_verify_mt): stage0 inv + stage1_mt parts +
6320        // stage3_mt mixed must be BIT-IDENTICAL to the token-grid stages above.
6321        {
6322            let mut inv_mt = e.zeros(t3 * streams)?;
6323            launch_hc_diet_stage0_mt(e, &ptrs3, &mut inv_mt, hidden, streams, t3, eps)?;
6324            let mut parts_mt = e.zeros(t3 * streams * rank)?;
6325            let mut injp_mt = e.zeros(t3 * streams * streams)?;
6326            launch_hc_diet_stage1_mt(
6327                e,
6328                &ptrs3,
6329                &norm_stack,
6330                &inv_mt,
6331                &down_b16,
6332                Some(&inj_b16),
6333                &mut parts_mt,
6334                &mut injp_mt,
6335                hidden,
6336                rank,
6337                streams,
6338                t3,
6339            )?;
6340            let mut low_mt = e.zeros(t3 * rank)?;
6341            let mut all_mt = e.zeros(streams * t3)?;
6342            launch_hc_diet_stage2(
6343                e,
6344                &parts_mt,
6345                &injp_mt,
6346                &mut low_mt,
6347                &mut all_mt,
6348                rank,
6349                streams,
6350                t3,
6351                true,
6352            )?;
6353            let mut mixed_mt = e.zeros(t3 * hidden)?;
6354            launch_hc_diet_stage3_mt(
6355                e,
6356                &ptrs3,
6357                &norm_stack,
6358                &inv_mt,
6359                &up_b16,
6360                &low_mt,
6361                &mut mixed_mt,
6362                hidden,
6363                rank,
6364                streams,
6365                t3,
6366            )?;
6367            let bit_check_mt = |name: &str, a: &[f32], b: &[f32]| -> Res<()> {
6368                for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
6369                    if x.to_bits() != y.to_bits() {
6370                        return Err(format!(
6371                            "hc-diet mt oracle: {name} idx {i}: mt {x} vs grid {y} NOT \
6372                             bit-identical"
6373                        )
6374                        .into());
6375                    }
6376                }
6377                Ok(())
6378            };
6379            bit_check_mt("inv", &e.dtoh(&inv_mt)?, &e.dtoh(&inv3)?)?;
6380            bit_check_mt("low_act", &e.dtoh(&low_mt)?, &low3_h)?;
6381            bit_check_mt("inject", &e.dtoh(&all_mt)?, &all3_h)?;
6382            bit_check_mt("mixed", &e.dtoh(&mixed_mt)?, &mixed3_h)?;
6383        }
6384        let bit_check = |name: &str, a: &[f32], b: &[f32]| -> Res<()> {
6385            for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
6386                if x.to_bits() != y.to_bits() {
6387                    return Err(format!(
6388                        "hc-diet t-ext oracle: {name} idx {i}: t3 {x} vs t1 {y} NOT bit-identical"
6389                    )
6390                    .into());
6391                }
6392            }
6393            Ok(())
6394        };
6395        for tok in 0..t3 {
6396            let ptr_tok: Vec<u64> = ptr_vals3
6397                .iter()
6398                .map(|&base| base + (tok * hidden * 4) as u64)
6399                .collect();
6400            let ptrs_tok = e.htod_u64(&ptr_tok)?;
6401            let mut parts1 = e.zeros(streams * rank)?;
6402            let mut injp1 = e.zeros(streams * streams)?;
6403            let mut inv1 = e.zeros(streams)?;
6404            launch_hc_diet_stage1(
6405                e,
6406                &ptrs_tok,
6407                &norm_stack,
6408                &down_b16,
6409                Some(&inj_b16),
6410                &mut parts1,
6411                &mut injp1,
6412                &mut inv1,
6413                hidden,
6414                rank,
6415                streams,
6416                1,
6417                eps,
6418            )?;
6419            let mut low1 = e.zeros(rank)?;
6420            let mut all1 = e.zeros(streams)?;
6421            launch_hc_diet_stage2(
6422                e, &parts1, &injp1, &mut low1, &mut all1, rank, streams, 1, true,
6423            )?;
6424            let mut mixed1 = e.zeros(hidden)?;
6425            launch_hc_diet_stage3(
6426                e,
6427                &ptrs_tok,
6428                &norm_stack,
6429                &inv1,
6430                &up_b16,
6431                &low1,
6432                &mut mixed1,
6433                hidden,
6434                rank,
6435                streams,
6436                1,
6437            )?;
6438            bit_check(
6439                "low_act",
6440                &low3_h[tok * rank..(tok + 1) * rank],
6441                &e.dtoh(&low1)?,
6442            )?;
6443            let all1_h = e.dtoh(&all1)?;
6444            let col: Vec<f32> = (0..streams).map(|s| all3_h[s * t3 + tok]).collect();
6445            bit_check("inject", &col, &all1_h)?;
6446            bit_check(
6447                "mixed",
6448                &mixed3_h[tok * hidden..(tok + 1) * hidden],
6449                &e.dtoh(&mixed1)?,
6450            )?;
6451        }
6452    }
6453    Ok(format!(
6454        "hc-diet real-geometry oracle: streams 4 hidden 2560 rank 320, worst rel \
6455         {worst:.3e} vs the classic fused chain at t 1; t 3 token-dim AND the mt \
6456         weight-shared stages BIT-IDENTICAL to per-token t 1 launches"
6457    ))
6458}
6459
6460/// Kernel-vs-host oracle for the bf16 trunk matvec (`qmatvec_bf16w_f32`). The tiny
6461/// four-arm gate's FIXTURE weights are random f32 (never bf16-representable), so its
6462/// bf16 twins are skipped by the value guard there and only the dir arms exercise the
6463/// path end to end; this synthetic arm gates the kernel directly against a host f32
6464/// matvec over identical bf16-widened weights: batch > 1, BOTH x_bstride modes (shared
6465/// plane like the up projection, per-batch planes like down), t > 1, negative/denormal
6466/// bf16 values, and a non-multiple-of-blockDim group count. Products are exact; only
6467/// summation order differs from the sequential host chain — tolerance 1e-5 rel.
6468/// REAL-GEOMETRY oracle for the hcmicro kernels (streams 4, hidden 2560, t 10 — the
6469/// artifact's read-gate shape, which the tiny plan (streams 2, hidden 16) cannot
6470/// reach). Each micro kernel runs against the classic composition it replaces on the
6471/// same random inputs: batched plane norms vs per-stream rms_norm, the two-stage inject
6472/// vs the single-stage kernel, the slab write vs the add_scaled_rows chain. Born from
6473/// the perf7 incident: the bundle shipped tiny-green and broke real prefill at layer 0.
6474pub fn gate_hc_micro_kernels(e: &Engine) -> Res<String> {
6475    let (streams, hidden, t) = (4usize, 2560usize, 10usize);
6476    let wide = streams * hidden;
6477    let mut lcg = 0x1357_9bdf_u64;
6478    let mut next_f32 = move || -> f32 {
6479        lcg = lcg
6480            .wrapping_mul(6364136223846793005)
6481            .wrapping_add(1442695040888963407);
6482        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
6483    };
6484    let mut rand_vec = |n: usize| -> Vec<f32> { (0..n).map(|_| next_f32()).collect() };
6485    let planes_host: Vec<Vec<f32>> = (0..streams).map(|_| rand_vec(t * hidden)).collect();
6486    let planes: Vec<CudaSlice<f32>> = planes_host
6487        .iter()
6488        .map(|v| e.htod(v))
6489        .collect::<Result<_, _>>()?;
6490    let ptr_vals: Vec<u64> = {
6491        let stream = e.gpu.stream();
6492        planes.iter().map(|p| p.device_ptr(&stream).0).collect()
6493    };
6494    let ptrs = e.htod_u64(&ptr_vals)?;
6495    let mut worst = 0.0f32;
6496    let check = |name: &str, a: &[f32], b: &[f32], worst: &mut f32| -> Res<()> {
6497        for (i, (&x, &y)) in a.iter().zip(b).enumerate() {
6498            let rel = (x - y).abs() / y.abs().max(1.0);
6499            if rel > *worst {
6500                *worst = rel;
6501            }
6502            if rel > 1e-4 {
6503                return Err(format!(
6504                    "hc-micro oracle: {name} idx {i}: micro {x} classic {y} (rel {rel:.3e})"
6505                )
6506                .into());
6507            }
6508        }
6509        Ok(())
6510    };
6511
6512    // (a) batched plane norms vs per-stream rms_norm_into_view.
6513    let norm_stack_host = rand_vec(wide);
6514    let norm_stack = e.htod(&norm_stack_host)?;
6515    let eps = 1e-6f32;
6516    let mut normed_a = e.zeros(streams * t * hidden)?;
6517    launch_hc_norm_planes(
6518        e,
6519        &ptrs,
6520        &norm_stack,
6521        &mut normed_a,
6522        hidden,
6523        t,
6524        streams,
6525        eps,
6526    )?;
6527    let mut normed_b = e.zeros(streams * t * hidden)?;
6528    for s in 0..streams {
6529        let w = e.htod(&norm_stack_host[s * hidden..(s + 1) * hidden])?;
6530        let mut dst = normed_b.slice_mut(s * t * hidden..(s + 1) * t * hidden);
6531        launch_rms_norm_into_view(e, &planes[s], &w, &mut dst, hidden, t, eps)?;
6532    }
6533    check("norm", &e.dtoh(&normed_a)?, &e.dtoh(&normed_b)?, &mut worst)?;
6534
6535    // (b) two-stage inject vs the single-stage kernel, over the SAME normed slab.
6536    let inj_w_host = rand_vec(streams * wide);
6537    let inj_w = e.htod(&inj_w_host)?;
6538    let mut all_a = e.zeros(streams * t)?;
6539    let mut partials = e.zeros(streams * t * 16)?;
6540    launch_hc_inject_two_stage(
6541        e,
6542        &normed_b,
6543        &inj_w,
6544        None,
6545        &mut partials,
6546        &mut all_a,
6547        streams,
6548        t,
6549        hidden,
6550        16,
6551    )?;
6552    let mut all_b = e.zeros(streams * t)?;
6553    launch_hc_inject_gates(e, &normed_b, &inj_w, &mut all_b, streams, t, hidden)?;
6554    check("inject", &e.dtoh(&all_a)?, &e.dtoh(&all_b)?, &mut worst)?;
6555
6556    // (c) slab write vs the add_scaled_rows chain, from identical plane states.
6557    let block_out = e.htod(&rand_vec(t * hidden))?;
6558    launch_hc_write_planes(e, &ptrs, &block_out, &all_b, hidden, t, streams)?;
6559    let mut expect: Vec<Vec<f32>> = Vec::with_capacity(streams);
6560    let all_host = e.dtoh(&all_b)?;
6561    let bo_host = e.dtoh(&block_out)?;
6562    for (s, base) in planes_host.iter().enumerate() {
6563        let mut rows = base.clone();
6564        for tok in 0..t {
6565            let g = all_host[s * t + tok];
6566            for d in 0..hidden {
6567                rows[tok * hidden + d] += bo_host[tok * hidden + d] * g;
6568            }
6569        }
6570        expect.push(rows);
6571    }
6572    for (s, plane) in planes.iter().enumerate() {
6573        check(
6574            &format!("write plane {s}"),
6575            &e.dtoh(plane)?,
6576            &expect[s],
6577            &mut worst,
6578        )?;
6579    }
6580    Ok(format!(
6581        "hc-micro real-geometry oracle: streams 4 hidden 2560 t 10, worst rel {worst:.3e} \
6582         over norm/inject/write vs the classic composition"
6583    ))
6584}
6585
6586/// REAL-GEOMETRY oracle for the perf-round-3 GDN kernels (the tiny plan cannot reach
6587/// either: hk 4 fails the step twin's warp guard, and the fused norm's win is only
6588/// meaningful at real widths). (a) `gdn_scan_step_f32` vs `gdn_scan_naive_f32` at t=1
6589/// on identical inputs and state copies — same per-element math, block-tree vs
6590/// sequential row sums, so tolerance-gated (1e-4 rel, worst reported); covers the
6591/// artifact geometry (nk 16, nv 48, hk/hv 128 — head sharing h%nk) and the minimum
6592/// hk=32 shape. (b) `rms_sigmul_f32` vs the rms_norm + sigmoid + mul chain it replaces
6593/// — asserted BIT-IDENTICAL (the kernel is rms_norm_f32-verbatim + sigmoid_f32 with no
6594/// contraction seam).
6595/// Block-list attention kernel oracle (long-context lane), real QSA geometry (hd 256,
6596/// 24/2 heads). Arm A: masked kernel vs block-list kernel over the SAME selections at
6597/// t_kv 4096 — BIT identity (the masked kernel's -1e30 entries contribute exact-0 terms
6598/// in the same ascending order; see the kernel comment). Arm B: t_kv 16384 — past the
6599/// masked kernel's smem bound, where only the block-list form runs — vs a HOST f32 twin
6600/// of the same phase order (expf vs libm exp differ in ULPs; tolerance class).
6601/// Selections come through the PRODUCTION renderers (`rowsel_to_mask`/`rowsel_positions`)
6602/// so the emission code is gated with the kernel.
6603pub fn gate_sdpa_blocklist(e: &Engine) -> Res<String> {
6604    let mut lcg = 0x51ee_7bad_u64;
6605    let mut next_f32 = move || -> f32 {
6606        lcg = lcg
6607            .wrapping_mul(6364136223846793005)
6608            .wrapping_add(1442695040888963407);
6609        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
6610    };
6611    let (hd, nh, nkv, t) = (256usize, 24usize, 2usize, 3usize);
6612    let block_size = 4usize;
6613    let scale = 1.0 / (hd as f32).sqrt();
6614    let mut bit_rows = 0usize;
6615    let mut worst_rel = 0.0f32;
6616    for (t_kv, vs_masked) in [(4096usize, true), (16384usize, false)] {
6617        let q_host: Vec<f32> = (0..t * nh * hd).map(|_| next_f32()).collect();
6618        let k_host: Vec<f32> = (0..t_kv * nkv * hd).map(|_| next_f32()).collect();
6619        let v_host: Vec<f32> = (0..t_kv * nkv * hd).map(|_| next_f32()).collect();
6620        // Per-row selections: row 0 full causal prefix; rows 1/2 scored-form block lists
6621        // (stride-3 / tail-heavy) with the always-visible incomplete tail.
6622        let sels: Vec<RowSel> = (0..t)
6623            .map(|qt| {
6624                let visible = t_kv - t + qt + 1;
6625                let complete = visible / block_size;
6626                // A full-prefix row (production: complete <= budget) only in the
6627                // 4096 case — its position list scales with `visible`, and the
6628                // 16384 full form would blow the 48 KB smem cap production never
6629                // approaches (full rows are <= 2052 positions there).
6630                if qt == 0 && vs_masked {
6631                    return RowSel {
6632                        full: true,
6633                        blocks: Vec::new(),
6634                        visible,
6635                    };
6636                }
6637                let stride = if qt == 1 { 3 } else { 7 };
6638                let blocks: Vec<u32> = (0..complete as u32)
6639                    .rev()
6640                    .step_by(stride)
6641                    .take(512)
6642                    .collect::<Vec<_>>()
6643                    .into_iter()
6644                    .rev()
6645                    .collect();
6646                RowSel {
6647                    full: false,
6648                    blocks,
6649                    visible,
6650                }
6651            })
6652            .collect();
6653        let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
6654        let q = e.htod(&q_host)?;
6655        let k = e.htod(&k_host)?;
6656        let v = e.htod(&v_host)?;
6657        let pos = e.htod_i32(&pos_flat)?;
6658        let meta_dev = e.htod_i32(&meta)?;
6659        let mut o_list = e.zeros(t * nh * hd)?;
6660        launch_sdpa_blocklist(
6661            e,
6662            &q,
6663            &k.slice(0..t_kv * nkv * hd),
6664            &v.slice(0..t_kv * nkv * hd),
6665            &mut o_list,
6666            &pos,
6667            &meta_dev,
6668            hd,
6669            nh,
6670            nkv,
6671            t,
6672            max_count,
6673            scale,
6674        )?;
6675        let ours = e.dtoh(&o_list)?;
6676        if vs_masked {
6677            let mask = rowsel_to_mask(&sels, block_size, t_kv);
6678            let mask_dev = e.htod_bytes(&mask)?;
6679            let mut o_mask = e.zeros(t * nh * hd)?;
6680            launch_sdpa_mask(
6681                e,
6682                &q,
6683                &k.slice(0..t_kv * nkv * hd),
6684                &v.slice(0..t_kv * nkv * hd),
6685                &mut o_mask,
6686                &mask_dev,
6687                hd,
6688                nh,
6689                nkv,
6690                t,
6691                t_kv,
6692                scale,
6693            )?;
6694            let masked = e.dtoh(&o_mask)?;
6695            for (i, (a, b)) in masked.iter().zip(ours.iter()).enumerate() {
6696                if a.to_bits() != b.to_bits() {
6697                    return Err(format!(
6698                        "sdpa_blocklist vs masked: bit mismatch at {i}: {a} vs {b} (t_kv {t_kv})"
6699                    )
6700                    .into());
6701                }
6702            }
6703            bit_rows = t * nh * hd;
6704        } else {
6705            // HOST twin, same phase order: per (row, head) dots ascending over the
6706            // selection, single-pass max/exp/normalize, weighted V ascending.
6707            for qt in 0..t {
6708                let off = meta[2 * qt] as usize;
6709                let count = meta[2 * qt + 1] as usize;
6710                for head in 0..nh {
6711                    let kvh = head / (nh / nkv);
6712                    let qrow = &q_host[(qt * nh + head) * hd..(qt * nh + head + 1) * hd];
6713                    let mut scores: Vec<f32> = (0..count)
6714                        .map(|i| {
6715                            let p = pos_flat[off + i] as usize;
6716                            let krow = &k_host[(p * nkv + kvh) * hd..(p * nkv + kvh + 1) * hd];
6717                            let mut acc = 0.0f32;
6718                            for d in 0..hd {
6719                                acc += qrow[d] * krow[d];
6720                            }
6721                            acc * scale
6722                        })
6723                        .collect();
6724                    let mx = scores.iter().copied().fold(-1e30f32, f32::max);
6725                    let mut sum = 0.0f32;
6726                    for s in scores.iter_mut() {
6727                        *s = (*s - mx).exp();
6728                        sum += *s;
6729                    }
6730                    let inv = 1.0 / sum;
6731                    for s in scores.iter_mut() {
6732                        *s *= inv;
6733                    }
6734                    for d in 0..hd {
6735                        let mut acc = 0.0f32;
6736                        for (i, s) in scores.iter().enumerate() {
6737                            let p = pos_flat[off + i] as usize;
6738                            acc += s * v_host[(p * nkv + kvh) * hd + d];
6739                        }
6740                        let got = ours[(qt * nh + head) * hd + d];
6741                        let rel = (got - acc).abs() / acc.abs().max(1e-3);
6742                        worst_rel = worst_rel.max(rel);
6743                        if rel > 1e-4 {
6744                            return Err(format!(
6745                                "sdpa_blocklist vs host twin: rel {rel} at row {qt} head {head} \
6746                                 dim {d} (t_kv {t_kv})"
6747                            )
6748                            .into());
6749                        }
6750                    }
6751                }
6752            }
6753        }
6754    }
6755    Ok(format!(
6756        "sdpa-blocklist oracle: BIT-IDENTICAL to the masked kernel over {bit_rows} values \
6757         (t_kv 4096, full+stride selections); past the mask bound (t_kv 16384) worst rel \
6758         {worst_rel:.3e} vs the host twin"
6759    ))
6760}
6761
6762/// kvq/idxq kernel oracles (KV-quant lane). Four pins, all BIT-exact:
6763/// (1) the append-quantize kernels vs the host quantize twins (q8_0 K rows, q5_1 V
6764///     rows) over random + adversarial blocks (zeros, half-ulp rounding ties, subnormal
6765///     scales, constant blocks) at real (512) and padded-tail (40) widths;
6766/// (2) the row-dequant kernel vs the host dequant twins on those bytes;
6767/// (3) the FUSED quantized block-list attention vs the composition
6768///     "q4e_kv_dequant_rows then sdpa_blocklist_f32" — the load-bearing oracle: it
6769///     proves in-kernel dequant reads the same f32 values the storage contract defines
6770///     (the qsa_index_score 1-ULP FMA lesson made both sides explicit-intrinsic);
6771/// (4) the indexer q8/bf16 device appenders vs the host cache twins (the idxcache
6772///     host/device interleave contract).
6773/// Caveat, stated: blocks mixing +0.0 and -0.0 are outside the pin (fminf/fmaxf zero
6774/// sign order is unspecified); projection outputs do not produce signed-zero ties.
6775pub fn gate_kvq_kernels(e: &Engine) -> Res<String> {
6776    let mut lcg = 0x6b76_715ee_du64; // "kvq"-seeded LCG
6777    let mut next_f32 = move || -> f32 {
6778        lcg = lcg
6779            .wrapping_mul(6364136223846793005)
6780            .wrapping_add(1442695040888963407);
6781        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
6782    };
6783    let mut report = Vec::new();
6784
6785    // ---- (1) + (2): quantize + dequant twins ----
6786    for &dim in &[512usize, 40usize] {
6787        let rows = 9usize;
6788        let mut host_rows_f: Vec<f32> = (0..rows * dim).map(|_| next_f32()).collect();
6789        // Adversarial rows: 0 = all zeros; 1 = constant block (d == 0 path for q5's
6790        // mx == mn); 2 = rounding ties (values at exact half steps of the block scale).
6791        for v in host_rows_f[0..dim].iter_mut() {
6792            *v = 0.0;
6793        }
6794        for v in host_rows_f[dim..2 * dim].iter_mut() {
6795            *v = 0.75;
6796        }
6797        for (i, v) in host_rows_f[2 * dim..3 * dim].iter_mut().enumerate() {
6798            // amax = 1.0 at lane 0; others sit at k*(1/127)*0.5 half-steps.
6799            *v = if i == 0 {
6800                1.0
6801            } else {
6802                (i as f32) * 0.5 / 127.0
6803            };
6804        }
6805        // Subnormal-scale row.
6806        for v in host_rows_f[3 * dim..4 * dim].iter_mut() {
6807            *v *= 1e-40;
6808        }
6809        let dev_rows = e.htod(&host_rows_f)?;
6810        let mut kq = e.alloc_u8(rows * q8_row_bytes(dim))?;
6811        let mut vq = e.alloc_u8(rows * q5_row_bytes(dim))?;
6812        launch_q4e_kv_append(e, &dev_rows, &dev_rows, &mut kq, &mut vq, 0, rows, dim)?;
6813        let kq_host = e.dtoh_u8(&kq)?;
6814        let vq_host = e.dtoh_u8(&vq)?;
6815        let mut k_twin = Vec::new();
6816        let mut v_twin = Vec::new();
6817        for r in 0..rows {
6818            host_quant_q8_row(&host_rows_f[r * dim..(r + 1) * dim], dim, &mut k_twin);
6819            host_quant_q5_row(&host_rows_f[r * dim..(r + 1) * dim], dim, &mut v_twin);
6820        }
6821        if kq_host != k_twin {
6822            let i = kq_host.iter().zip(&k_twin).position(|(a, b)| a != b);
6823            return Err(format!("kvq q8 quantize twin: byte mismatch at {i:?} (dim {dim})").into());
6824        }
6825        if vq_host != v_twin {
6826            let i = vq_host.iter().zip(&v_twin).position(|(a, b)| a != b);
6827            return Err(format!("kvq q5 quantize twin: byte mismatch at {i:?} (dim {dim})").into());
6828        }
6829        // Dequant twin.
6830        let mut kf = e.zeros(rows * dim)?;
6831        let mut vf = e.zeros(rows * dim)?;
6832        launch_q4e_kv_dequant_rows(e, &kq, &vq, &mut kf, &mut vf, 0, rows, dim)?;
6833        let kf_host = e.dtoh(&kf)?;
6834        let vf_host = e.dtoh(&vf)?;
6835        let mut kf_twin = Vec::new();
6836        let mut vf_twin = Vec::new();
6837        host_deq_q8_rows(&kq_host, 0, rows, dim, &mut kf_twin);
6838        host_deq_q5_rows(&vq_host, 0, rows, dim, &mut vf_twin);
6839        for (i, (a, b)) in kf_host.iter().zip(&kf_twin).enumerate() {
6840            if a.to_bits() != b.to_bits() {
6841                return Err(format!("kvq q8 dequant twin: bit mismatch at {i} (dim {dim})").into());
6842            }
6843        }
6844        for (i, (a, b)) in vf_host.iter().zip(&vf_twin).enumerate() {
6845            if a.to_bits() != b.to_bits() {
6846                return Err(format!("kvq q5 dequant twin: bit mismatch at {i} (dim {dim})").into());
6847            }
6848        }
6849        report.push(format!("quant+dequant twins dim {dim}: BYTE/BIT-IDENTICAL"));
6850    }
6851
6852    // ---- (3) fused quant attention vs the dequant-rows composition ----
6853    {
6854        let (hd, nh, nkv, t) = (256usize, 24usize, 2usize, 3usize);
6855        let kv_dim = nkv * hd;
6856        let block_size = 4usize;
6857        let scale = 1.0 / (hd as f32).sqrt();
6858        let t_kv = 4096usize;
6859        let q_host: Vec<f32> = (0..t * nh * hd).map(|_| next_f32()).collect();
6860        let k_host: Vec<f32> = (0..t_kv * kv_dim).map(|_| next_f32()).collect();
6861        let v_host: Vec<f32> = (0..t_kv * kv_dim).map(|_| next_f32()).collect();
6862        let k_rows = e.htod(&k_host)?;
6863        let v_rows = e.htod(&v_host)?;
6864        let mut kq = e.alloc_u8(t_kv * q8_row_bytes(kv_dim))?;
6865        let mut vq = e.alloc_u8(t_kv * q5_row_bytes(kv_dim))?;
6866        launch_q4e_kv_append(e, &k_rows, &v_rows, &mut kq, &mut vq, 0, t_kv, kv_dim)?;
6867        // Selections: one full-prefix row + two scored stride rows (the
6868        // gate_sdpa_blocklist shapes, bounded to the production smem class).
6869        let sels: Vec<RowSel> = (0..t)
6870            .map(|qt| {
6871                let visible = (t_kv - t + qt + 1).min(2052);
6872                if qt == 0 {
6873                    return RowSel {
6874                        full: true,
6875                        blocks: Vec::new(),
6876                        visible,
6877                    };
6878                }
6879                let complete = (t_kv - t + qt + 1) / block_size;
6880                let stride = if qt == 1 { 3 } else { 7 };
6881                let blocks: Vec<u32> = (0..complete as u32)
6882                    .rev()
6883                    .step_by(stride)
6884                    .take(512)
6885                    .collect::<Vec<_>>()
6886                    .into_iter()
6887                    .rev()
6888                    .collect();
6889                RowSel {
6890                    full: false,
6891                    blocks,
6892                    visible: t_kv - t + qt + 1,
6893                }
6894            })
6895            .collect();
6896        let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
6897        let q = e.htod(&q_host)?;
6898        let pos = e.htod_i32(&pos_flat)?;
6899        let meta_dev = e.htod_i32(&meta)?;
6900        let mut o_fused = e.zeros(t * nh * hd)?;
6901        launch_q4e_sdpa_blocklist_q8q5(
6902            e,
6903            &q,
6904            &kq,
6905            &vq,
6906            &mut o_fused,
6907            &pos,
6908            &meta_dev,
6909            hd,
6910            nh,
6911            nkv,
6912            t,
6913            max_count,
6914            scale,
6915        )?;
6916        let mut k_deq = e.zeros(t_kv * kv_dim)?;
6917        let mut v_deq = e.zeros(t_kv * kv_dim)?;
6918        launch_q4e_kv_dequant_rows(e, &kq, &vq, &mut k_deq, &mut v_deq, 0, t_kv, kv_dim)?;
6919        let mut o_comp = e.zeros(t * nh * hd)?;
6920        launch_sdpa_blocklist(
6921            e,
6922            &q,
6923            &k_deq.slice(0..t_kv * kv_dim),
6924            &v_deq.slice(0..t_kv * kv_dim),
6925            &mut o_comp,
6926            &pos,
6927            &meta_dev,
6928            hd,
6929            nh,
6930            nkv,
6931            t,
6932            max_count,
6933            scale,
6934        )?;
6935        let fused = e.dtoh(&o_fused)?;
6936        let comp = e.dtoh(&o_comp)?;
6937        for (i, (a, b)) in fused.iter().zip(&comp).enumerate() {
6938            if a.to_bits() != b.to_bits() {
6939                return Err(format!(
6940                    "kvq fused attention vs dequant composition: bit mismatch at {i}: {a} vs {b}"
6941                )
6942                .into());
6943            }
6944        }
6945        // ---- (3b) `kvhoist` vs the un-hoisted kernel, SAME real geometry ----
6946        // The hoist is a pure read-pattern change (fp16 K block scale loaded once per 32-element
6947        // block instead of once per element), so the bar is bit-identity and nothing weaker.
6948        //
6949        // This arm rides arm (3)'s geometry deliberately: hd=256 is EIGHT 32-element blocks per
6950        // head slice and nkv=2 means the second KV head starts at element 256, so the hoisted
6951        // loop's block walk and its `e0 = kv_head*head_dim` offset are both genuinely exercised.
6952        // At a tiny head_dim the loop would run ONE iteration and the per-block scale advance —
6953        // the only thing the seam changes — would never be taken. That is precisely the
6954        // tiny-green/real-broken shape this lane has been bitten by twice, so the arm is written
6955        // where it cannot happen rather than trusted to a comment.
6956        {
6957            let was = kv_hoist_on();
6958            set_kv_hoist(true);
6959            let mut o_hoist = e.zeros(t * nh * hd)?;
6960            let launched = launch_q4e_sdpa_blocklist_q8q5(
6961                e,
6962                &q,
6963                &kq,
6964                &vq,
6965                &mut o_hoist,
6966                &pos,
6967                &meta_dev,
6968                hd,
6969                nh,
6970                nkv,
6971                t,
6972                max_count,
6973                scale,
6974            );
6975            set_kv_hoist(was);
6976            launched?;
6977            let hoist = e.dtoh(&o_hoist)?;
6978            let mut worst: Option<(usize, f32, f32)> = None;
6979            for (i, (a, b)) in hoist.iter().zip(&fused).enumerate() {
6980                if a.to_bits() != b.to_bits() && worst.is_none() {
6981                    worst = Some((i, *a, *b));
6982                }
6983            }
6984            if let Some((i, a, b)) = worst {
6985                return Err(format!(
6986                    "kvhoist vs un-hoisted q8q5 blocklist: bit mismatch at {i}: {a} vs {b} \
6987                     (hd={hd} nh={nh} nkv={nkv} t={t} t_kv={t_kv} max_count={max_count})"
6988                )
6989                .into());
6990            }
6991            // A no-op arm would also compare equal. Prove the seam actually selected the other
6992            // kernel: `kv_hoist_on()` gates the `e.func` name, and an unknown name would have
6993            // failed the launch above rather than silently falling through — so a green compare
6994            // plus a completed launch under the armed seam is the engagement evidence. State the
6995            // count so a zero-value compare cannot pass as a pass.
6996            report.push(format!(
6997                "kvhoist vs un-hoisted q8q5 blocklist: BIT-IDENTICAL over {} values \
6998                 (real geometry hd={hd} nh={nh} nkv={nkv}, {} blocks/head slice, max_count={max_count})",
6999                t * nh * hd,
7000                hd / 32
7001            ));
7002        }
7003        report.push(format!(
7004            "fused q8q5 blocklist vs dequant+f32 composition: BIT-IDENTICAL over {} values",
7005            t * nh * hd
7006        ));
7007    }
7008
7009    // ---- (4) indexer appenders vs the host cache twins ----
7010    {
7011        let idx_dim = 128usize;
7012        let qk_width = 5 * idx_dim; // 4 query heads + 1 key head
7013        let rows = 7usize;
7014        let src_host: Vec<f32> = (0..rows * qk_width).map(|_| next_f32()).collect();
7015        let src = e.htod(&src_host)?;
7016        let q_off = 4 * idx_dim;
7017        // q8 arm.
7018        let mut dst_q8 = e.alloc_u8((rows + 2) * q8_row_bytes(idx_dim))?;
7019        launch_q4e_idx_append_q8(e, &src, &mut dst_q8, rows, idx_dim, qk_width, q_off, 2)?;
7020        let got = e.dtoh_u8(&dst_q8)?;
7021        let mut twin = vec![0u8; 2 * q8_row_bytes(idx_dim)];
7022        for r in 0..rows {
7023            host_quant_q8_row(
7024                &src_host[r * qk_width + q_off..(r + 1) * qk_width],
7025                idx_dim,
7026                &mut twin,
7027            );
7028        }
7029        if got[2 * q8_row_bytes(idx_dim)..] != twin[2 * q8_row_bytes(idx_dim)..] {
7030            return Err("idxq q8 append twin: byte mismatch".into());
7031        }
7032        // bf16 arm.
7033        let mut dst_bf = unsafe { e.gpu.stream().alloc::<u16>((rows + 2) * idx_dim)? };
7034        e.gpu.stream().memset_zeros(&mut dst_bf)?;
7035        launch_q4e_idx_append_bf16(e, &src, &mut dst_bf, rows, idx_dim, qk_width, q_off, 2)?;
7036        let got_bf: Vec<u16> = {
7037            let v = e
7038                .gpu
7039                .stream()
7040                .clone_dtoh(&dst_bf.slice(0..(rows + 2) * idx_dim))?;
7041            e.gpu.stream().synchronize()?;
7042            v
7043        };
7044        for r in 0..rows {
7045            for c in 0..idx_dim {
7046                let want = f32_to_bf16_rne(src_host[r * qk_width + q_off + c]);
7047                if got_bf[(2 + r) * idx_dim + c] != want {
7048                    return Err(format!("idxq bf16 append twin: mismatch row {r} col {c}").into());
7049                }
7050            }
7051        }
7052        report.push("idx q8/bf16 appenders vs host twins: BYTE-IDENTICAL".to_string());
7053    }
7054
7055    Ok(format!("kvq kernel oracles: {}", report.join("; ")))
7056}
7057
7058/// Device QSA index-scorer oracle at REAL indexer geometry (4 heads x 128, block 4):
7059/// `qsa_index_score_f32` vs the host twin's arithmetic, BIT for BIT, over a block count
7060/// past the real budget (so the scoring arm — not the structural fast path — is what
7061/// runs), plus the top-k SET equality that the selection actually depends on.
7062pub fn gate_qsa_index_score(e: &Engine) -> Res<String> {
7063    let mut lcg = 0xfeed_1234_u64;
7064    let mut next_f32 = move || -> f32 {
7065        lcg = lcg
7066            .wrapping_mul(6364136223846793005)
7067            .wrapping_add(1442695040888963407);
7068        (((lcg >> 33) as u32) % 4000) as f32 / 2000.0 - 1.0
7069    };
7070    let (heads, head_dim) = (4usize, 128usize);
7071    let scale = (head_dim as f32).sqrt();
7072    let budget = 512usize;
7073    let mut worst_rows = 0usize;
7074    for (rows, n_blocks) in [(1usize, 4096usize), (7, 1031)] {
7075        let q_host: Vec<f32> = (0..rows * heads * head_dim).map(|_| next_f32()).collect();
7076        let pooled_host: Vec<f32> = (0..n_blocks * head_dim).map(|_| next_f32()).collect();
7077        let q = e.htod(&q_host)?;
7078        let pooled = e.htod(&pooled_host)?;
7079        let mut scores_dev = e.uninit(rows * n_blocks)?;
7080        launch_qsa_index_score(
7081            e,
7082            &q,
7083            &pooled,
7084            &mut scores_dev,
7085            heads,
7086            head_dim,
7087            n_blocks,
7088            rows,
7089            scale,
7090        )?;
7091        let got = e.dtoh(&scores_dev)?;
7092        for row in 0..rows {
7093            let qr = &q_host[row * heads * head_dim..(row + 1) * heads * head_dim];
7094            let host = score_blocks(qr, &pooled_host, heads, head_dim, n_blocks, scale, 1);
7095            for (b, want) in host.iter().enumerate() {
7096                let g = got[row * n_blocks + b];
7097                if g.to_bits() != want.to_bits() {
7098                    return Err(format!(
7099                        "qsa_index_score: bit mismatch row {row} block {b}: {g} vs host {want}"
7100                    )
7101                    .into());
7102                }
7103            }
7104            let a = top_blocks_ascending(&host, budget, 1);
7105            let b = top_blocks_ascending(&got[row * n_blocks..(row + 1) * n_blocks], budget, 1);
7106            if a != b {
7107                return Err(format!("qsa_index_score: top-k set differs at row {row}").into());
7108            }
7109            worst_rows += 1;
7110        }
7111    }
7112    // ---- `poolT`: the dim-major plane, through the SAME host-twin bar ----
7113    // Validates the whole chain, not just the kernel: the transpose kernel writes the plane from
7114    // the row-major region on device, and the transposed score kernel reads it. Bit-identity to
7115    // the host twin (not merely to the row-major device kernel) is the bar, because the row-major
7116    // kernel is itself gated against the host above — comparing only device-to-device would let a
7117    // shared mistake pass twice.
7118    //
7119    // The case is chosen to catch the ONE mistake this layout invites: `cap_rows != n_blocks`.
7120    // The plane's pitch is the mirror's block CAPACITY, and the mirror grows to a power of two
7121    // while `n_blocks` is whatever the fill happens to be — so `cap_rows == n_blocks` is the
7122    // ABNORMAL state, and a kernel handed `n_blocks` as its pitch would read dim d of block b as
7123    // dim d of a different block for every d > 0. That is silent wrong values, and it would be
7124    // green in any gate where the two numbers happen to coincide. Here they deliberately do not
7125    // (1031 blocks in a 4096-block plane), and a second case pins the aligned edge.
7126    let mut pool_t_rows = 0usize;
7127    for (rows, n_blocks, cap_rows) in [(1usize, 1031usize, 4096usize), (5, 2048, 2048)] {
7128        let q_host: Vec<f32> = (0..rows * heads * head_dim).map(|_| next_f32()).collect();
7129        let pooled_host: Vec<f32> = (0..n_blocks * head_dim).map(|_| next_f32()).collect();
7130        let q = e.htod(&q_host)?;
7131        // The mirror as `indexer_select_rows` builds it: POOL_PLANES regions of cap_rows*head_dim,
7132        // the row-major rows H2D'd into the first, the plane filled by the transpose kernel.
7133        let mut mirror = e.zeros(cap_rows * head_dim * POOL_PLANES)?;
7134        {
7135            let mut view = mirror.slice_mut(0..n_blocks * head_dim);
7136            e.gpu.stream().memcpy_htod(&pooled_host, &mut view)?;
7137        }
7138        launch_qsa_pooled_transpose(e, &mut mirror, 0, n_blocks, head_dim, cap_rows)?;
7139        let was = pool_t_on();
7140        set_pool_t(true);
7141        let mut scores_dev = e.uninit(rows * n_blocks)?;
7142        let launched = launch_qsa_index_score(
7143            e,
7144            &q,
7145            &mirror,
7146            &mut scores_dev,
7147            heads,
7148            head_dim,
7149            n_blocks,
7150            rows,
7151            scale,
7152        );
7153        set_pool_t(was);
7154        launched?;
7155        let got = e.dtoh(&scores_dev)?;
7156        for row in 0..rows {
7157            let qr = &q_host[row * heads * head_dim..(row + 1) * heads * head_dim];
7158            let host = score_blocks(qr, &pooled_host, heads, head_dim, n_blocks, scale, 1);
7159            for (b, want) in host.iter().enumerate() {
7160                let g = got[row * n_blocks + b];
7161                if g.to_bits() != want.to_bits() {
7162                    return Err(format!(
7163                        "poolT qsa_index_score_f32_t: bit mismatch row {row} block {b}: \
7164                         {g} vs host {want} (n_blocks={n_blocks} cap_rows={cap_rows})"
7165                    )
7166                    .into());
7167                }
7168            }
7169            if top_blocks_ascending(&host, budget, 1)
7170                != top_blocks_ascending(&got[row * n_blocks..(row + 1) * n_blocks], budget, 1)
7171            {
7172                return Err(format!(
7173                    "poolT qsa_index_score_f32_t: top-{budget} set differs at row {row} \
7174                     (n_blocks={n_blocks} cap_rows={cap_rows})"
7175                )
7176                .into());
7177            }
7178            pool_t_rows += 1;
7179        }
7180    }
7181    Ok(format!(
7182        "qsa-index-score oracle: device scores BIT-IDENTICAL to the host twin over \
7183         {worst_rows} rows (4096 + 1031 blocks, real 4x128 geometry) and top-512 sets equal; \
7184         poolT dim-major plane (transpose + transposed kernel) BIT-IDENTICAL to the SAME host \
7185         twin over {pool_t_rows} rows, incl. the pitch-trap case cap_rows=4096 != n_blocks=1031"
7186    ))
7187}
7188
7189/// PLE n-gram id CACHE oracle (262k perf lane, `plecache`): `host_ngram_ids_cached` vs the
7190/// full `host_ngram_ids` twin, ids compared EXACTLY (they are table row indices — one wrong
7191/// id gathers a different embedding row and the output is fluent and wrong, so there is no
7192/// tolerance to have). Host-only, so it costs nothing and runs on every gate invocation.
7193///
7194/// The cases are the ones a cache gets wrong, not the ones it gets right:
7195/// - **one-token-at-a-time growth** (the decode shape) and **chunked growth** (the prefill
7196///   shape) over the same sequence, interleaved lengths, against a fresh full recompute at
7197///   every length.
7198/// - **EOS inside the sequence**: `shift_right_ignore_eos` resets its segment at an eos, and
7199///   the running `last_eos_inclusive` is the one piece of cross-token state the incremental
7200///   form has to carry. A cache that ignored it would be green on eos-free text.
7201/// - **rewind to a DIVERGING prefix** (the spec-reject shape): extend, then ask for a
7202///   sequence that shares only a prefix. The cache must truncate at the divergence, not at
7203///   the length — a length-only check keeps another sequence's hashes and produces fluent
7204///   output from the wrong rows, which is invisible.
7205/// - **a SHORTER unrelated sequence in the same cache** (state reuse).
7206/// - **eos as the very first token** and **an all-eos sequence** (segment_start edges).
7207pub fn gate_ple_ngram_cache() -> Res<String> {
7208    // Real artifact geometry: max_ngram 3, 16 heads (8 per ngram size), per-head vocab.
7209    let max_ngram = 3usize;
7210    let heads_per_ngram = 8usize;
7211    let total_heads = (max_ngram - 1) * heads_per_ngram;
7212    let multipliers: Vec<i64> = vec![
7213        0x2545_F491_4F6C_DD1D,
7214        0x9E37_79B9_7F4A_7C15u64 as i64,
7215        0x1234_5678_9ABC_DEF1,
7216    ];
7217    let sizes: Vec<i64> = (0..total_heads)
7218        .map(|i| 2_500_012_160 - (i as i64) * 7)
7219        .collect();
7220    let offsets: Vec<i64> = (0..total_heads)
7221        .map(|i| (i as i64) * 2_500_012_160)
7222        .collect();
7223    let eos = 248_046u32;
7224    let full = |ids: &[u32]| -> Vec<i64> {
7225        host_ngram_ids(
7226            ids,
7227            &multipliers,
7228            &sizes,
7229            &offsets,
7230            max_ngram,
7231            heads_per_ngram,
7232            eos,
7233        )
7234    };
7235    let mut lcg = 0x0be1_10ca_u64;
7236    let mut next_tok = move || -> u32 {
7237        lcg = lcg
7238            .wrapping_mul(6364136223846793005)
7239            .wrapping_add(1442695040888963407);
7240        ((lcg >> 33) as u32) % 250_000
7241    };
7242    let mut checks = 0usize;
7243    let mut run = |label: &str, steps: Vec<Vec<u32>>| -> Res<usize> {
7244        // `steps` are cumulative sequences fed to ONE cache, in order.
7245        let (mut ci, mut ch, mut ce) = (Vec::new(), Vec::new(), -1i64);
7246        let mut n = 0usize;
7247        for seq in &steps {
7248            host_ngram_ids_cached(
7249                &mut ci,
7250                &mut ch,
7251                &mut ce,
7252                seq,
7253                &multipliers,
7254                &sizes,
7255                &offsets,
7256                max_ngram,
7257                heads_per_ngram,
7258                eos,
7259            );
7260            let want = full(seq);
7261            if ci.len() != want.len() {
7262                return Err(format!(
7263                    "plecache oracle {label}: cache has {} ids, twin {} at len {}",
7264                    ci.len(),
7265                    want.len(),
7266                    seq.len()
7267                )
7268                .into());
7269            }
7270            if let Some(i) = ci.iter().zip(&want).position(|(a, b)| a != b) {
7271                return Err(format!(
7272                    "plecache oracle {label}: id {i} differs at len {} (token {}, head {}): \
7273                     cache {} vs twin {}",
7274                    seq.len(),
7275                    i / total_heads,
7276                    i % total_heads,
7277                    ci[i],
7278                    want[i]
7279                )
7280                .into());
7281            }
7282            n += seq.len();
7283        }
7284        Ok(n)
7285    };
7286    // 1. Decode shape: grow one token at a time, eos-free.
7287    {
7288        let base: Vec<u32> = (0..200).map(|_| next_tok()).collect();
7289        let steps: Vec<Vec<u32>> = (1..=base.len()).map(|n| base[..n].to_vec()).collect();
7290        checks += run("decode-growth", steps)?;
7291    }
7292    // 2. Prefill shape: chunked growth with ragged chunk sizes.
7293    {
7294        let base: Vec<u32> = (0..600).map(|_| next_tok()).collect();
7295        let mut steps = Vec::new();
7296        let mut n = 0usize;
7297        for step in [7usize, 1, 64, 3, 128, 2, 200, 195] {
7298            n = (n + step).min(base.len());
7299            steps.push(base[..n].to_vec());
7300        }
7301        checks += run("prefill-chunks", steps)?;
7302    }
7303    // 3. EOS inside the sequence (segment resets), incl. adjacent eos and a trailing eos.
7304    {
7305        let mut base: Vec<u32> = (0..300).map(|_| next_tok()).collect();
7306        for p in [0usize, 1, 2, 37, 38, 100, 101, 102, 299] {
7307            base[p] = eos;
7308        }
7309        let steps: Vec<Vec<u32>> = (1..=base.len()).map(|n| base[..n].to_vec()).collect();
7310        checks += run("eos-segments", steps)?;
7311    }
7312    // 4. All-eos: every position resets its own segment.
7313    {
7314        let base: Vec<u32> = vec![eos; 40];
7315        let steps: Vec<Vec<u32>> = (1..=base.len()).map(|n| base[..n].to_vec()).collect();
7316        checks += run("all-eos", steps)?;
7317    }
7318    // 5. Rewind to a DIVERGING prefix, repeatedly, then past the old length.
7319    {
7320        let a: Vec<u32> = (0..300).map(|_| next_tok()).collect();
7321        let mut b = a.clone();
7322        b[150] = a[150].wrapping_add(1) % 250_000;
7323        let mut c = b.clone();
7324        c[7] = b[7].wrapping_add(3) % 250_000;
7325        let mut d = c.clone();
7326        d.truncate(9);
7327        d.extend((0..100).map(|_| next_tok()));
7328        checks += run(
7329            "rewind-divergent",
7330            vec![
7331                a.clone(),
7332                a[..151].to_vec(),
7333                b.clone(),
7334                b[..8].to_vec(),
7335                c.clone(),
7336                d.clone(),
7337                a.clone(),
7338            ],
7339        )?;
7340    }
7341    // 6. A shorter unrelated sequence in the same cache (state reuse), and back up again.
7342    {
7343        let a: Vec<u32> = (0..250).map(|_| next_tok()).collect();
7344        let mut s: Vec<u32> = (0..11).map(|_| next_tok()).collect();
7345        s[0] = eos;
7346        checks += run("state-reuse", vec![a.clone(), s.clone(), a.clone(), s])?;
7347    }
7348    Ok(format!(
7349        "plecache oracle: incremental n-gram ids EXACT vs the full host_ngram_ids twin over \
7350         {checks} cumulative-sequence comparisons across 6 case families (decode one-at-a-time \
7351         growth, ragged prefill chunks, eos segment resets incl. adjacent + leading + trailing \
7352         eos, all-eos, repeated rewinds to DIVERGING prefixes, and shorter-unrelated-sequence \
7353         state reuse)"
7354    ))
7355}
7356
7357/// SEAM TABLE oracle (host-only, 262k host-lever lane): every `MEMRA_Q4E_SEAMS` name maps to its
7358/// OWN switch, `set_seam` and `seam_state` agree, and arming one seam changes NOTHING else.
7359///
7360/// This exists because the name table was refactored out of `apply_env_seams` into `set_seam` so
7361/// a measurement harness could flip a seam between timed rounds, and three agents add arms to it
7362/// concurrently. The failure mode of a mechanical refactor like that is not a crash: it is one
7363/// arm wired to a neighbour's switch, which arms the wrong seam and produces a fully fluent,
7364/// fully green run measuring something other than what the receipt claims. A copy-paste arm that
7365/// duplicates the line above it is exactly what a per-name distinctness check catches and what
7366/// reading the diff does not.
7367///
7368/// The strong assertion is the CROSS one: for each name, snapshot every other seam's state, flip
7369/// this one, and require that every other state is unchanged. That is what makes it a wiring
7370/// test rather than a smoke test — a table where two names share a switch passes "set then read
7371/// it back" and fails this.
7372pub fn gate_seam_table() -> Res<String> {
7373    // Derived from `seam_names()` — the engine's own list — so adding a seam extends this gate
7374    // automatically instead of silently escaping it. The three-valued names (`idxq`, `longatt`)
7375    // have no boolean `seam_state` and are filtered out here, but they are still required below
7376    // to be ACCEPTED by both entry points.
7377    let all: &[&str] = seam_names();
7378    let boolean: Vec<&str> = all
7379        .iter()
7380        .copied()
7381        .filter(|n| seam_state(n).is_some())
7382        .collect();
7383    // Non-vacuity, and it has to be able to FAIL: a collapsed list would make every assertion
7384    // below pass over nothing. Both bounds are real — the table carries 20+ boolean seams today,
7385    // and at least the two three-valued ones (`idxq`, `longatt`) must be present and filtered
7386    // out — so a list that lost either class trips here instead of reporting a green over a stub.
7387    if boolean.len() < 20 || all.len() < boolean.len() + 2 {
7388        return Err(format!(
7389            "seam-table oracle: refusing to report on {} boolean names out of {} total — the \
7390             seam list collapsed, so every assertion below would be vacuous",
7391            boolean.len(),
7392            all.len()
7393        )
7394        .into());
7395    }
7396    let names: &[&str] = &boolean;
7397    let snapshot = || -> Res<Vec<bool>> {
7398        names
7399            .iter()
7400            .map(|n| {
7401                seam_state(n).ok_or_else(|| {
7402                    Box::<dyn std::error::Error>::from(format!(
7403                        "seam-table oracle: seam_state({n:?}) is None — the name is in set_seam \
7404                         but not in seam_state, so save/restore around a measurement would \
7405                         silently not restore it"
7406                    ))
7407                })
7408            })
7409            .collect()
7410    };
7411    let restore = |v: &[bool]| {
7412        for (n, &b) in names.iter().zip(v) {
7413            set_seam(n, b, None);
7414        }
7415    };
7416    let entry = snapshot()?;
7417    let mut checks = 0usize;
7418    for (i, name) in names.iter().enumerate() {
7419        for &want in &[true, false, true] {
7420            let before = snapshot()?;
7421            if !set_seam(name, want, None) {
7422                restore(&entry);
7423                return Err(format!("seam-table oracle: set_seam({name:?}) refused").into());
7424            }
7425            let after = snapshot()?;
7426            if after[i] != want {
7427                restore(&entry);
7428                return Err(format!(
7429                    "seam-table oracle: set_seam({name:?}, {want}) then seam_state read {} — the \
7430                     two tables disagree on this name",
7431                    after[i]
7432                )
7433                .into());
7434            }
7435            // THE CROSS-CHECK, and the reason this is a wiring test rather than a smoke test: a
7436            // copy-paste arm wired to a neighbour's switch passes "set it then read it back" and
7437            // fails only here.
7438            for (j, other) in names.iter().enumerate() {
7439                if j != i && after[j] != before[j] {
7440                    restore(&entry);
7441                    return Err(format!(
7442                        "seam-table oracle: arming {name:?} also changed {other:?} ({} -> {}) — \
7443                         two names share one switch",
7444                        before[j], after[j]
7445                    )
7446                    .into());
7447                }
7448            }
7449            checks += 1;
7450        }
7451    }
7452    // Every name in the engine's own list — including the three-valued ones — must be accepted by
7453    // both entry points, or `apply_env_seams` would silently ignore a documented seam and the
7454    // run would measure the default while its receipt named the seam.
7455    for name in all {
7456        if !seam_exists(name) {
7457            restore(&entry);
7458            return Err(format!(
7459                "seam-table oracle: seam_names() lists {name:?} but seam_exists refuses it"
7460            )
7461            .into());
7462        }
7463        if !set_seam(name, seam_state(name).unwrap_or(false), None) {
7464            restore(&entry);
7465            return Err(format!(
7466                "seam-table oracle: seam_names() lists {name:?} but set_seam refuses it"
7467            )
7468            .into());
7469        }
7470    }
7471    // An unknown name must be refused by BOTH entry points, not silently accepted.
7472    if seam_exists("definitely-not-a-seam") || set_seam("definitely-not-a-seam", true, None) {
7473        restore(&entry);
7474        return Err("seam-table oracle: an unknown seam name was accepted".into());
7475    }
7476    // And `seam_exists` must apply NOTHING — the property the interleaved-A/B harness relies on
7477    // when it validates a seam name before a 25-80 minute prefill begins.
7478    let before = snapshot()?;
7479    for name in all {
7480        let _ = seam_exists(name);
7481    }
7482    if snapshot()? != before {
7483        restore(&entry);
7484        return Err("seam-table oracle: seam_exists mutated a seam (it must be name-only)".into());
7485    }
7486    restore(&entry);
7487    if snapshot()? != entry {
7488        return Err("seam-table oracle: the gate did not restore the entry state".into());
7489    }
7490    Ok(format!(
7491        "seam-table oracle: {} boolean seam names of {} total, {checks} set/read cycles, each \
7492         verified to change its OWN state and NO other (the cross-check that catches an arm \
7493         wired to a neighbour's switch), every listed name accepted by both entry points, \
7494         unknown names refused by both, seam_exists proven side-effect-free, entry state restored",
7495        names.len(),
7496        all.len()
7497    ))
7498}
7499
7500/// Device QSA indexer top-k SELECTION oracle (262k perf lane): `qsa_index_topk_u32` vs
7501/// `top_blocks_ascending` over the SAME score slab. Contract: the selected block ids AND
7502/// their emitted (ascending) order are EXACT — hard fail on any difference, no tolerance,
7503/// because a differing selection changes which KV rows the attention reads.
7504///
7505/// Geometry is REAL, not tiny: budget 512 (the shipped `budget_blocks`) at block counts up
7506/// to **65,536 — the 262,144-token target window's `fill/4`** — plus non-multiple counts
7507/// and RAGGED batches where each row reads its own prefix of a wider slab, which is the
7508/// exact shape the sub-batched caller produces. The tiny-green/real-broken trap has bitten
7509/// this lane twice; a budget-2 fixture would pass a kernel that cannot address 2^16 blocks.
7510///
7511/// Tie batteries a random draw cannot produce, and they are the point rather than an edge
7512/// case — the pinned rule is score desc then block index ASC:
7513/// - **all-zero**: every score +0.0. The whole selection is decided by the index tiebreak,
7514///   and this class is STRUCTURAL here (the scores are a relu-sum, so a deep row really
7515///   does carry long runs of exact +0.0). A tie-blind kernel is green everywhere else and
7516///   silently wrong here.
7517/// - **duplicate group straddling the budget boundary**: more equal scores than remaining
7518///   slots, so the boundary itself is resolved by index.
7519/// - **signed zeros / subnormals / negative / NaN**: outside the reachable score domain
7520///   (the caller's scores are >= +0.0), but the kernel's key is `f32::total_cmp` verbatim
7521///   over the whole domain, so the oracle proves that rather than assuming the domain.
7522pub fn gate_qsa_index_topk(e: &Engine) -> Res<String> {
7523    let budget = 512usize;
7524    let mut lcg = 0x1d5e_10ca_u64;
7525    let mut rows_checked = 0usize;
7526    let mut deepest = 0usize;
7527    // (label, per-row block counts, slab stride, score generator)
7528    let mut cases: Vec<(String, Vec<usize>, usize, Vec<f32>)> = Vec::new();
7529    let mut next_f32 = move || -> f32 {
7530        lcg = lcg
7531            .wrapping_mul(6364136223846793005)
7532            .wrapping_add(1442695040888963407);
7533        // Relu-sum scores are >= 0 with a heavy mass at exactly +0.0 — draw that shape.
7534        let r = ((lcg >> 33) as u32) % 1000;
7535        if r < 250 { 0.0 } else { (r as f32) / 250.0 }
7536    };
7537    for (label, counts) in [
7538        ("real-262k-depth", vec![65_536usize]),
7539        ("real-131k-depth", vec![32_768usize, 32_768]),
7540        ("shallow", vec![513usize, 1_031, 4_096]),
7541        ("ragged-batch", vec![2_049usize, 8_191, 65_536, 4_097]),
7542    ] {
7543        let stride = *counts.iter().max().unwrap();
7544        let slab: Vec<f32> = (0..counts.len() * stride).map(|_| next_f32()).collect();
7545        cases.push((label.to_string(), counts, stride, slab));
7546    }
7547    // all-zero: index tiebreak alone decides the whole selection.
7548    cases.push((
7549        "all-zero".into(),
7550        vec![65_536usize],
7551        65_536,
7552        vec![0.0f32; 65_536],
7553    ));
7554    // duplicate group straddling the boundary: 600 equal scores for the last 500 slots.
7555    {
7556        let n = 4_096usize;
7557        let mut v = vec![0.0f32; n];
7558        for (i, slot) in v.iter_mut().enumerate() {
7559            *slot = if i < 12 {
7560                100.0 - i as f32
7561            } else if i % 7 == 0 {
7562                2.5 // ~585 exact duplicates, straddling slot 512
7563            } else {
7564                (i % 3) as f32 * 0.25
7565            };
7566        }
7567        cases.push(("dup-straddle".into(), vec![n], n, v));
7568    }
7569    // Signed zeros, subnormals, negatives and NaN: the total_cmp domain, not the score
7570    // domain. total_cmp orders -0.0 below +0.0 and every NaN by its sign bit.
7571    {
7572        let n = 2_048usize;
7573        let mut v = vec![0.0f32; n];
7574        for (i, slot) in v.iter_mut().enumerate() {
7575            *slot = match i % 8 {
7576                0 => 0.0,
7577                1 => -0.0,
7578                2 => f32::from_bits(1),  // smallest positive subnormal
7579                3 => -f32::from_bits(1), // smallest negative subnormal
7580                4 => -(i as f32) * 0.5,
7581                5 => f32::NAN,
7582                6 => -f32::NAN,
7583                _ => (i % 5) as f32,
7584            };
7585        }
7586        cases.push(("total-cmp-domain".into(), vec![n], n, v));
7587    }
7588    for (label, counts, stride, slab) in &cases {
7589        let scores = e.htod(slab)?;
7590        let picked = launch_qsa_index_topk(e, &scores, counts, *stride, budget)?;
7591        if picked.len() != counts.len() {
7592            return Err(format!("idxsel oracle {label}: {} rows back", picked.len()).into());
7593        }
7594        for (r, &complete) in counts.iter().enumerate() {
7595            let row = &slab[r * *stride..r * *stride + complete];
7596            let twin = top_blocks_ascending(row, budget, 1);
7597            if twin != picked[r] {
7598                let first = twin
7599                    .iter()
7600                    .zip(picked[r].iter())
7601                    .position(|(a, b)| a != b)
7602                    .unwrap_or(twin.len().min(picked[r].len()));
7603                return Err(format!(
7604                    "idxsel oracle {label}: selection differs at row {r} (blocks {complete}), \
7605                     first differing slot {first}: host {:?} vs device {:?}",
7606                    twin.get(first),
7607                    picked[r].get(first)
7608                )
7609                .into());
7610            }
7611            rows_checked += 1;
7612            deepest = deepest.max(complete);
7613        }
7614    }
7615    Ok(format!(
7616        "qsa-index-topk oracle: device selection ids + ASCENDING order EXACT vs \
7617         top_blocks_ascending over {rows_checked} rows / {} cases at budget {budget}, \
7618         deepest {deepest} blocks (= the 262,144-token window), incl. the all-zero, \
7619         boundary-straddling-duplicate and total_cmp-domain (signed zero / subnormal / \
7620         negative / NaN) tie classes",
7621        cases.len()
7622    ))
7623}
7624
7625/// Device-router oracle at REAL geometry (devtwin lane): `qwen4exp_route_topk_f32` vs
7626/// `host_route_softmax_topk` on the SAME logits. Contract: the selection (ids AND their
7627/// emitted order — the combine reads slots sequentially) is EXACT, hard fail on any
7628/// mismatch; weights within a documented ULP bound (exp is the one op not bit-pinned to
7629/// host libm — kernel doc), worst observed printed in the receipt. Rows include the tie
7630/// batteries a random draw cannot produce: duplicate-logit groups STRADDLING the top-k
7631/// boundary (weight ties resolve by index — the rule a logits-ordered top-k would get
7632/// wrong), an all-equal row, and underflow rows (subnormal/zero weight ties). The renorm
7633/// denominator floor is unbindable on softmax geometry (top-k sum >= k/experts — see
7634/// ROUTE_DENOM_FLOOR) so it carries no arm; the twin computes the same fmaxf.
7635pub fn gate_route_kernel(e: &Engine) -> Res<String> {
7636    let mut lcg = 0x00de_7710_u64;
7637    let mut next_f32 = move || -> f32 {
7638        lcg = lcg
7639            .wrapping_mul(6364136223846793005)
7640            .wrapping_add(1442695040888963407);
7641        (((lcg >> 33) as u32) % 8000) as f32 / 200.0 - 20.0 // router-logit-scale [-20, 20)
7642    };
7643    const ULP_BOUND: u32 = 2;
7644    let mut worst_ulp: u32 = 0;
7645    let mut rows_checked = 0usize;
7646    let run = |e: &Engine,
7647               label: &str,
7648               logits_host: &[f32],
7649               experts: usize,
7650               selected: usize,
7651               rows: usize,
7652               worst_ulp: &mut u32|
7653     -> Res<()> {
7654        let logits = e.htod(logits_host)?;
7655        let mut sel = e.alloc_uninit::<i32>(rows * selected)?;
7656        let mut w = e.uninit(rows * selected)?;
7657        let mut tok = e.alloc_uninit::<i32>(rows * selected)?;
7658        launch_route_topk(
7659            e,
7660            &logits,
7661            &mut sel,
7662            &mut w,
7663            Some((&mut tok, 3)),
7664            experts,
7665            selected,
7666            rows,
7667        )?;
7668        let sel_h = e.gpu.stream().clone_dtoh(&sel.slice(0..rows * selected))?;
7669        let w_h = e.dtoh(&w)?;
7670        let tok_h = e.gpu.stream().clone_dtoh(&tok.slice(0..rows * selected))?;
7671        let k = selected.min(experts);
7672        for row in 0..rows {
7673            let twin =
7674                host_route_softmax_topk(&logits_host[row * experts..(row + 1) * experts], selected);
7675            if twin.len() != k {
7676                return Err(format!("route oracle {label}: host twin width {}", twin.len()).into());
7677            }
7678            for (j, &(idx, wt)) in twin.iter().enumerate() {
7679                let ds = sel_h[row * selected + j];
7680                let dw = w_h[row * selected + j];
7681                if ds != idx as i32 {
7682                    return Err(format!(
7683                        "route oracle {label}: selection mismatch row {row} slot {j}: \
7684                         device {ds} vs host {idx}"
7685                    )
7686                    .into());
7687                }
7688                let ulp = (dw.to_bits() as i64 - wt.to_bits() as i64).unsigned_abs();
7689                let ulp = u32::try_from(ulp).unwrap_or(u32::MAX);
7690                if ulp > ULP_BOUND {
7691                    return Err(format!(
7692                        "route oracle {label}: weight ULP {ulp} > {ULP_BOUND} at row {row} \
7693                         slot {j}: device {dw:e} vs host {wt:e}"
7694                    )
7695                    .into());
7696                }
7697                *worst_ulp = (*worst_ulp).max(ulp);
7698                if tok_h[row * selected + j] != (3 + row) as i32 {
7699                    return Err(format!(
7700                        "route oracle {label}: tok map wrong at row {row} slot {j}"
7701                    )
7702                    .into());
7703                }
7704            }
7705        }
7706        Ok(())
7707    };
7708    // Real geometry, random router-scale logits, batched rows (the verify shape).
7709    let (experts, selected) = (512usize, 10usize);
7710    for rows in [1usize, 6, 16] {
7711        let logits: Vec<f32> = (0..rows * experts).map(|_| next_f32()).collect();
7712        run(e, "real", &logits, experts, selected, rows, &mut worst_ulp)?;
7713        rows_checked += rows;
7714    }
7715    // Tie batteries (single rows).
7716    let mut tie_rows: Vec<(String, Vec<f32>)> = Vec::new();
7717    {
7718        // A 12-wide duplicate group straddling the top-10 boundary at positions 4..16:
7719        // host keeps the six lowest indices of the group after the four strict leaders.
7720        let mut v: Vec<f32> = (0..experts).map(|i| -30.0 - (i as f32) * 0.01).collect();
7721        for (rank, slot) in [40usize, 7, 300, 11].iter().enumerate() {
7722            v[*slot] = 10.0 - rank as f32;
7723        }
7724        for slot in [500usize, 3, 77, 210, 8, 401, 129, 64, 255, 380, 17, 450] {
7725            v[slot] = 2.5;
7726        }
7727        tie_rows.push(("dup-straddle".into(), v));
7728        // All-equal: the selection is indices 0..k by the tie rule alone.
7729        tie_rows.push(("all-equal".into(), vec![0.125f32; experts]));
7730        // Underflow: one dominant logit, the rest deep negative — weights tie at
7731        // 0.0/subnormal and the boundary resolves by index among bit-equal weights.
7732        let mut v = vec![-200.0f32; experts];
7733        v[100] = 5.0;
7734        for (i, slot) in [479usize, 2, 33].iter().enumerate() {
7735            v[*slot] = -80.0 - i as f32; // subnormal-weight class
7736        }
7737        tie_rows.push(("underflow".into(), v));
7738    }
7739    for (label, v) in &tie_rows {
7740        run(e, label, v, experts, selected, 1, &mut worst_ulp)?;
7741        rows_checked += 1;
7742    }
7743    // Off-real geometry (the envelope's edges): small expert counts, selected == experts.
7744    for (ex, se) in [(64usize, 4usize), (16, 16), (128, 32)] {
7745        let logits: Vec<f32> = (0..3 * ex).map(|_| next_f32()).collect();
7746        run(e, "geom", &logits, ex, se, 3, &mut worst_ulp)?;
7747        rows_checked += 3;
7748    }
7749    Ok(format!(
7750        "route oracle: device selection ids+order EXACT vs host twin over {rows_checked} rows \
7751         (real 512/10 + tie straddle/all-equal/underflow + geometry edges), worst weight \
7752         ULP {worst_ulp} (bound {ULP_BOUND}), tok map exact"
7753    ))
7754}
7755
7756pub fn gate_gdn_step_kernels(e: &Engine) -> Res<String> {
7757    let mut lcg = 0x0bad_cafe_u64;
7758    let mut next_f32 = move || -> f32 {
7759        lcg = lcg
7760            .wrapping_mul(6364136223846793005)
7761            .wrapping_add(1442695040888963407);
7762        (((lcg >> 33) as u32) % 2000) as f32 / 1000.0 - 1.0
7763    };
7764    let mut worst = 0.0f32;
7765    for (nk, nv, hk, hv) in [(16usize, 48usize, 128usize, 128usize), (2, 4, 32, 8)] {
7766        let conv_dim = 2 * nk * hk + nv * hv;
7767        let qkv_host: Vec<f32> = (0..conv_dim).map(|_| next_f32()).collect();
7768        let g_log_host: Vec<f32> = (0..nv).map(|_| next_f32().abs() * -2.0).collect();
7769        let beta_host: Vec<f32> = (0..nv).map(|_| next_f32()).collect();
7770        let state_host: Vec<f32> = (0..nv * hv * hk).map(|_| next_f32()).collect();
7771        let qkv = e.htod(&qkv_host)?;
7772        let g_log = e.htod(&g_log_host)?;
7773        let beta = e.htod(&beta_host)?;
7774        let scale = 1.0 / (hk as f32).sqrt();
7775        let eps = 1e-6f32;
7776        let mut state_a = e.htod(&state_host)?;
7777        let mut o_a = e.zeros(nv * hv)?;
7778        launch_gdn_scan(
7779            e,
7780            &qkv,
7781            &g_log,
7782            &beta,
7783            &mut state_a,
7784            &mut o_a,
7785            nk,
7786            nv,
7787            hk,
7788            hv,
7789            1,
7790            scale,
7791            eps,
7792        )?;
7793        let mut state_b = e.htod(&state_host)?;
7794        let mut o_b = e.zeros(nv * hv)?;
7795        launch_gdn_scan_step(
7796            e,
7797            &qkv,
7798            &g_log,
7799            &beta,
7800            &mut state_b,
7801            &mut o_b,
7802            nk,
7803            nv,
7804            hk,
7805            hv,
7806            scale,
7807            eps,
7808        )?;
7809        for (name, reference, candidate) in [
7810            ("o", e.dtoh(&o_a)?, e.dtoh(&o_b)?),
7811            ("state", e.dtoh(&state_a)?, e.dtoh(&state_b)?),
7812        ] {
7813            for (i, (&r, &c)) in reference.iter().zip(&candidate).enumerate() {
7814                let rel = (r - c).abs() / r.abs().max(1.0);
7815                if rel > worst {
7816                    worst = rel;
7817                }
7818                if rel > 1e-4 {
7819                    return Err(format!(
7820                        "gdn-step oracle: nk{nk}/nv{nv}/hk{hk}/hv{hv} {name} idx {i}: \
7821                         naive {r} step {c} (rel {rel:.3e})"
7822                    )
7823                    .into());
7824                }
7825            }
7826        }
7827    }
7828    // (b) fused norm+gate bit-identity at the artifact norm shape (48 rows of 128).
7829    let (rows, cols) = (48usize, 128usize);
7830    let x = e.htod(&(0..rows * cols).map(|_| next_f32()).collect::<Vec<_>>())?;
7831    let w = e.htod(&(0..cols).map(|_| next_f32()).collect::<Vec<_>>())?;
7832    let z = e.htod(&(0..rows * cols).map(|_| next_f32()).collect::<Vec<_>>())?;
7833    let eps = 1e-6f32;
7834    let mut normed = e.zeros(rows * cols)?;
7835    e.rms_norm(&x, &w, &mut normed, cols, rows, eps)?;
7836    let mut sg = e.zeros(rows * cols)?;
7837    e.sigmoid(&z, &mut sg, rows * cols)?;
7838    let mut chain = e.zeros(rows * cols)?;
7839    e.mul(&normed, &sg, &mut chain, rows * cols)?;
7840    let mut fused = e.zeros(rows * cols)?;
7841    launch_rms_sigmul(e, &x, &w, &z, &mut fused, cols, rows, eps)?;
7842    let (chain_h, fused_h) = (e.dtoh(&chain)?, e.dtoh(&fused)?);
7843    for (i, (&a, &b)) in chain_h.iter().zip(&fused_h).enumerate() {
7844        if a.to_bits() != b.to_bits() {
7845            return Err(format!(
7846                "rms_sigmul oracle: idx {i} not bit-identical: chain {a:?} fused {b:?}"
7847            )
7848            .into());
7849        }
7850    }
7851    Ok(format!(
7852        "gdn-step kernel oracle: scan step twin worst rel {worst:.3e} over artifact + \
7853         hk32 geometries; rms_sigmul bit-identical to the norm/sigmoid/mul chain ({rows}x{cols})"
7854    ))
7855}
7856
7857pub fn gate_qmatvec_bf16(e: &Engine) -> Res<String> {
7858    let mut lcg = 0x9e37_79b9_u64;
7859    let mut next_u32 = move || -> u32 {
7860        lcg = lcg
7861            .wrapping_mul(6364136223846793005)
7862            .wrapping_add(1442695040888963407);
7863        (lcg >> 33) as u32
7864    };
7865    let mut worst = (0.0f32, 0.0f32);
7866    for (mode, batch, t, out_f, in_f, x_bstride) in [
7867        ("per_batch_x", 3usize, 2usize, 5usize, 48usize, 2 * 48usize),
7868        ("shared_x", 4, 3, 7, 16, 0usize),
7869    ] {
7870        // bf16 weights minted as bf16 BYTES first (so the host twin widens the same
7871        // values the kernel reads), incl. sign and small-exponent coverage.
7872        let w_elems = batch * out_f * in_f;
7873        let mut w_bytes = Vec::with_capacity(w_elems * 2);
7874        let mut w_host = Vec::with_capacity(w_elems);
7875        for _ in 0..w_elems {
7876            // Magnitude bits below 0x4000 (= 2.0): denormals through ~2.0, signed —
7877            // keeps a 48-term dot far from overflow while covering the exponent range.
7878            let h = ((next_u32() % 0x4000) as u16) | (((next_u32() & 1) as u16) << 15);
7879            w_bytes.extend_from_slice(&h.to_le_bytes());
7880            w_host.push(f32::from_bits(u32::from(h) << 16));
7881        }
7882        let x_rows = if x_bstride == 0 { t } else { batch * t };
7883        let x_host: Vec<f32> = (0..x_rows * in_f)
7884            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7885            .collect();
7886        let w_dev = e.htod_bytes(&w_bytes)?;
7887        let x_dev = e.htod(&x_host)?;
7888        let mut y_dev = e.uninit(batch * t * out_f)?;
7889        launch_qmatvec_bf16w(
7890            e,
7891            &w_dev,
7892            &x_dev,
7893            &mut y_dev,
7894            in_f,
7895            out_f,
7896            t,
7897            batch,
7898            out_f * in_f,
7899            x_bstride,
7900            in_f,
7901            t * out_f,
7902        )?;
7903        let y = e.dtoh(&y_dev)?;
7904        for b in 0..batch {
7905            for tok in 0..t {
7906                let xrow = &x_host[b * x_bstride + tok * in_f..][..in_f];
7907                for o in 0..out_f {
7908                    let wrow = &w_host[(b * out_f + o) * in_f..][..in_f];
7909                    let mut want = 0.0f32;
7910                    for i in 0..in_f {
7911                        want += wrow[i] * xrow[i];
7912                    }
7913                    let got = y[(b * t + tok) * out_f + o];
7914                    let abs = (want - got).abs();
7915                    let rel = abs / want.abs().max(1.0);
7916                    worst.0 = worst.0.max(abs);
7917                    worst.1 = worst.1.max(rel);
7918                    if rel > 1e-5 {
7919                        return Err(format!(
7920                            "bf16-matvec oracle: {mode} b {b} tok {tok} row {o}: want {want} \
7921                             got {got} (rel {rel:.3e})"
7922                        )
7923                        .into());
7924                    }
7925                }
7926            }
7927        }
7928    }
7929    // MT weight-shared mode (mtp-spec verify): the multi-token kernel must be
7930    // BIT-IDENTICAL per (row, token) to the per-token grid on the same operands —
7931    // artifact-class geometry (in_f % 8, wide rows) + odd t.
7932    {
7933        let (out_f, in_f, t) = (33usize, 64usize, 5usize);
7934        let w_elems = out_f * in_f;
7935        let mut w_bytes = Vec::with_capacity(w_elems * 2);
7936        for _ in 0..w_elems {
7937            let h = ((next_u32() % 0x4000) as u16) | (((next_u32() & 1) as u16) << 15);
7938            w_bytes.extend_from_slice(&h.to_le_bytes());
7939        }
7940        let x_host: Vec<f32> = (0..t * in_f)
7941            .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7942            .collect();
7943        let w_dev = e.htod_bytes(&w_bytes)?;
7944        let x_dev = e.htod(&x_host)?;
7945        let mut y_grid = e.uninit(t * out_f)?;
7946        launch_qmatvec_bf16w(
7947            e,
7948            &w_dev,
7949            &x_dev,
7950            &mut y_grid,
7951            in_f,
7952            out_f,
7953            t,
7954            1,
7955            0,
7956            0,
7957            in_f,
7958            0,
7959        )?;
7960        let mut y_mt = e.uninit(t * out_f)?;
7961        launch_qmatvec_bf16w_mt(e, &w_dev, 0, &x_dev, &mut y_mt, in_f, out_f, t)?;
7962        let (a, b) = (e.dtoh(&y_grid)?, e.dtoh(&y_mt)?);
7963        for (i, (&x1, &x2)) in a.iter().zip(&b).enumerate() {
7964            if x1.to_bits() != x2.to_bits() {
7965                return Err(format!(
7966                    "bf16-matvec mt oracle: idx {i}: grid {x1} vs mt {x2} NOT bit-identical"
7967                )
7968                .into());
7969            }
7970        }
7971    }
7972    // SEL mode (devtwin stage 2, the DeviceBf16 draft bank): the device-selected
7973    // grouped kernel must be BIT-IDENTICAL per slot to the per-slot off_into chain on
7974    // the same bank + sel (duplicate slots included), in BOTH stride shapes — shared x
7975    // (gate/up) and per-slot x rows (down).
7976    {
7977        let (experts, out_f, in_f, n_sel) = (16usize, 24usize, 32usize, 6usize);
7978        let w_elems = experts * out_f * in_f;
7979        let mut w_bytes = Vec::with_capacity(w_elems * 2);
7980        for _ in 0..w_elems {
7981            let h = ((next_u32() % 0x4000) as u16) | (((next_u32() & 1) as u16) << 15);
7982            w_bytes.extend_from_slice(&h.to_le_bytes());
7983        }
7984        let sel_host: Vec<i32> = vec![7, 0, 15, 7, 3, 9]; // duplicate expert on purpose
7985        let bank = e.htod_bytes(&w_bytes)?;
7986        let sel = e.htod_i32(&sel_host)?;
7987        for (label, x_rows, x_sstride) in [("shared-x", 1usize, 0usize), ("slot-x", n_sel, in_f)] {
7988            let x_host: Vec<f32> = (0..x_rows * in_f)
7989                .map(|_| (next_u32() % 2000) as f32 / 1000.0 - 1.0)
7990                .collect();
7991            let x_dev = e.htod(&x_host)?;
7992            let mut y_sel = e.uninit(n_sel * out_f)?;
7993            launch_qmatvec_bf16w_sel(
7994                e, &bank, &sel, 0, &x_dev, 0, x_sstride, &mut y_sel, n_sel, in_f, out_f,
7995            )?;
7996            let mut y_ref = e.uninit(n_sel * out_f)?;
7997            for (slot, &eid) in sel_host.iter().enumerate() {
7998                launch_qmatvec_bf16w_off_into(
7999                    e,
8000                    &bank,
8001                    eid as usize * out_f,
8002                    &x_dev,
8003                    slot * x_sstride,
8004                    &mut y_ref,
8005                    slot * out_f,
8006                    in_f,
8007                    out_f,
8008                )?;
8009            }
8010            let (a, b) = (e.dtoh(&y_sel)?, e.dtoh(&y_ref)?);
8011            for (i, (&x1, &x2)) in a.iter().zip(&b).enumerate() {
8012                if x1.to_bits() != x2.to_bits() {
8013                    return Err(format!(
8014                        "bf16-matvec sel oracle ({label}): idx {i}: sel {x1} vs off_into {x2} \
8015                         NOT bit-identical"
8016                    )
8017                    .into());
8018                }
8019            }
8020        }
8021    }
8022    Ok(format!(
8023        "bf16-matvec kernel oracle: worst abs {:.3e} rel {:.3e} over per-batch + shared-x \
8024         modes, batch>1, t>1, signed/denormal bf16; mt weight-shared twin BIT-IDENTICAL \
8025         at t 5; sel grouped twin BIT-IDENTICAL to the off_into chain (shared-x + slot-x, \
8026         duplicate slots)",
8027        worst.0, worst.1
8028    ))
8029}
8030
8031/// Dequantize ONE expert of a device-resident modelopt-NVFP4 stacked bank to f32.
8032///
8033/// The existing dsv4 kernel (`memra_dsv4_nvfp4_deq_bf16`) emits bf16, so the macro is
8034/// NOT passed into it: e2m1 × e4m3 products carry ≤ 6 significand bits and are EXACT in
8035/// bf16, and the macro multiplies AFTER the exact f32 upcast. That reproduces the host
8036/// decoder (`dsv4::dequant_nvfp4_expert`: `(code * scale) * scale_2`, one f32 rounding)
8037/// bit-for-bit for ANY finite macro — the real qwen4_exp mint ships modelopt's
8038/// amax-derived NON-pow2 `weight_scale_2` (measured 5.9945243e-5), which the dsv4-era
8039/// in-kernel-macro chain would round in bf16 (hence its pow2 law; not needed here).
8040fn dequant_nvfp4_expert_f32(
8041    e: &Engine,
8042    codes: &CudaSlice<u8>,
8043    scales: &CudaSlice<u8>,
8044    macro_scale: f32,
8045    expert: usize,
8046    rows: usize,
8047    cols: usize,
8048) -> Res<CudaSlice<f32>> {
8049    let wbytes = rows * cols / 2;
8050    let sbytes = rows * cols / 16;
8051    let bf = e.alloc_u8(rows * cols * 2)?;
8052    let stream = e.gpu.stream();
8053    let wp = (codes.device_ptr(&stream).0 as usize + expert * wbytes) as *const c_void;
8054    let scp = (scales.device_ptr(&stream).0 as usize + expert * sbytes) as *const c_void;
8055    let dst = bf.device_ptr(&stream).0 as usize as *mut c_void;
8056    let rc = unsafe {
8057        crate::dsv4_ffi::memra_dsv4_nvfp4_deq_bf16(
8058            wp,
8059            scp,
8060            1.0, // macro applied post-upcast in f32 (see the doc comment)
8061            rows as i32,
8062            cols as i32,
8063            dst,
8064            stream.cu_stream() as *mut c_void,
8065        )
8066    };
8067    if rc != 0 {
8068        return Err(format!("memra_dsv4_nvfp4_deq_bf16 rc={rc}").into());
8069    }
8070    let mut out = e.bf16_to_f32(&bf.slice(0..rows * cols * 2), rows * cols)?;
8071    if macro_scale != 1.0 {
8072        e.scale_inplace(&mut out, macro_scale, rows * cols)?;
8073    }
8074    Ok(out)
8075}
8076
8077// ---------------------------------------------------------------- loading
8078
8079fn expect(weights: &ReferenceWeights, id: &TensorId) -> Res<ReferenceTensor> {
8080    weights
8081        .get(id)
8082        .cloned()
8083        .ok_or_else(|| format!("qwen4exp_gpu: missing weight {id:?}").into())
8084}
8085
8086fn family_id(key: String) -> TensorId {
8087    TensorId::Family {
8088        family: "qwen4_exp",
8089        key,
8090    }
8091}
8092
8093fn layer_id(index: u32, tensor: LayerTensor) -> TensorId {
8094    TensorId::Layer { index, tensor }
8095}
8096
8097fn upload(e: &Engine, tensor: &ReferenceTensor) -> Res<CudaSlice<f32>> {
8098    e.htod(&tensor.data)
8099}
8100
8101/// Slice a [rows, wide] row-major tensor into per-stream [rows, hidden] column blocks.
8102fn split_columns(data: &[f32], rows: usize, streams: usize, hidden: usize) -> Vec<Vec<f32>> {
8103    let wide = streams * hidden;
8104    (0..streams)
8105        .map(|s| {
8106            let mut out = Vec::with_capacity(rows * hidden);
8107            for row in 0..rows {
8108                out.extend_from_slice(
8109                    &data[row * wide + s * hidden..row * wide + (s + 1) * hidden],
8110                );
8111            }
8112            out
8113        })
8114        .collect()
8115}
8116
8117/// Slice a [wide, cols] row-major tensor into per-stream [hidden, cols] row blocks.
8118fn split_rows(data: &[f32], streams: usize, hidden: usize, cols: usize) -> Vec<Vec<f32>> {
8119    (0..streams)
8120        .map(|s| data[s * hidden * cols..(s + 1) * hidden * cols].to_vec())
8121        .collect()
8122}
8123
8124fn load_gate(
8125    e: &Engine,
8126    weights: &ReferenceWeights,
8127    prefix: &str,
8128    sublayer: &str,
8129    streams: usize,
8130    hidden: usize,
8131    rank: usize,
8132    with_inject: bool,
8133) -> Res<GateW> {
8134    let wide = streams * hidden;
8135    let norm = expect(
8136        weights,
8137        &family_id(format!("{prefix}{sublayer}hc_norm.weight")),
8138    )?;
8139    let down = expect(
8140        weights,
8141        &family_id(format!("{prefix}{sublayer}input_mix_weight_down.weight")),
8142    )?;
8143    let up = expect(
8144        weights,
8145        &family_id(format!("{prefix}{sublayer}input_mix_weight_up.weight")),
8146    )?;
8147    if norm.data.len() != wide || down.data.len() != rank * wide || up.data.len() != wide * rank {
8148        return Err(format!("qwen4exp_gpu: gate {prefix}{sublayer} shape mismatch").into());
8149    }
8150    let norm_slices = split_rows(&norm.data, streams, hidden, 1);
8151    let down_slices = split_columns(&down.data, rank, streams, hidden);
8152    let up_slices = split_rows(&up.data, streams, hidden, rank);
8153    // bf16 trunk twins, STACKED across streams so the fused gate runs one batched
8154    // launch per projection (guards in `bf16_twin`).
8155    let stack = |slices: &[Vec<f32>]| -> Vec<f32> {
8156        let mut out = Vec::with_capacity(slices.len() * slices[0].len());
8157        for s in slices {
8158            out.extend_from_slice(s);
8159        }
8160        out
8161    };
8162    let down_b16 = bf16_twin(e, &stack(&down_slices), hidden)?;
8163    let up_b16 = bf16_twin(e, &stack(&up_slices), rank)?;
8164    let (inject, inject_b16) = if with_inject {
8165        let inject = expect(
8166            weights,
8167            &family_id(format!("{prefix}{sublayer}block_inject_weight.weight")),
8168        )?;
8169        if inject.data.len() != streams * wide {
8170            return Err(format!("qwen4exp_gpu: inject {prefix}{sublayer} shape mismatch").into());
8171        }
8172        // Kept whole: the fused inject kernel walks [s][s2*hidden + d] directly, which is
8173        // exactly this tensor's row-major layout against the stream-major normed planes.
8174        (
8175            Some(e.htod(&inject.data)?),
8176            bf16_twin(e, &inject.data, hidden)?,
8177        )
8178    } else {
8179        (None, None)
8180    };
8181    Ok(GateW {
8182        norm_stack: e.htod(&stack(&norm_slices))?,
8183        norm: norm_slices
8184            .into_iter()
8185            .map(|v| e.htod(&v))
8186            .collect::<Result<_, _>>()?,
8187        down: down_slices
8188            .into_iter()
8189            .map(|v| e.htod(&v))
8190            .collect::<Result<_, _>>()?,
8191        up: up_slices
8192            .into_iter()
8193            .map(|v| e.htod(&v))
8194            .collect::<Result<_, _>>()?,
8195        inject,
8196        down_b16,
8197        up_b16,
8198        inject_b16,
8199    })
8200}
8201
8202/// Loader-side carriers that bypass `ReferenceWeights` (the real artifact cannot
8203/// materialize them host-f32): device-bound expert banks and host n-gram tables,
8204/// keyed by trunk layer index.
8205#[derive(Default)]
8206pub struct ExternalParts {
8207    expert_banks: std::collections::BTreeMap<u32, ExpertBank>,
8208    ngram_tables: std::collections::BTreeMap<u32, NgramTable>,
8209}
8210
8211/// Build one decoder layer's engine-resident weights from TensorId-keyed reference
8212/// weights — shared by the trunk loop and the MTP draft block (mtp-spec lane), which is
8213/// the same layer schema at global index n_trunk under the `mtp.layers.{depth}.` prefix.
8214#[allow(clippy::too_many_arguments)]
8215fn build_layer_w(
8216    e: &Engine,
8217    weights: &ReferenceWeights,
8218    layer: &memra_gguf::model_plan::LayerPlan,
8219    prefix: &str,
8220    streams: usize,
8221    hidden: usize,
8222    rank: usize,
8223    bank_override: Option<ExpertBank>,
8224    table_override: Option<NgramTable>,
8225) -> Res<LayerW> {
8226    let ResidualTopology::GatedResidual { .. } = layer.residual else {
8227        return Err(format!("qwen4exp_gpu: layer {} is not gated-residual", layer.index).into());
8228    };
8229    let attn_gate = load_gate(
8230        e,
8231        weights,
8232        &prefix,
8233        "attn_hyper_connection.",
8234        streams,
8235        hidden,
8236        rank,
8237        true,
8238    )?;
8239    let mlp_gate = load_gate(
8240        e,
8241        weights,
8242        &prefix,
8243        "mlp_hyper_connection.",
8244        streams,
8245        hidden,
8246        rank,
8247        true,
8248    )?;
8249    let mixer = match &layer.attention {
8250        AttentionPlan::Full(attn) => {
8251            let overlay = layer.sparse_overlay.ok_or_else(|| {
8252                format!(
8253                    "qwen4exp_gpu: QSA layer {} has no indexer overlay",
8254                    layer.index
8255                )
8256            })?;
8257            // Plain partial rope or YaRN (long-context lane); anything else refuses in
8258            // `build_yarn`.
8259            let yarn = build_yarn(e, &attn.rope, Some(&overlay), layer.index)?;
8260            // The eager attention path lays q/k/v/attended out with ONE head_dim
8261            // and gates full-width; unequal key/value dims would be silently
8262            // wrong, so refuse (family: 256/256).
8263            if attn.key_head_dim != attn.value_head_dim {
8264                return Err(format!(
8265                    "qwen4exp_gpu: layer {} key_head_dim {} != value_head_dim {}",
8266                    layer.index, attn.key_head_dim, attn.value_head_dim
8267                )
8268                .into());
8269            }
8270            let load_opt_norm = |tensor: LayerTensor| -> Res<Option<CudaSlice<f32>>> {
8271                match weights.get(&layer_id(layer.index, tensor)) {
8272                    Some(t) => Ok(Some(e.htod(&t.data)?)),
8273                    None if attn.qk_norm == TensorPresence::Required => {
8274                        Err(format!("qwen4exp_gpu: layer {} missing qk norm", layer.index).into())
8275                    }
8276                    None => Ok(None),
8277                }
8278            };
8279            let wq_t = expect(weights, &layer_id(layer.index, LayerTensor::Query))?;
8280            let wk_t = expect(weights, &layer_id(layer.index, LayerTensor::Key))?;
8281            let wv_t = expect(weights, &layer_id(layer.index, LayerTensor::Value))?;
8282            let wo_t = expect(
8283                weights,
8284                &layer_id(layer.index, LayerTensor::AttentionOutput),
8285            )?;
8286            let o_in = (attn.query_heads * attn.key_head_dim) as usize;
8287            MixerW::Qsa(QsaW {
8288                attn: attn.clone(),
8289                overlay,
8290                yarn,
8291                proj_b16: bf16_stack_twin(e, &[&wq_t.data, &wk_t.data, &wv_t.data], hidden)?,
8292                wo_b16: bf16_twin(e, &wo_t.data, o_in)?,
8293                wq: upload(e, &wq_t)?,
8294                wk: upload(e, &wk_t)?,
8295                wv: upload(e, &wv_t)?,
8296                wo: upload(e, &wo_t)?,
8297                q_norm: load_opt_norm(LayerTensor::QueryNorm)?,
8298                k_norm: load_opt_norm(LayerTensor::KeyNorm)?,
8299                idx_proj: upload(
8300                    e,
8301                    &expect(
8302                        weights,
8303                        &family_id(format!("{prefix}self_attn.indexer.index_qk_proj.weight")),
8304                    )?,
8305                )?,
8306                idx_q_norm: expect(
8307                    weights,
8308                    &family_id(format!("{prefix}self_attn.indexer.q_layernorm.weight")),
8309                )?
8310                .data,
8311                idx_k_norm: expect(
8312                    weights,
8313                    &family_id(format!("{prefix}self_attn.indexer.k_layernorm.weight")),
8314                )?
8315                .data,
8316            })
8317        }
8318        AttentionPlan::GatedDeltaNet(gdn) => {
8319            let qkv_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnQkv))?;
8320            let z_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnGate))?;
8321            let beta_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnBeta))?;
8322            let alpha_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnAlpha))?;
8323            let out_t = expect(weights, &layer_id(layer.index, LayerTensor::GdnOutput))?;
8324            let o_in = (gdn.value_heads * gdn.value_head_dim) as usize;
8325            MixerW::Gdn(GdnW {
8326                plan: *gdn,
8327                proj_b16: bf16_stack_twin(
8328                    e,
8329                    &[&qkv_t.data, &z_t.data, &beta_t.data, &alpha_t.data],
8330                    hidden,
8331                )?,
8332                out_b16: bf16_twin(e, &out_t.data, o_in)?,
8333                qkv: upload(e, &qkv_t)?,
8334                z: upload(e, &z_t)?,
8335                beta: upload(e, &beta_t)?,
8336                alpha: upload(e, &alpha_t)?,
8337                conv_w: upload(
8338                    e,
8339                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnConv1d))?,
8340                )?,
8341                a: upload(
8342                    e,
8343                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnA))?,
8344                )?,
8345                dt: upload(
8346                    e,
8347                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnDtBias))?,
8348                )?,
8349                norm: upload(
8350                    e,
8351                    &expect(weights, &layer_id(layer.index, LayerTensor::GdnNorm))?,
8352                )?,
8353                out: upload(e, &out_t)?,
8354            })
8355        }
8356        other => {
8357            return Err(format!(
8358                "qwen4exp_gpu: unsupported mixer {other:?} at layer {}",
8359                layer.index
8360            )
8361            .into());
8362        }
8363    };
8364    let MlpPlan::Moe(moe_plan) = &layer.mlp else {
8365        return Err(format!("qwen4exp_gpu: layer {} is not MoE", layer.index).into());
8366    };
8367    if !matches!(moe_plan.router, RouterPlan::Softmax) {
8368        return Err("qwen4exp_gpu: only the softmax router arm is implemented".into());
8369    }
8370    let shared = moe_plan
8371        .shared
8372        .as_ref()
8373        .ok_or("qwen4exp_gpu: missing shared expert plan")?;
8374    let bank = match bank_override {
8375        Some(bank) => bank,
8376        None => {
8377            let gate = expect(
8378                weights,
8379                &layer_id(layer.index, LayerTensor::MoeExpertGateBank),
8380            )?;
8381            let up = expect(
8382                weights,
8383                &layer_id(layer.index, LayerTensor::MoeExpertUpBank),
8384            )?;
8385            let down = expect(
8386                weights,
8387                &layer_id(layer.index, LayerTensor::MoeExpertDownBank),
8388            )?;
8389            let experts = moe_plan.expert_count as usize;
8390            let ff = moe_plan.expert_intermediate_size as usize;
8391            if gate.data.len() != experts * ff * hidden
8392                || up.data.len() != experts * ff * hidden
8393                || down.data.len() != experts * hidden * ff
8394            {
8395                return Err(format!(
8396                    "qwen4exp_gpu: layer {} expert bank shape mismatch",
8397                    layer.index
8398                )
8399                .into());
8400            }
8401            ExpertBank {
8402                gate: BankHalf::F32(e.htod(&gate.data)?),
8403                up: BankHalf::F32(e.htod(&up.data)?),
8404                down: BankHalf::F32(e.htod(&down.data)?),
8405            }
8406        }
8407    };
8408    let sh_gate_t = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpGate))?;
8409    let sh_up_t = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpUp))?;
8410    let sh_down_t = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpDown))?;
8411    let sff = shared.intermediate_size as usize;
8412    let router_t = expect(weights, &layer_id(layer.index, LayerTensor::MoeRouter))?;
8413    let moe = MoeW {
8414        plan: moe_plan.clone(),
8415        router_b16: bf16_twin(e, &router_t.data, hidden)?,
8416        router: upload(e, &router_t)?,
8417        bank,
8418        shared_gu_b16: bf16_stack_twin(e, &[&sh_gate_t.data, &sh_up_t.data], hidden)?,
8419        shared_down_b16: bf16_twin(e, &sh_down_t.data, sff)?,
8420        shared_gate: upload(e, &sh_gate_t)?,
8421        shared_up: upload(e, &sh_up_t)?,
8422        shared_down: upload(e, &sh_down_t)?,
8423        shared_input_gate: if shared.gated {
8424            Some(upload(
8425                e,
8426                &expect(
8427                    weights,
8428                    &layer_id(layer.index, LayerTensor::SharedMlpInputGate),
8429                )?,
8430            )?)
8431        } else {
8432            None
8433        },
8434    };
8435    let ple = match layer.ple.as_ref() {
8436        None => None,
8437        Some(ple_plan) => {
8438            let embed_dim = ple_plan.embed_dim as usize;
8439            let head_dim = ple_plan.head_embed_dim as usize;
8440            let wide = streams * hidden;
8441            let key_proj = expect(weights, &family_id(format!("{prefix}ple.key_proj.weight")))?;
8442            let conv_w = expect(weights, &family_id(format!("{prefix}ple.conv1d.weight")))?;
8443            if key_proj.data.len() != wide * embed_dim {
8444                return Err("qwen4exp_gpu: ple key_proj shape mismatch".into());
8445            }
8446            let norm_slices = |name: &str| -> Res<Vec<CudaSlice<f32>>> {
8447                let t = expect(weights, &family_id(format!("{prefix}ple.{name}.weight")))?;
8448                split_rows(&t.data, streams, hidden, 1)
8449                    .into_iter()
8450                    .map(|v| e.htod(&v))
8451                    .collect::<Result<_, _>>()
8452                    .map_err(Into::into)
8453            };
8454            let ints = |name: &str| -> Res<Vec<i64>> {
8455                let t = expect(
8456                    weights,
8457                    &family_id(format!("{prefix}ple.ple_embedding.{name}")),
8458                )?;
8459                t.ints
8460                    .clone()
8461                    .ok_or_else(|| "qwen4exp_gpu: n-gram buffer must be I64".into())
8462            };
8463            let table = match table_override {
8464                Some(table) => table,
8465                None => {
8466                    let t = expect(
8467                        weights,
8468                        &family_id(format!("{prefix}ple.ple_embedding.ngram_embedding")),
8469                    )?;
8470                    if t.shape.len() != 2 || t.shape[1] != head_dim {
8471                        return Err("qwen4exp_gpu: n-gram table shape mismatch".into());
8472                    }
8473                    NgramTable::F32(t.data)
8474                }
8475            };
8476            Some(PleW {
8477                plan: *ple_plan,
8478                key_proj: split_rows(&key_proj.data, streams, hidden, embed_dim)
8479                    .into_iter()
8480                    .map(|v| e.htod(&v))
8481                    .collect::<Result<_, _>>()?,
8482                value_proj: upload(
8483                    e,
8484                    &expect(
8485                        weights,
8486                        &family_id(format!("{prefix}ple.value_proj.weight")),
8487                    )?,
8488                )?,
8489                norm_key: norm_slices("norm_key")?,
8490                norm_query: norm_slices("norm_query")?,
8491                norm_conv: norm_slices("norm_conv")?,
8492                conv_w: split_rows(&conv_w.data, streams, hidden, ple_plan.conv_kernel as usize)
8493                    .into_iter()
8494                    .map(|v| e.htod(&v))
8495                    .collect::<Result<_, _>>()?,
8496                multipliers: ints("layer_multipliers")?,
8497                sizes: ints("ngram_heads_vocab_sizes")?,
8498                offsets: ints("ngram_heads_offsets")?,
8499                table,
8500            })
8501        }
8502    };
8503    Ok(LayerW {
8504        index: layer.index,
8505        eps_attn: layer.pre_attention_norm.epsilon,
8506        eps_mlp: layer.pre_mlp_norm.epsilon,
8507        attn_gate,
8508        mlp_gate,
8509        mixer,
8510        moe,
8511        ple,
8512    })
8513}
8514
8515/// Build the MTP draft block (SEMANTICS.md §MTP): fusion glue + the one decoder layer +
8516/// the draft's own exit mixer. The lm_head is SHARED with the trunk (`self.output`).
8517#[allow(clippy::too_many_arguments)]
8518fn build_mtp_w(
8519    e: &Engine,
8520    weights: &ReferenceWeights,
8521    block: &memra_gguf::model_plan::MtpBlockPlan,
8522    streams: usize,
8523    hidden: usize,
8524    rank: usize,
8525    bank_override: Option<ExpertBank>,
8526) -> Res<MtpW> {
8527    use memra_gguf::tensor_contract::MtpTensor;
8528    if block.input.fusion != memra_gguf::model_plan::MtpFusionPlan::SeparateProjections {
8529        return Err("qwen4exp_gpu: MTP block is not the separate-projections family".into());
8530    }
8531    let wide = streams * hidden;
8532    let depth = block.depth;
8533    let mtp_id = |tensor: MtpTensor| TensorId::Mtp { depth, tensor };
8534    let pre_e = expect(weights, &mtp_id(MtpTensor::EmbeddingNorm))?;
8535    let pre_h = expect(weights, &mtp_id(MtpTensor::HiddenNorm))?;
8536    let fc_e = expect(weights, &mtp_id(MtpTensor::EmbeddingProjection))?;
8537    let fc_h = expect(weights, &mtp_id(MtpTensor::HiddenProjection))?;
8538    if pre_e.data.len() != hidden
8539        || pre_h.data.len() != wide
8540        || fc_e.data.len() != hidden * hidden
8541        || fc_h.data.len() != hidden * hidden
8542    {
8543        return Err("qwen4exp_gpu: MTP fusion tensor shape mismatch".into());
8544    }
8545    let prefix = format!("mtp.layers.{depth}.");
8546    let layer = build_layer_w(
8547        e,
8548        weights,
8549        &block.layer,
8550        &prefix,
8551        streams,
8552        hidden,
8553        rank,
8554        bank_override,
8555        None,
8556    )?;
8557    let mixer = load_gate(
8558        e,
8559        weights,
8560        "mtp.hyper_connection_mixer.",
8561        "",
8562        streams,
8563        hidden,
8564        rank,
8565        false,
8566    )?;
8567    Ok(MtpW {
8568        eps_embed: block.input.embedding_norm.epsilon,
8569        eps_hidden: block.input.hidden_norm.epsilon,
8570        fc_embed_b16: bf16_twin(e, &fc_e.data, hidden)?,
8571        fc_hidden_b16: bf16_twin(e, &fc_h.data, hidden)?,
8572        pre_norm_embed: upload(e, &pre_e)?,
8573        pre_norm_hidden: upload(e, &pre_h)?,
8574        fc_embed: upload(e, &fc_e)?,
8575        fc_hidden: upload(e, &fc_h)?,
8576        layer,
8577        mixer,
8578    })
8579}
8580
8581impl Qwen4ExpGpu {
8582    /// Build the eager model from TensorId-keyed reference weights (the deterministic tiny
8583    /// fixture, or a checkpoint materialized through `read_checkpoint`'s binding walk).
8584    /// Effective (already-folded) norm weights; reference layout throughout.
8585    pub fn from_reference_weights(
8586        e: &Engine,
8587        plan: &ModelPlan,
8588        weights: &ReferenceWeights,
8589    ) -> Res<Self> {
8590        Self::from_reference_weights_with(e, None, plan, weights, ExternalParts::default())
8591    }
8592
8593    fn from_reference_weights_with(
8594        e: &Engine,
8595        // Card-1 draft placement (mtp10): when given, the MTP block's device tensors and
8596        // a private lm-head copy build on THIS engine instead of `e`.
8597        draft_e: Option<&Engine>,
8598        plan: &ModelPlan,
8599        weights: &ReferenceWeights,
8600        mut parts: ExternalParts,
8601    ) -> Res<Self> {
8602        let hidden = plan.hidden_size as usize;
8603        let vocab = plan.vocab_size as usize;
8604        let Some(mixer_plan) = plan.exit_mixer else {
8605            return Err("qwen4exp_gpu requires the gated-residual exit mixer".into());
8606        };
8607        let streams = mixer_plan.streams as usize;
8608        if streams > PLANE_SLOTS.len() {
8609            return Err("qwen4exp_gpu: hc_count exceeds the step-workspace slot table".into());
8610        }
8611        let rank = mixer_plan.bottleneck_rank as usize;
8612        if !plan.logits.is_empty() {
8613            return Err("qwen4exp_gpu: logits transforms are not part of this family".into());
8614        }
8615
8616        let embed = expect(weights, &TensorId::TokenEmbedding)?;
8617        if embed.data.len() != vocab * hidden {
8618            return Err("qwen4exp_gpu: embedding shape mismatch".into());
8619        }
8620        let (output, output_b16) = match weights.get(&TensorId::OutputProjection) {
8621            Some(tensor) => (e.htod(&tensor.data)?, bf16_twin(e, &tensor.data, hidden)?),
8622            None => (e.htod(&embed.data)?, bf16_twin(e, &embed.data, hidden)?),
8623        };
8624
8625        let mut layers = Vec::with_capacity(plan.layers.len());
8626        for layer in &plan.layers {
8627            let prefix = format!("trunk.layers.{}.", layer.index);
8628            layers.push(build_layer_w(
8629                e,
8630                weights,
8631                layer,
8632                &prefix,
8633                streams,
8634                hidden,
8635                rank,
8636                parts.expert_banks.remove(&layer.index),
8637                parts.ngram_tables.remove(&layer.index),
8638            )?);
8639        }
8640        // The MTP draft block (mtp-spec lane): built when its rows are present in the
8641        // materialized weights — presence-driven, so the deterministic fixture carries
8642        // it and a checkpoint loaded without `LoadOptions::load_mtp` skips it.
8643        let mtp = match plan.mtp_blocks.first() {
8644            Some(block)
8645                if weights
8646                    .get(&TensorId::Mtp {
8647                        depth: block.depth,
8648                        tensor: memra_gguf::tensor_contract::MtpTensor::EmbeddingProjection,
8649                    })
8650                    .is_some() =>
8651            {
8652                Some(build_mtp_w(
8653                    draft_e.unwrap_or(e),
8654                    weights,
8655                    block,
8656                    streams,
8657                    hidden,
8658                    rank,
8659                    parts.expert_banks.remove(&block.layer.index),
8660                )?)
8661            }
8662            _ => None,
8663        };
8664        // Card-1 lm-head copy for the dev1 draft: the SAME f32 rows and the SAME bf16
8665        // twin bytes as card 0's head, so the draft head program is verbatim.
8666        let mtp_dev1 = match (draft_e, mtp.as_ref()) {
8667            (Some(de), Some(_)) => {
8668                let head_data: &[f32] = match weights.get(&TensorId::OutputProjection) {
8669                    Some(tensor) => &tensor.data,
8670                    None => &embed.data,
8671                };
8672                Some(MtpDev1 {
8673                    dev: de.ctx().ordinal(),
8674                    output: de.htod(head_data)?,
8675                    output_b16: bf16_twin(de, head_data, hidden)?,
8676                })
8677            }
8678            (Some(_), None) => {
8679                return Err(
8680                    "qwen4exp_gpu: a draft engine was given but no mtp.* rows were \
8681                     materialized (LoadOptions::load_mtp)"
8682                        .into(),
8683                );
8684            }
8685            _ => None,
8686        };
8687        let exit_mixer = load_gate(
8688            e,
8689            weights,
8690            "trunk.hyper_connection_mixer.",
8691            "",
8692            streams,
8693            hidden,
8694            rank,
8695            false,
8696        )?;
8697        Ok(Self {
8698            plan: plan.clone(),
8699            hidden,
8700            streams,
8701            vocab,
8702            embed_host: embed.data,
8703            output,
8704            output_b16,
8705            layers,
8706            exit_mixer,
8707            exit_eps: plan.output_norm.epsilon,
8708            mtp,
8709            mtp_dev1,
8710            draft_trim: None,
8711            draft_trim_parked: None,
8712            chain_embed: None,
8713        })
8714    }
8715
8716    /// Arm the FR-Spec draft-head trim (mtp9): gather the `ids` rows of the SHARED lm head
8717    /// into a [n, hidden] trimmed head, D2D — same bytes, so every trimmed logit is
8718    /// bit-identical to its full-vocab twin. `ids` is the own-gen rank list in rank order
8719    /// (most frequent first); duplicates and out-of-range ids are rejected.
8720    ///
8721    /// Arming changes what the DRAFT can propose (acceptance), never what the model
8722    /// commits: the verify chunk is full-vocab and the accept walk compares against it.
8723    pub fn build_draft_trim(&mut self, e: &Engine, ids: &[u32]) -> Res<()> {
8724        // Card-1 placement: the trim gathers from the DEV1 head copy (same bytes as
8725        // card 0's) and its rows live beside the draft — `e` must be the draft engine.
8726        self.check_draft_engine(e)?;
8727        let n = ids.len();
8728        if n == 0 || n > self.vocab {
8729            return Err(format!("qwen4exp_gpu: draft trim wants 1..={} ids", self.vocab).into());
8730        }
8731        let mut seen = vec![false; self.vocab];
8732        for &id in ids {
8733            let id = id as usize;
8734            if id >= self.vocab {
8735                return Err(format!("qwen4exp_gpu: draft trim id {id} out of vocab").into());
8736            }
8737            if std::mem::replace(&mut seen[id], true) {
8738                return Err(format!("qwen4exp_gpu: draft trim id {id} repeats").into());
8739            }
8740        }
8741        let hidden = self.hidden;
8742        let (src_f32, src_b16) = match self.mtp_dev1.as_ref() {
8743            Some(d) => (&d.output, d.output_b16.as_ref()),
8744            None => (&self.output, self.output_b16.as_ref()),
8745        };
8746        // Gather the bf16 twin when it exists (the arm the trunk seam runs) and SKIP the
8747        // f32 gather entirely — at N=32768 that is 168 MB instead of 503 MB, and the f32
8748        // arm would be dead residency. No twin => gather f32, the only arm available.
8749        let (head_b16, head) = match src_b16 {
8750            Some(full) => {
8751                let mut trim = e.alloc_u8_uninit(n * hidden * 2)?;
8752                for (row, &id) in ids.iter().enumerate() {
8753                    e.copy_u8_range_into(
8754                        &mut trim,
8755                        row * hidden * 2,
8756                        full,
8757                        id as usize * hidden * 2,
8758                        hidden * 2,
8759                    )?;
8760                }
8761                (Some(trim), None)
8762            }
8763            None => {
8764                let mut head = e.uninit(n * hidden)?;
8765                for (row, &id) in ids.iter().enumerate() {
8766                    e.copy_range_into(
8767                        &mut head,
8768                        row * hidden,
8769                        src_f32,
8770                        id as usize * hidden,
8771                        hidden,
8772                    )?;
8773                }
8774                (None, Some(head))
8775            }
8776        };
8777        self.draft_trim = Some(DraftTrim {
8778            n,
8779            d2t: ids.to_vec(),
8780            head,
8781            head_b16,
8782        });
8783        self.draft_trim_parked = None;
8784        Ok(())
8785    }
8786
8787    /// Flip a BUILT trim between live and parked (the interleaved A/B's two arms) without
8788    /// reallocating the gathered head. No-op when no trim was ever built.
8789    pub fn set_draft_trim(&mut self, on: bool) {
8790        if on {
8791            if let Some(t) = self.draft_trim_parked.take() {
8792                self.draft_trim = Some(t);
8793            }
8794        } else if let Some(t) = self.draft_trim.take() {
8795            self.draft_trim_parked = Some(t);
8796        }
8797    }
8798
8799    /// Drop the draft trim entirely (both live and parked).
8800    pub fn clear_draft_trim(&mut self) {
8801        self.draft_trim = None;
8802        self.draft_trim_parked = None;
8803    }
8804
8805    /// Arm the deferred-chain embed table (mtp11, `SpecOpts::defer`): the chain's
8806    /// next-step embed rows, resident on the DRAFT engine, so the device argmax feeds
8807    /// the next chain step without a host round trip (see [`ChainEmbed`] for the
8808    /// bf16-clean bit-identity contract and the trim-rank row order). Re-arm after any
8809    /// trim change — `spec_generate_ext` refuses a table whose trim state or width
8810    /// disagrees with the live draft head.
8811    pub fn arm_spec_devchain(&mut self, de: &Engine) -> Res<()> {
8812        self.check_draft_engine(de)?;
8813        let hidden = self.hidden;
8814        let (rows, for_trim) = match self.draft_trim.as_ref() {
8815            Some(tr) => (tr.n, true),
8816            None => (self.vocab, false),
8817        };
8818        let src_row = |r: usize| -> &[f32] {
8819            let id = match self.draft_trim.as_ref() {
8820                Some(tr) => tr.d2t[r] as usize,
8821                None => r,
8822            };
8823            &self.embed_host[id * hidden..(id + 1) * hidden]
8824        };
8825        // bf16-clean scan over the SELECTED rows: every value must round-trip
8826        // f32 -> bits>>16 -> bits<<16 exactly, or the table falls back to raw f32.
8827        let clean = (0..rows).all(|r| src_row(r).iter().all(|x| x.to_bits() & 0xFFFF == 0));
8828        let (bytes, qt, row_bytes) = if clean {
8829            let mut b = vec![0u8; rows * hidden * 2];
8830            for r in 0..rows {
8831                for (j, &x) in src_row(r).iter().enumerate() {
8832                    let h = (x.to_bits() >> 16) as u16;
8833                    b[(r * hidden + j) * 2..(r * hidden + j) * 2 + 2]
8834                        .copy_from_slice(&h.to_le_bytes());
8835                }
8836            }
8837            (b, crate::QT_BF16, hidden * 2)
8838        } else {
8839            let mut b = vec![0u8; rows * hidden * 4];
8840            for r in 0..rows {
8841                for (j, &x) in src_row(r).iter().enumerate() {
8842                    b[(r * hidden + j) * 4..(r * hidden + j) * 4 + 4]
8843                        .copy_from_slice(&x.to_le_bytes());
8844                }
8845            }
8846            (b, crate::QT_F32, hidden * 4)
8847        };
8848        let table = de.upload_u8(&bytes)?;
8849        println!(
8850            "[qwen4exp-spec] deferred-chain embed table armed: {} rows x {hidden} ({}, {:.1} MiB, dev {}{})",
8851            rows,
8852            if clean {
8853                "bf16 bit-clean"
8854            } else {
8855                "f32 fallback"
8856            },
8857            (rows * row_bytes) as f64 / (1024.0 * 1024.0),
8858            de.ctx().ordinal(),
8859            if for_trim { ", trim-rank order" } else { "" },
8860        );
8861        self.chain_embed = Some(ChainEmbed {
8862            table,
8863            qt,
8864            row_bytes,
8865            rows,
8866            for_trim,
8867            dev: de.ctx().ordinal(),
8868        });
8869        Ok(())
8870    }
8871
8872    /// Drop the deferred-chain embed table (frees the card-1 residency).
8873    pub fn clear_spec_devchain(&mut self) {
8874        self.chain_embed = None;
8875    }
8876
8877    /// Rows the draft's lm_head produces: the trim width when armed, else full vocab.
8878    /// Draft logits live in TRIMMED space when armed; `draft_token` maps a row back.
8879    pub fn draft_logits_width(&self) -> usize {
8880        match self.draft_trim.as_ref() {
8881            Some(t) => t.n,
8882            None => self.vocab,
8883        }
8884    }
8885
8886    /// Map a draft-logits row index back to its TARGET vocab id (identity when the trim
8887    /// is off).
8888    fn draft_token(&self, row: u32) -> Res<u32> {
8889        match self.draft_trim.as_ref() {
8890            Some(t) => t
8891                .d2t
8892                .get(row as usize)
8893                .copied()
8894                .ok_or_else(|| format!("qwen4exp_gpu: draft row {row} outside the trim").into()),
8895            None => Ok(row),
8896        }
8897    }
8898
8899    /// Trunk f32 diet (yarn-cell follow-up 3): FREE the f32 originals whose bf16 twins
8900    /// are resident — under the ship seams (trunk-bf16 + fused-gate, both default ON)
8901    /// every consumer of these tensors runs the bf16 kernels at every t, so the f32
8902    /// copies are pure dead residency (~6 GiB on card 0 at the real geometry). Each
8903    /// dropped tensor becomes a 1-element stub; every f32 fallback path guards on the
8904    /// stub and errs loudly instead of reading it (flipping the trunk seams OFF after
8905    /// the diet refuses rather than corrupting). Returns bytes freed. NOT applied to
8906    /// the MTP draft weights (card-1 slack; the reference-parity gates read them).
8907    pub fn trunk_f32_diet(&mut self, e: &Engine) -> Res<usize> {
8908        if !trunk_bf16_on() || !hc_fused_gate_on() {
8909            return Err(
8910                "qwen4exp_gpu: trunk_f32_diet requires the trunk-bf16 + fused-gate seams ON \
8911                 (the bf16 paths must be the ones serving)"
8912                    .into(),
8913            );
8914        }
8915        let mut freed = 0usize;
8916        fn stub(e: &Engine, s: &mut CudaSlice<f32>, freed: &mut usize) -> Res<()> {
8917            if s.len() > 1 {
8918                *freed += s.len() * 4;
8919                *s = e.zeros(1)?;
8920            }
8921            Ok(())
8922        }
8923        fn diet_gate(e: &Engine, g: &mut GateW, freed: &mut usize) -> Res<()> {
8924            if g.down_b16.is_none()
8925                || g.up_b16.is_none()
8926                || (g.inject.is_some() && g.inject_b16.is_none())
8927            {
8928                return Ok(()); // partial twins: keep the f32 arm whole
8929            }
8930            for s in g.down.iter_mut() {
8931                stub(e, s, freed)?;
8932            }
8933            for s in g.up.iter_mut() {
8934                stub(e, s, freed)?;
8935            }
8936            if let Some(inj) = g.inject.as_mut() {
8937                stub(e, inj, freed)?;
8938            }
8939            Ok(())
8940        }
8941        for layer in self.layers.iter_mut() {
8942            diet_gate(e, &mut layer.attn_gate, &mut freed)?;
8943            diet_gate(e, &mut layer.mlp_gate, &mut freed)?;
8944            match &mut layer.mixer {
8945                MixerW::Qsa(q) => {
8946                    if q.proj_b16.is_some() {
8947                        stub(e, &mut q.wq, &mut freed)?;
8948                        stub(e, &mut q.wk, &mut freed)?;
8949                        stub(e, &mut q.wv, &mut freed)?;
8950                    }
8951                    if q.wo_b16.is_some() {
8952                        stub(e, &mut q.wo, &mut freed)?;
8953                    }
8954                }
8955                MixerW::Gdn(g) => {
8956                    if g.proj_b16.is_some() {
8957                        stub(e, &mut g.qkv, &mut freed)?;
8958                        stub(e, &mut g.z, &mut freed)?;
8959                        stub(e, &mut g.beta, &mut freed)?;
8960                        stub(e, &mut g.alpha, &mut freed)?;
8961                    }
8962                    if g.out_b16.is_some() {
8963                        stub(e, &mut g.out, &mut freed)?;
8964                    }
8965                }
8966            }
8967            let moe = &mut layer.moe;
8968            if moe.router_b16.is_some() {
8969                stub(e, &mut moe.router, &mut freed)?;
8970            }
8971            if moe.shared_gu_b16.is_some() {
8972                stub(e, &mut moe.shared_gate, &mut freed)?;
8973                stub(e, &mut moe.shared_up, &mut freed)?;
8974            }
8975            if moe.shared_down_b16.is_some() {
8976                stub(e, &mut moe.shared_down, &mut freed)?;
8977            }
8978        }
8979        diet_gate(e, &mut self.exit_mixer, &mut freed)?;
8980        if self.output_b16.is_some() {
8981            stub(e, &mut self.output, &mut freed)?;
8982        }
8983        Ok(freed)
8984    }
8985
8986    pub fn alloc_state(&self, e: &Engine, capacity: usize) -> Res<Qwen4ExpState> {
8987        self.alloc_state_reserve(e, capacity, capacity, None)
8988    }
8989
8990    /// Long-context state: `reserve` caps the workspace-slot unit at the chunk bound
8991    /// (see `Qwen4ExpState::reserve`), and `kv_engine` optionally places the QSA KV
8992    /// caches on ANOTHER card (the kv-dev1 ladder arm: card 0 holds the trunk at
8993    /// ~90 GiB; the attention kernels read K/V over UVA P2P). `None` = same card.
8994    pub fn alloc_state_reserve(
8995        &self,
8996        e: &Engine,
8997        capacity: usize,
8998        reserve: usize,
8999        kv_engine: Option<&Engine>,
9000    ) -> Res<Qwen4ExpState> {
9001        let kv_e = kv_engine.unwrap_or(e);
9002        let mut layers = Vec::with_capacity(self.layers.len());
9003        for layer in &self.layers {
9004            let mixer = match &layer.mixer {
9005                MixerW::Qsa(qsa) => {
9006                    let kv_width = qsa.attn.kv_heads as usize * qsa.attn.key_head_dim as usize;
9007                    let v_width = qsa.attn.kv_heads as usize * qsa.attn.value_head_dim as usize;
9008                    // kvq/idxq lanes: the storage format latches PER STATE here (a byte
9009                    // cache cannot flip mid-run; the A/B harness allocates per arm).
9010                    let kv = if kv_quant_on() {
9011                        QsaKvStore::Q8Q5 {
9012                            k: kv_e.alloc_u8(capacity * q8_row_bytes(kv_width))?,
9013                            v: kv_e.alloc_u8(capacity * q5_row_bytes(v_width))?,
9014                        }
9015                    } else {
9016                        QsaKvStore::F32 {
9017                            k: kv_e.zeros(capacity * kv_width)?,
9018                            v: kv_e.zeros(capacity * v_width)?,
9019                        }
9020                    };
9021                    MixerState::Qsa {
9022                        kv,
9023                        raw_keys: IdxRawCache::new(idxq_mode()),
9024                        pooled_keys: Vec::new(),
9025                        pooled_dev: None,
9026                        pooled_dev_rows: 0,
9027                        raw_dev: None,
9028                        raw_dev_rows: 0,
9029                        idx_audit: (idxq_mode() != IdxQMode::F32 && idxq_audit_on()).then(|| {
9030                            Box::new(IdxAudit {
9031                                raw_f32: IdxRawCache::F32(Vec::new()),
9032                                pooled_f32: Vec::new(),
9033                            })
9034                        }),
9035                    }
9036                }
9037                MixerW::Gdn(gdn) => {
9038                    let p = &gdn.plan;
9039                    let conv_dim = 2 * (p.key_heads * p.key_head_dim) as usize
9040                        + (p.value_heads * p.value_head_dim) as usize;
9041                    let pad = p.conv_kernel as usize - 1;
9042                    MixerState::Gdn {
9043                        conv: e.zeros(pad * conv_dim)?,
9044                        state: e
9045                            .zeros((p.value_heads * p.value_head_dim * p.key_head_dim) as usize)?,
9046                    }
9047                }
9048            };
9049            let ple = match layer.ple.as_ref() {
9050                None => None,
9051                Some(ple) => {
9052                    let pad = (ple.plan.conv_kernel as usize - 1) * ple.plan.max_ngram as usize;
9053                    let mut conv_hist = Vec::with_capacity(self.streams);
9054                    for _ in 0..self.streams {
9055                        conv_hist.push(e.zeros(pad * self.hidden)?);
9056                    }
9057                    Some(PleState {
9058                        conv_hist,
9059                        ngram_ids: Vec::new(),
9060                        ngram_history: Vec::new(),
9061                        ngram_last_eos: -1,
9062                    })
9063                }
9064            };
9065            layers.push(LayerState { mixer, ple });
9066        }
9067        Ok(Qwen4ExpState {
9068            pos: 0,
9069            capacity,
9070            reserve,
9071            tokens: Vec::new(),
9072            layers,
9073            ws: StepPool::default(),
9074            graphs: StepGraphs::default(),
9075            tp2: None,
9076            verify: None,
9077        })
9078    }
9079
9080    /// Prefill `ids` from the state's current position. Returns [t, vocab] logits (host).
9081    pub fn prefill(&self, e: &Engine, ids: &[u32], state: &mut Qwen4ExpState) -> Res<Vec<f32>> {
9082        self.forward(e, ids, state, None)
9083    }
9084
9085    /// LONG-context chunked prefill: forward `ids` in `chunk`-sized pieces from the
9086    /// state's current position, skipping the exit mixer + lm_head on every chunk but
9087    /// materializing ONLY the final row's logits at the end. State-identical to one big
9088    /// `prefill` (the head reads no state and writes none); the [t, vocab] logits block
9089    /// a big chunk would otherwise materialize is the thing being skipped (16 GB at
9090    /// chunk 16384 on this vocab). Returns the LAST row's logits [vocab].
9091    pub fn prefill_extend(
9092        &self,
9093        e: &Engine,
9094        ids: &[u32],
9095        state: &mut Qwen4ExpState,
9096        chunk: usize,
9097    ) -> Res<Vec<f32>> {
9098        if ids.is_empty() || chunk == 0 {
9099            return Err("qwen4exp_gpu: prefill_extend needs ids and a chunk size".into());
9100        }
9101        let mut last = Vec::new();
9102        for piece in ids.chunks(chunk) {
9103            let is_last =
9104                piece.as_ptr() as usize + piece.len() * 4 == ids.as_ptr() as usize + ids.len() * 4;
9105            let head = if is_last {
9106                HeadMode::LastRow
9107            } else {
9108                HeadMode::Skip
9109            };
9110            last = self.forward_with(e, piece, state, None, head)?;
9111        }
9112        Ok(last)
9113    }
9114
9115    /// One incremental decode step (no prompt recompute). Returns [vocab] logits (host).
9116    pub fn decode_step(&self, e: &Engine, token: u32, state: &mut Qwen4ExpState) -> Res<Vec<f32>> {
9117        self.forward(e, &[token], state, None)
9118    }
9119
9120    /// Prefill with per-layer parity capture (the transformers hidden-goldens hook
9121    /// points): post-layer WIDE rows per trunk layer + the exit mixer output.
9122    pub fn prefill_captured(
9123        &self,
9124        e: &Engine,
9125        ids: &[u32],
9126        state: &mut Qwen4ExpState,
9127    ) -> Res<(Vec<f32>, PrefillCapture)> {
9128        let mut capture = PrefillCapture {
9129            layer_wide: Vec::with_capacity(self.layers.len()),
9130            exit_mixed: Vec::new(),
9131        };
9132        let logits = self.forward(e, ids, state, Some(&mut capture))?;
9133        Ok((logits, capture))
9134    }
9135
9136    /// Interleave stream-major planes into token-major wide rows [t, streams*hidden]
9137    /// (the HF wide-stream layout: token row = concat over streams).
9138    fn planes_to_wide(&self, e: &Engine, planes: &[CudaSlice<f32>], t: usize) -> Res<Vec<f32>> {
9139        let hidden = self.hidden;
9140        let wide = self.streams * hidden;
9141        let mut out = vec![0.0f32; t * wide];
9142        for (s, plane) in planes.iter().enumerate() {
9143            // Slice: workspace planes are reserve-sized (>= t*hidden).
9144            let host = e.dtoh_view(&plane.slice(0..t * hidden))?;
9145            for row in 0..t {
9146                out[row * wide + s * hidden..row * wide + (s + 1) * hidden]
9147                    .copy_from_slice(&host[row * hidden..(row + 1) * hidden]);
9148            }
9149        }
9150        Ok(out)
9151    }
9152
9153    fn forward(
9154        &self,
9155        e: &Engine,
9156        ids: &[u32],
9157        state: &mut Qwen4ExpState,
9158        capture: Option<&mut PrefillCapture>,
9159    ) -> Res<Vec<f32>> {
9160        self.forward_with(e, ids, state, capture, HeadMode::All)
9161    }
9162
9163    fn forward_with(
9164        &self,
9165        e: &Engine,
9166        ids: &[u32],
9167        state: &mut Qwen4ExpState,
9168        mut capture: Option<&mut PrefillCapture>,
9169        head: HeadMode,
9170    ) -> Res<Vec<f32>> {
9171        let t = ids.len();
9172        let hidden = self.hidden;
9173        if t == 0 {
9174            return Err("qwen4exp_gpu: empty input".into());
9175        }
9176        if head != HeadMode::All {
9177            // Head-skipping forwards are a chunked-prefill shape: goldens capture wants
9178            // every row, and a verify-EXACT chunk (t <= k_cap) or a t == 1 step feeds
9179            // the argmax sink from the full logits block. Big verify-armed chunks are
9180            // fine — the wide capture happens before the head, and the spec co-prefill
9181            // is exactly this shape.
9182            if capture.is_some() {
9183                return Err("qwen4exp_gpu: prefill capture wants every logits row".into());
9184            }
9185            if let Some(v) = state.verify.as_ref()
9186                && (t == 1 || t <= v.k_cap)
9187            {
9188                return Err(
9189                    "qwen4exp_gpu: head-skipping forward on a verify-exact chunk shape".into(),
9190                );
9191            }
9192        }
9193        if state.pos + t > state.capacity {
9194            return Err("qwen4exp_gpu: state capacity exceeded".into());
9195        }
9196        if state.tp2.is_some() {
9197            return Err(
9198                "qwen4exp_gpu: state already decoded in TP2 mode; single-card forward \
9199                 requires a fresh state (the half-state migration is one-way)"
9200                    .into(),
9201            );
9202        }
9203        let base_pos = state.pos;
9204        state.tokens.extend_from_slice(ids);
9205        // A multi-token chunk can GROW workspace slots (reallocation) — any captured
9206        // graph would keep the stale baked addresses, so invalidate them first.
9207        if t > 1 {
9208            state.graphs = StepGraphs::default();
9209        }
9210        // Decode graphs never engage on an ARMED-verify state (mtp11): the graphs tail
9211        // (`forward_graphs_tail`) carries neither the wide capture nor the argmax sink,
9212        // so two consecutive t == 1 forwards with verify armed (= consecutive zero-draft
9213        // rounds under the p-min guard) would route the second through the tail and skip
9214        // the wide row the next replay seeds from — an acceptance-only degradation the
9215        // byte-identity gates cannot see (the mtp11 audit's found-while-auditing item).
9216        let graphs_mode = t == 1
9217            && decode_graphs_on()
9218            && step_ws_on()
9219            && hc_fused_gate_on()
9220            && !prof::on()
9221            && capture.is_none()
9222            && state.verify.is_none();
9223        let tokens = &state.tokens;
9224        let ws = &mut state.ws;
9225        // Verify instrument (mtp-spec lane): while armed, capture the final wide rows
9226        // every forward; 1 < t <= k_cap chunks additionally run the EXACT row programs
9227        // (each row bit-identical to t == 1 decode) and stash per-column GDN/PLE state.
9228        let verify = state.verify.as_mut();
9229        let (exact, stash_gdn, stash_ple, stash_wide, argmax_sink, last_row_only) = match verify {
9230            Some(v) => {
9231                // Exact verify chunks NEVER include the prefill (base_pos == 0): a
9232                // prompt shorter than k_cap would otherwise prefill through the
9233                // per-row DECODE programs while the plain baseline prefills FUSED —
9234                // bit-different state from token 0 that drifts until the first
9235                // thin-margin argmax flips. Found by the mtp11 256-token battery
9236                // (raw prompt 2, len 6, K=5: k_cap 6 >= 6 -> exact prefill ->
9237                // divergence at gen 157; K<=4 fused the same prefill and passed);
9238                // latent since mtp-spec (every green spec-gate ran 64 tokens, and
9239                // the tiny fixture's 18-token prompt never fit inside k_cap).
9240                let exact = base_pos > 0 && t > 1 && t <= v.k_cap;
9241                // mtp11 deferred round: the t == 1 steps (zero-draft verify, dynk
9242                // plain tail) take the argmax fast path too — same sink, same
9243                // bit-identical device argmax, a 4-byte dtoh instead of ~1 MB.
9244                let amx_t1 = t == 1 && v.want_argmax_t1;
9245                if exact {
9246                    v.chunk = Some((base_pos, t));
9247                    v.argmax.clear();
9248                } else if amx_t1 && v.want_argmax {
9249                    v.argmax.clear();
9250                }
9251                (
9252                    exact,
9253                    Some(&mut v.gdn),
9254                    Some(&mut v.ple),
9255                    Some((&mut v.wide, v.ring_rows)),
9256                    if (exact || amx_t1) && v.want_argmax {
9257                        Some((&mut v.argmax, &mut v.toks))
9258                    } else {
9259                        None
9260                    },
9261                    v.last_row_only && t > 1 && !exact,
9262                )
9263            }
9264            None => (false, None, None, None, None, false),
9265        };
9266        let mut stash_gdn = stash_gdn;
9267        let mut stash_ple = stash_ple;
9268        // Slot RESERVE unit: reserve-derived so a growing decode never reallocates a
9269        // slot mid-run (address stability, item 2b's prerequisite). Transients scale
9270        // with the CHUNK length t; `reserve` = capacity by default, but a LONG-context
9271        // state (alloc_state_reserve) caps it at the chunk bound — a 1M-capacity state
9272        // must not reserve 1M-token transients (plane slots alone would be ~41 GB).
9273        let cap = state.reserve.max(t);
9274
9275        // Entry: wide stream = `streams` copies of the embedding (modular L1012), held as
9276        // stream-major planes so every per-stream op is a contiguous existing kernel.
9277        let mut planes = prof_section(e, "entry.embed", || {
9278            let mut embedded = vec![0.0f32; t * hidden];
9279            for (row, &token) in ids.iter().enumerate() {
9280                let token = token as usize;
9281                if token >= self.vocab {
9282                    return Err(format!("qwen4exp_gpu: token {token} out of range").into());
9283                }
9284                embedded[row * hidden..(row + 1) * hidden]
9285                    .copy_from_slice(&self.embed_host[token * hidden..(token + 1) * hidden]);
9286            }
9287            let embedded_dev = ws.take_f32_h2d(e, "entry.embed", &embedded, cap * hidden)?;
9288            let mut planes: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
9289            for s in 0..self.streams {
9290                let mut plane = ws.take_f32(e, PLANE_SLOTS[s], t * hidden, cap * hidden)?;
9291                e.copy_into(&mut plane, 0, &embedded_dev, t * hidden)?;
9292                planes.push(plane);
9293            }
9294            ws.put_f32("entry.embed", embedded_dev);
9295            Ok(planes)
9296        })?;
9297
9298        // Plane pointer table for the stream-batched kernels (hcmicro): refreshed every
9299        // step (eagerly, outside any graph) into a stable slot the captured launches
9300        // read at run time.
9301        let ptr_vals: Vec<u64> = {
9302            let stream = e.gpu.stream();
9303            planes.iter().map(|p| p.device_ptr(&stream).0).collect()
9304        };
9305        let ptrs = ws.take_u64_h2d(e, "hc.ptrs", &ptr_vals, 0)?;
9306
9307        if graphs_mode {
9308            if state.graphs.warm {
9309                return self.forward_graphs_tail(e, state, planes, ptrs, base_pos);
9310            }
9311            // First graph-eligible step: run EAGER to warm/park every slot (allocations
9312            // inside a capture region become graph mem nodes); capture starts next step.
9313            state.graphs.warm = true;
9314        }
9315
9316        for (li, (layer, lstate)) in self.layers.iter().zip(state.layers.iter_mut()).enumerate() {
9317            if let (Some(ple), Some(ple_state)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
9318                let ps = if exact {
9319                    stash_ple
9320                        .as_mut()
9321                        .and_then(|v| v.get_mut(li))
9322                        .and_then(|s| s.as_mut())
9323                } else {
9324                    None
9325                };
9326                self.ple_block(
9327                    e,
9328                    layer,
9329                    ple,
9330                    &ple.table,
9331                    ple_state,
9332                    &mut planes,
9333                    tokens,
9334                    t,
9335                    exact,
9336                    ps,
9337                )?;
9338            }
9339            let (mixed, inject) = prof_section(e, "hyper.read", || {
9340                self.gate_read(
9341                    e,
9342                    ws,
9343                    &ptrs,
9344                    &layer.attn_gate,
9345                    &planes,
9346                    t,
9347                    layer.eps_attn,
9348                    exact,
9349                )
9350            })?;
9351            let block_out = match &layer.mixer {
9352                MixerW::Qsa(qsa) => self.qsa_forward(
9353                    e,
9354                    ws,
9355                    layer,
9356                    qsa,
9357                    &mixed,
9358                    &mut lstate.mixer,
9359                    base_pos,
9360                    t,
9361                    0,
9362                    exact,
9363                )?,
9364                MixerW::Gdn(gdn) => {
9365                    let gs = if exact {
9366                        stash_gdn
9367                            .as_mut()
9368                            .and_then(|v| v.get_mut(li))
9369                            .and_then(|s| s.as_mut())
9370                    } else {
9371                        None
9372                    };
9373                    self.gdn_forward(e, ws, layer, gdn, &mixed, &mut lstate.mixer, t, gs)?
9374                }
9375            };
9376            ws.put_f32("hc.mixed", mixed);
9377            prof_section(e, "hyper.write", || {
9378                self.gate_write(e, &mut planes, &ptrs, &block_out, &inject, t)
9379            })?;
9380            ws.put_f32("mixer.out", block_out);
9381            put_inject(ws, inject);
9382            let (mixed, inject) = prof_section(e, "hyper.read", || {
9383                self.gate_read(
9384                    e,
9385                    ws,
9386                    &ptrs,
9387                    &layer.mlp_gate,
9388                    &planes,
9389                    t,
9390                    layer.eps_mlp,
9391                    exact,
9392                )
9393            })?;
9394            // Chunked long-context prefill (head-skipping forwards) rides the GROUPED
9395            // MoE program like verify chunks do: the per-expert prefill executor pays
9396            // 3 dequants + several small syncing H2Ds + GEMMs PER ROUTED EXPERT per
9397            // chunk (~512 x 48 per chunk = minutes/chunk measured on the smoke ladder);
9398            // the grouped path is 2 launches + t combines per layer on NVFP4 banks.
9399            // Decode-class rows (per-slot programs bit-identical to t == 1) — the
9400            // chunked-prefill gates are tolerance-class by design.
9401            // `prefill_grouped_all_on()` is the TP2 class gate's PRIME instrument (default
9402            // OFF = today's behavior exactly): it lets an all-rows single-card forward run
9403            // the GROUPED executor so a TP2 comparison isolates the expert-half split
9404            // instead of straddling it and the executor difference. See the flag's doc.
9405            let grouped = exact || head != HeadMode::All || prefill_grouped_all_on();
9406            let mlp = self.moe_forward(e, ws, &layer.moe, &mixed, t, grouped, layer.index)?;
9407            ws.put_f32("hc.mixed", mixed);
9408            prof_section(e, "hyper.write", || {
9409                self.gate_write(e, &mut planes, &ptrs, &mlp, &inject, t)
9410            })?;
9411            ws.put_f32("moe.out", mlp);
9412            put_inject(ws, inject);
9413            if let Some(capture) = capture.as_deref_mut() {
9414                capture.layer_wide.push(self.planes_to_wide(e, &planes, t)?);
9415            }
9416        }
9417
9418        // Verify wide capture: the trunk's FINAL wide rows at their absolute positions,
9419        // ring-slotted (row % ring_rows; ring == capacity is the historical identity
9420        // layout) — the draft's hidden seeds (SEMANTICS.md §MTP).
9421        if let Some((wide_buf, ring_rows)) = stash_wide {
9422            let wide = self.streams * hidden;
9423            for (s, plane) in planes.iter().enumerate() {
9424                for tok in 0..t {
9425                    e.copy_range_into(
9426                        wide_buf,
9427                        ((base_pos + tok) % ring_rows) * wide + s * hidden,
9428                        plane,
9429                        tok * hidden,
9430                        hidden,
9431                    )?;
9432                }
9433            }
9434        }
9435
9436        // Head skip (chunked long-context prefill): the exit mixer + lm_head read no
9437        // state and write none — a mid-prefill chunk stops here, state-identical.
9438        if head == HeadMode::Skip {
9439            ws.put_u64("hc.ptrs", ptrs);
9440            state.pos += t;
9441            for (s, plane) in planes.into_iter().enumerate() {
9442                ws.put_f32(PLANE_SLOTS[s], plane);
9443            }
9444            return Ok(Vec::new());
9445        }
9446
9447        // Exit downmix replaces the final norm (SEMANTICS.md §Layer stack).
9448        let x = prof_section(e, "exit.mixer", || {
9449            Ok(self
9450                .gate_read_inner(
9451                    e,
9452                    ws,
9453                    &ptrs,
9454                    &self.exit_mixer,
9455                    &planes,
9456                    t,
9457                    self.exit_eps,
9458                    false,
9459                    exact,
9460                )?
9461                .0)
9462        })?;
9463        ws.put_u64("hc.ptrs", ptrs);
9464        if let Some(capture) = capture.as_deref_mut() {
9465            capture.exit_mixed = e.dtoh(&x)?;
9466        }
9467        // LastRow (chunked prefill's final chunk): lm_head on ONE row — a [t, vocab]
9468        // logits block at long-context chunk sizes is gigabytes.
9469        let head_rows = if head == HeadMode::LastRow { 1 } else { t };
9470        let logits = prof_section(e, "lm_head", || {
9471            let mut logits =
9472                ws.take_f32(e, "logits", head_rows * self.vocab, head_rows * self.vocab)?;
9473            let x_head = if head == HeadMode::LastRow {
9474                let mut last = ws.take_f32(e, "exit.last", hidden, hidden)?;
9475                e.copy_range_into(&mut last, 0, &x, (t - 1) * hidden, hidden)?;
9476                last
9477            } else {
9478                x
9479            };
9480            linear_trunk_into(
9481                e,
9482                &self.output,
9483                &self.output_b16,
9484                &x_head,
9485                &mut logits,
9486                head_rows,
9487                hidden,
9488                self.vocab,
9489            )?;
9490            ws.put_f32(
9491                if head == HeadMode::LastRow {
9492                    "exit.last"
9493                } else {
9494                    "hc.mixed"
9495                },
9496                x_head,
9497            );
9498            Ok(logits)
9499        })?;
9500        state.pos += t;
9501        if head == HeadMode::LastRow {
9502            let out = prof_section(e, "logits.dtoh", || {
9503                Ok(e.dtoh_view(&logits.slice(0..self.vocab))?)
9504            })?;
9505            ws.put_f32("logits", logits);
9506            for (s, plane) in planes.into_iter().enumerate() {
9507                ws.put_f32(PLANE_SLOTS[s], plane);
9508            }
9509            return Ok(out);
9510        }
9511        // Verify fast path: per-row device argmax + a 4t-byte dtoh instead of the
9512        // [t, vocab] block (the spec loop reads target rows only).
9513        let out = if let Some((argmax_rows, toks)) = argmax_sink {
9514            prof_section(e, "logits.argmax", || {
9515                for row in 0..t {
9516                    e.argmax_token_device_col(&logits, row, self.vocab, toks, row)?;
9517                }
9518                let host = e.gpu.stream().clone_dtoh(&toks.slice(0..t))?;
9519                argmax_rows.extend_from_slice(&host);
9520                Ok(Vec::new())
9521            })?
9522        } else if last_row_only {
9523            // mtp11: big-t (prefill) forwards under the deferred seam dtoh ONE row —
9524            // the spec loop reads exactly one (x0). Same bytes for that row.
9525            prof_section(e, "logits.dtoh", || {
9526                Ok(e.dtoh_view(&logits.slice((t - 1) * self.vocab..t * self.vocab))?)
9527            })?
9528        } else {
9529            prof_section(e, "logits.dtoh", || {
9530                Ok(e.dtoh_view(&logits.slice(0..t * self.vocab))?)
9531            })?
9532        };
9533        ws.put_f32("logits", logits);
9534        for (s, plane) in planes.into_iter().enumerate() {
9535            ws.put_f32(PLANE_SLOTS[s], plane);
9536        }
9537        Ok(out)
9538    }
9539
9540    /// Gated-residual read gate (`gated_residual_read` twin): grouped (effective-weight)
9541    /// RMSNorm per stream, `w = sigmoid(up(silu(down(normed)/S)))`, `mixed = mean_s(w ⊙
9542    /// normed_s)`, inject scalars `2*sigmoid(block_inject(normed)/S)` per stream.
9543    #[allow(clippy::too_many_arguments)]
9544    #[allow(clippy::too_many_arguments)]
9545    fn gate_read(
9546        &self,
9547        e: &Engine,
9548        ws: &mut StepPool,
9549        ptrs: &CudaSlice<u64>,
9550        gate: &GateW,
9551        planes: &[CudaSlice<f32>],
9552        t: usize,
9553        eps: f32,
9554        exact: bool,
9555    ) -> Res<(CudaSlice<f32>, InjectOut)> {
9556        self.gate_read_inner(e, ws, ptrs, gate, planes, t, eps, true, exact)
9557    }
9558
9559    #[allow(clippy::too_many_arguments)]
9560    #[allow(clippy::too_many_arguments)]
9561    fn gate_read_inner(
9562        &self,
9563        e: &Engine,
9564        ws: &mut StepPool,
9565        ptrs: &CudaSlice<u64>,
9566        gate: &GateW,
9567        planes: &[CudaSlice<f32>],
9568        t: usize,
9569        eps: f32,
9570        with_inject: bool,
9571        // Verify-chunk exactness (mtp-spec lane): engage the DIET kernels at t > 1 so
9572        // every verify row runs the DECODE gate program verbatim per token (the diet
9573        // kernels' token dim is the t == 1 program at a plane offset — bit-identical
9574        // rows). Plain prefill keeps the fused chain (banked-goldens numerics stay).
9575        exact: bool,
9576    ) -> Res<(CudaSlice<f32>, InjectOut)> {
9577        if !hc_fused_gate_on() {
9578            return self.gate_read_legacy(e, ws, gate, planes, t, eps, with_inject);
9579        }
9580        let hidden = self.hidden;
9581        let streams = self.streams;
9582        let rank = gate_rank(gate, hidden, streams)?;
9583        let micro_norm = micro_norm_on();
9584        let micro_inj = micro_inj_on();
9585        // Hyper-gate diet (round 4): the whole read gate in THREE launches. Requires the
9586        // bf16 twins + the Slab inject posture (micro_inj — take_inject's form contract)
9587        // + real geometry; anything else falls back to the fused chain below.
9588        if hc_diet_on()
9589            && (t == 1 || exact)
9590            && trunk_bf16_on()
9591            && micro_inj
9592            && hidden % 8 == 0
9593            && rank % 8 == 0
9594            && gate.down_b16.is_some()
9595            && gate.up_b16.is_some()
9596            && (!with_inject || gate.inject_b16.is_some())
9597        {
9598            let mut parts = ws.take_f32(e, "hc.parts", t * streams * rank, 0)?;
9599            let mut injp = ws.take_f32(e, "hc.injp", t * streams * streams, 0)?;
9600            let mut inv = ws.take_f32(e, "hc.inv", t * streams, 0)?;
9601            let winj = if with_inject {
9602                gate.inject_b16.as_ref()
9603            } else {
9604                None
9605            };
9606            // Weight-shared MT stages (set_verify_mt) at verify chunks: bit-identical
9607            // per token to the token-grid stages (kernel docs + gate oracle), weight
9608            // reads 1x instead of t x.
9609            let mt = t > 1 && verify_mt_on() && (2..=12).contains(&t);
9610            if mt {
9611                launch_hc_diet_stage0_mt(e, ptrs, &mut inv, hidden, streams, t, eps)?;
9612                launch_hc_diet_stage1_mt(
9613                    e,
9614                    ptrs,
9615                    &gate.norm_stack,
9616                    &inv,
9617                    gate.down_b16.as_ref().expect("guarded above"),
9618                    winj,
9619                    &mut parts,
9620                    &mut injp,
9621                    hidden,
9622                    rank,
9623                    streams,
9624                    t,
9625                )?;
9626            } else {
9627                launch_hc_diet_stage1(
9628                    e,
9629                    ptrs,
9630                    &gate.norm_stack,
9631                    gate.down_b16.as_ref().expect("guarded above"),
9632                    winj,
9633                    &mut parts,
9634                    &mut injp,
9635                    &mut inv,
9636                    hidden,
9637                    rank,
9638                    streams,
9639                    t,
9640                    eps,
9641                )?;
9642            }
9643            let mut low_act = ws.take_f32(e, "hc.low_act", t * rank, 0)?;
9644            let mut all = ws.take_f32(e, "hc.inj_all", streams * t, 0)?;
9645            launch_hc_diet_stage2(
9646                e,
9647                &parts,
9648                &injp,
9649                &mut low_act,
9650                &mut all,
9651                rank,
9652                streams,
9653                t,
9654                with_inject,
9655            )?;
9656            let mut mixed = ws.take_f32(e, "hc.mixed", t * hidden, 0)?;
9657            if mt && (t * rank + 8 * streams * t) * 4 <= 96 * 1024 {
9658                launch_hc_diet_stage3_mt(
9659                    e,
9660                    ptrs,
9661                    &gate.norm_stack,
9662                    &inv,
9663                    gate.up_b16.as_ref().expect("guarded above"),
9664                    &low_act,
9665                    &mut mixed,
9666                    hidden,
9667                    rank,
9668                    streams,
9669                    t,
9670                )?;
9671            } else {
9672                launch_hc_diet_stage3(
9673                    e,
9674                    ptrs,
9675                    &gate.norm_stack,
9676                    &inv,
9677                    gate.up_b16.as_ref().expect("guarded above"),
9678                    &low_act,
9679                    &mut mixed,
9680                    hidden,
9681                    rank,
9682                    streams,
9683                    t,
9684                )?;
9685            }
9686            ws.put_f32("hc.parts", parts);
9687            ws.put_f32("hc.injp", injp);
9688            ws.put_f32("hc.inv", inv);
9689            ws.put_f32("hc.low_act", low_act);
9690            let inject_out = if with_inject {
9691                InjectOut::Slab(all)
9692            } else {
9693                ws.put_f32("hc.inj_all", all);
9694                InjectOut::Rows(Vec::new())
9695            };
9696            return Ok((mixed, inject_out));
9697        }
9698
9699        // Buffers are STREAM-MAJOR and CONTIGUOUS ([streams, t, width]) so the three fused
9700        // gate kernels (perf lane attack (c)) each read every stream in one launch; the
9701        // 12 GEMVs stay cuBLASLt. Launches per read gate: 4 norms + 4 down + 1 reduce +
9702        // 4 up + 1 epilogue + 1 inject = 15, vs ~71 before (PROFILE-0: 27.7% of the token
9703        // across 96 calls, nearly all issue latency).
9704        let mut normed = ws.take_f32(e, "hc.normed", streams * t * hidden, 0)?;
9705        if micro_norm {
9706            // One launch for all streams over the plane pointer table (hcmicro).
9707            launch_hc_norm_planes(
9708                e,
9709                ptrs,
9710                &gate.norm_stack,
9711                &mut normed,
9712                hidden,
9713                t,
9714                streams,
9715                eps,
9716            )?;
9717        } else {
9718            for s in 0..streams {
9719                let mut dst = normed.slice_mut(s * t * hidden..(s + 1) * t * hidden);
9720                launch_rms_norm_into_view(e, &planes[s], &gate.norm[s], &mut dst, hidden, t, eps)?;
9721            }
9722        }
9723        // low_act = silu(mean_s down_s @ normed_s). bf16 trunk residency runs the
9724        // projection as ONE batched launch over the stream-major slab (stacked twin,
9725        // same output layout as the per-stream cuBLASLt chain — the A/B/fallback arm).
9726        let trunk_b16 = trunk_bf16_on();
9727        let mut parts = ws.take_f32(e, "hc.parts", streams * t * rank, 0)?;
9728        if let (true, Some(w)) = (trunk_b16, gate.down_b16.as_ref()) {
9729            launch_qmatvec_bf16w(
9730                e,
9731                w,
9732                &normed,
9733                &mut parts,
9734                hidden,
9735                rank,
9736                t,
9737                streams,
9738                rank * hidden,
9739                t * hidden,
9740                hidden,
9741                t * rank,
9742            )?;
9743        } else {
9744            if gate.down[0].len() < rank * hidden {
9745                return Err(
9746                    "qwen4exp_gpu: gate down f32 dropped (trunk_f32_diet) — keep the \
9747                            trunk-bf16 seam ON"
9748                        .into(),
9749                );
9750            }
9751            for s in 0..streams {
9752                let x = normed.slice(s * t * hidden..(s + 1) * t * hidden);
9753                let w = gate.down[s].slice(0..rank * hidden);
9754                let mut out = parts.slice_mut(s * t * rank..(s + 1) * t * rank);
9755                e.linear_device_into(&x, &w, &mut out, t, hidden, rank)?;
9756            }
9757        }
9758        let mut low_act = ws.take_f32(e, "hc.low_act", t * rank, 0)?;
9759        launch_hc_lowrank_reduce(e, &parts, &mut low_act, streams, t, rank)?;
9760        ws.put_f32("hc.parts", parts);
9761
9762        // mixed = mean_s sigmoid(up_s @ low_act) ⊙ normed_s (batched twin: x_bstride 0
9763        // shares the one low_act plane across streams).
9764        let mut gates = ws.take_f32(e, "hc.gates", streams * t * hidden, 0)?;
9765        if let (true, Some(w)) = (trunk_b16, gate.up_b16.as_ref()) {
9766            launch_qmatvec_bf16w(
9767                e,
9768                w,
9769                &low_act,
9770                &mut gates,
9771                rank,
9772                hidden,
9773                t,
9774                streams,
9775                hidden * rank,
9776                0,
9777                rank,
9778                t * hidden,
9779            )?;
9780        } else {
9781            if gate.up[0].len() < hidden * rank {
9782                return Err(
9783                    "qwen4exp_gpu: gate up f32 dropped (trunk_f32_diet) — keep the \
9784                            trunk-bf16 seam ON"
9785                        .into(),
9786                );
9787            }
9788            for s in 0..streams {
9789                let x = low_act.slice(0..t * rank);
9790                let w = gate.up[s].slice(0..hidden * rank);
9791                let mut out = gates.slice_mut(s * t * hidden..(s + 1) * t * hidden);
9792                e.linear_device_into(&x, &w, &mut out, t, rank, hidden)?;
9793            }
9794        }
9795        let mut mixed = ws.take_f32(e, "hc.mixed", t * hidden, 0)?;
9796        launch_hc_mix_epilogue(e, &gates, &normed, &mut mixed, streams, t, hidden)?;
9797        ws.put_f32("hc.gates", gates);
9798        ws.put_f32("hc.low_act", low_act);
9799
9800        let mut inject_out = InjectOut::Rows(Vec::new());
9801        if with_inject {
9802            let inject = gate
9803                .inject
9804                .as_ref()
9805                .ok_or("qwen4exp_gpu: read gate missing inject weights")?;
9806            // trunk_f32_diet: the f32 inject may be a dropped stub — every non-b16
9807            // consumer below must refuse it rather than read garbage.
9808            let inject_dropped = inject.len() < streams * streams * hidden;
9809            let inject_guard = || -> Res<()> {
9810                if inject_dropped {
9811                    return Err("qwen4exp_gpu: inject f32 dropped (trunk_f32_diet) — keep \
9812                                the trunk-bf16 seam ON"
9813                        .into());
9814                }
9815                Ok(())
9816            };
9817            let mut all = ws.take_f32(e, "hc.inj_all", streams * t, 0)?;
9818            if micro_inj {
9819                // Two-stage inject (hcmicro): chunked partials fill the card, the reduce
9820                // applies the sigmoid; the slab goes straight to `gate_write`.
9821                const CHUNKS: usize = 16;
9822                let mut partials = ws.take_f32(e, "hc.inj_part", streams * t * CHUNKS, 0)?;
9823                let w_b16 = if trunk_b16 {
9824                    gate.inject_b16.as_ref()
9825                } else {
9826                    None
9827                };
9828                if w_b16.is_none() {
9829                    inject_guard()?;
9830                }
9831                launch_hc_inject_two_stage(
9832                    e,
9833                    &normed,
9834                    inject,
9835                    w_b16,
9836                    &mut partials,
9837                    &mut all,
9838                    streams,
9839                    t,
9840                    hidden,
9841                    CHUNKS,
9842                )?;
9843                ws.put_f32("hc.inj_part", partials);
9844                inject_out = InjectOut::Slab(all);
9845            } else {
9846                // [streams, t] scalars in one launch; `gate_write` consumes one row per
9847                // stream.
9848                if let (true, Some(w)) = (trunk_b16, gate.inject_b16.as_ref()) {
9849                    launch_hc_inject_gates_b16(e, &normed, w, &mut all, streams, t, hidden)?;
9850                } else {
9851                    inject_guard()?;
9852                    launch_hc_inject_gates(e, &normed, inject, &mut all, streams, t, hidden)?;
9853                }
9854                let mut rows = Vec::with_capacity(streams);
9855                for s in 0..streams {
9856                    let mut row = ws.take_f32(e, INJECT_SLOTS[s], t, 0)?;
9857                    e.copy_range_into(&mut row, 0, &all, s * t, t)?;
9858                    rows.push(row);
9859                }
9860                ws.put_f32("hc.inj_all", all);
9861                inject_out = InjectOut::Rows(rows);
9862            }
9863        }
9864        ws.put_f32("hc.normed", normed);
9865        Ok((mixed, inject_out))
9866    }
9867
9868    /// Unfused read gate — the literal `gated_residual_read` composition from existing
9869    /// engine ops, kept as the A/B twin of the fused arm (`set_hc_fused_gate(false)`) and
9870    /// as the readable statement of the program. ~71 launches per call at hc_count 4.
9871    /// Deliberately NOT workspace-pooled: it is the hc-off measurement twin.
9872    #[allow(clippy::too_many_arguments)]
9873    fn gate_read_legacy(
9874        &self,
9875        e: &Engine,
9876        _ws: &mut StepPool,
9877        gate: &GateW,
9878        planes: &[CudaSlice<f32>],
9879        t: usize,
9880        eps: f32,
9881        with_inject: bool,
9882    ) -> Res<(CudaSlice<f32>, InjectOut)> {
9883        let hidden = self.hidden;
9884        let streams = self.streams;
9885        let rank = gate_rank(gate, hidden, streams)?;
9886        if gate.down[0].len() < rank * hidden {
9887            return Err(
9888                "qwen4exp_gpu: gate f32 originals dropped (trunk_f32_diet) — the \
9889                        legacy gate path needs them (keep hc seams ON)"
9890                    .into(),
9891            );
9892        }
9893        let inv_streams = 1.0 / streams as f32; // pow2 (hc_count 4 / tiny 2) — exact
9894
9895        let mut normed = Vec::with_capacity(streams);
9896        for s in 0..streams {
9897            let mut dst = e.uninit(t * hidden)?;
9898            e.rms_norm(&planes[s], &gate.norm[s], &mut dst, hidden, t, eps)?;
9899            normed.push(dst);
9900        }
9901        // low = silu(sum_s down_s @ normed_s / S)
9902        let mut low = e.linear(&normed[0], &gate.down[0], t, hidden, rank)?;
9903        for s in 1..streams {
9904            let part = e.linear(&normed[s], &gate.down[s], t, hidden, rank)?;
9905            let mut view = low.slice_mut(0..t * rank);
9906            e.axpy_into(&part, 1.0, &mut view, t * rank)?;
9907        }
9908        e.scale_inplace(&mut low, inv_streams, t * rank)?;
9909        let ones = e.htod(&vec![1.0f32; t * rank.max(1)])?;
9910        let mut low_act = e.uninit(t * rank)?;
9911        e.silu_mul(&low, &ones, &mut low_act, t * rank)?;
9912
9913        // mixed = mean_s sigmoid(up_s @ low) ⊙ normed_s
9914        let mut mixed = e.zeros(t * hidden)?;
9915        let mut gate_buf = e.uninit(t * hidden)?;
9916        let mut prod = e.uninit(t * hidden)?;
9917        for s in 0..streams {
9918            let g = e.linear(&low_act, &gate.up[s], t, rank, hidden)?;
9919            e.sigmoid(&g, &mut gate_buf, t * hidden)?;
9920            e.mul(&gate_buf, &normed[s], &mut prod, t * hidden)?;
9921            let mut view = mixed.slice_mut(0..t * hidden);
9922            e.axpy_into(&prod, 1.0, &mut view, t * hidden)?;
9923        }
9924        e.scale_inplace(&mut mixed, inv_streams, t * hidden)?;
9925
9926        let mut inject_out = Vec::new();
9927        if with_inject {
9928            let inject = gate
9929                .inject
9930                .as_ref()
9931                .ok_or("qwen4exp_gpu: read gate missing inject weights")?;
9932            let wide = streams * hidden;
9933            for s in 0..streams {
9934                // Per-(s, s2) [hidden] weight windows of block_inject_weight row s.
9935                let mut acc = {
9936                    let w = inject.slice(s * wide..s * wide + hidden);
9937                    let x = normed[0].slice(0..t * hidden);
9938                    let mut out = e.uninit(t)?;
9939                    e.linear_device_into(&x, &w, &mut out, t, hidden, 1)?;
9940                    out
9941                };
9942                for s2 in 1..streams {
9943                    let w = inject.slice(s * wide + s2 * hidden..s * wide + (s2 + 1) * hidden);
9944                    let x = normed[s2].slice(0..t * hidden);
9945                    let mut part = e.uninit(t)?;
9946                    e.linear_device_into(&x, &w, &mut part, t, hidden, 1)?;
9947                    let mut view = acc.slice_mut(0..t);
9948                    e.axpy_into(&part, 1.0, &mut view, t)?;
9949                }
9950                e.scale_inplace(&mut acc, inv_streams, t)?;
9951                let mut sg = e.uninit(t)?;
9952                e.sigmoid(&acc, &mut sg, t)?;
9953                e.scale_inplace(&mut sg, 2.0, t)?;
9954                inject_out.push(sg);
9955            }
9956        }
9957        Ok((mixed, InjectOut::Rows(inject_out)))
9958    }
9959
9960    /// Write half (`gated_residual_write` twin): plane_s += block_out ⊗ inject_s.
9961    /// Rows = per-stream add_scaled_rows (item-1-era plumbing); Slab = one launch over
9962    /// the plane pointer table (hcmicro).
9963    fn gate_write(
9964        &self,
9965        e: &Engine,
9966        planes: &mut [CudaSlice<f32>],
9967        ptrs: &CudaSlice<u64>,
9968        block_out: &CudaSlice<f32>,
9969        inject: &InjectOut,
9970        t: usize,
9971    ) -> Res<()> {
9972        match inject {
9973            InjectOut::Rows(rows) => {
9974                for (plane, inj) in planes.iter_mut().zip(rows) {
9975                    e.add_scaled_rows(block_out, inj, plane, self.hidden, t)?;
9976                }
9977                Ok(())
9978            }
9979            InjectOut::Slab(slab) => {
9980                launch_hc_write_planes(e, ptrs, block_out, slab, self.hidden, t, self.streams)
9981            }
9982        }
9983    }
9984
9985    /// One decode layer's INTERIOR at t == 1 (graph driver, item 2b): PLE (when
9986    /// present) → attn read gate → mixer → write → mlp read gate, ending with the mlp
9987    /// `mixed`/inject scalars PARKED in their slots for the MoE tail. The exact
9988    /// semantics of the eager `forward` loop body up to `moe_forward`; device-only for
9989    /// GDN layers without PLE, which is what makes those capturable.
9990    #[allow(clippy::too_many_arguments)]
9991    #[allow(clippy::too_many_arguments)]
9992    fn layer_interior(
9993        &self,
9994        e: &Engine,
9995        ws: &mut StepPool,
9996        ptrs: &CudaSlice<u64>,
9997        layer: &LayerW,
9998        lstate: &mut LayerState,
9999        planes: &mut [CudaSlice<f32>],
10000        tokens: &[u32],
10001        base_pos: usize,
10002    ) -> Res<()> {
10003        if let (Some(ple), Some(ple_state)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
10004            self.ple_block(
10005                e, layer, ple, &ple.table, ple_state, planes, tokens, 1, false, None,
10006            )?;
10007        }
10008        let (mixed, inject) = self.gate_read(
10009            e,
10010            ws,
10011            ptrs,
10012            &layer.attn_gate,
10013            planes,
10014            1,
10015            layer.eps_attn,
10016            false,
10017        )?;
10018        let block_out = match &layer.mixer {
10019            MixerW::Qsa(qsa) => self.qsa_forward(
10020                e,
10021                ws,
10022                layer,
10023                qsa,
10024                &mixed,
10025                &mut lstate.mixer,
10026                base_pos,
10027                1,
10028                0,
10029                false,
10030            )?,
10031            MixerW::Gdn(gdn) => {
10032                self.gdn_forward(e, ws, layer, gdn, &mixed, &mut lstate.mixer, 1, None)?
10033            }
10034        };
10035        ws.put_f32("hc.mixed", mixed);
10036        self.gate_write(e, planes, ptrs, &block_out, &inject, 1)?;
10037        ws.put_f32("mixer.out", block_out);
10038        put_inject(ws, inject);
10039        let (mixed, inject) = self.gate_read(
10040            e,
10041            ws,
10042            ptrs,
10043            &layer.mlp_gate,
10044            planes,
10045            1,
10046            layer.eps_mlp,
10047            false,
10048        )?;
10049        ws.put_f32("hc.mixed", mixed);
10050        put_inject(ws, inject);
10051        Ok(())
10052    }
10053
10054    /// Per-step MoE routing (graph driver): router GEMV over the parked mlp `mixed`,
10055    /// dtoh (the per-layer host boundary — routing is a HOST twin by lane doctrine, so
10056    /// a whole-step graph is structurally impossible; this is the sync the segment
10057    /// graphs meet at), reference top-k, then H2D of the selection into the slot
10058    /// addresses the captured MoE-tail graph baked.
10059    fn moe_route_slots(&self, e: &Engine, ws: &mut StepPool, moe: &MoeW, layer: u32) -> Res<()> {
10060        let hidden = self.hidden;
10061        let experts = moe.plan.expert_count as usize;
10062        let selected = moe.plan.experts_per_token as usize;
10063        let mixed = ws.take_f32(e, "hc.mixed", hidden, 0)?;
10064        let mut router_out = ws.take_f32(e, "moe.router", experts, 0)?;
10065        let none: Option<CudaSlice<u8>> = None;
10066        let rb = if router_bf16_on() {
10067            &moe.router_b16
10068        } else {
10069            &none
10070        };
10071        linear_trunk_into(
10072            e,
10073            &moe.router,
10074            rb,
10075            &mixed,
10076            &mut router_out,
10077            1,
10078            hidden,
10079            experts,
10080        )?;
10081        // Device router (devtwin lane): the route stays on device — no dtoh, no host
10082        // top-k, no selection h2d. Writes land in the SAME parked slots the captured
10083        // MoE-tail graph baked (take-without-upload + put preserves the address).
10084        if router_dev_on() && route_dev_geometry(experts, selected) {
10085            let mut sel = ws.take_i32_slot(e, "moe.sel", selected, 0)?;
10086            let mut w = ws.take_f32(e, "moe.w", selected, 0)?;
10087            route_topk_device(
10088                e,
10089                &router_out,
10090                &mut sel,
10091                &mut w,
10092                None,
10093                experts,
10094                selected,
10095                1,
10096                layer,
10097            )?;
10098            // DIAGNOSTIC ONLY (`MEMRA_Q4E_ROUTE_SYNC=1`, never a serving arm): restore the
10099            // host arm's per-layer SYNC structure while keeping the device route, to
10100            // separate "the kernel costs" from "the missing sync costs" in the
10101            // graphs-ON regression (devtwin: graphs OFF the seam wins 1.083x, graphs ON
10102            // it loses — PROFILE-9 §3).
10103            if route_sync_diag() {
10104                e.gpu.stream().synchronize()?;
10105            }
10106            ws.put_i32("moe.sel", sel);
10107            ws.put_f32("moe.w", w);
10108            ws.put_f32("moe.router", router_out);
10109            ws.put_f32("hc.mixed", mixed);
10110            return Ok(());
10111        }
10112        let logits = e.dtoh_view(&router_out.slice(0..experts))?;
10113        ws.put_f32("moe.router", router_out);
10114        ws.put_f32("hc.mixed", mixed);
10115        let route = host_route_softmax_topk(&logits, selected);
10116        let sel_host: Vec<i32> = route.iter().map(|&(x, _)| x as i32).collect();
10117        let w_host: Vec<f32> = route.iter().map(|&(_, w)| w).collect();
10118        ws.write_i32(e, "moe.sel", &sel_host)?;
10119        ws.write_f32(e, "moe.w", &w_host)?;
10120        Ok(())
10121    }
10122
10123    /// The grouped-MoE tail at t == 1 over PARKED slots (graph driver): sel matvecs →
10124    /// shared expert → mlp gate_write. Same kernels/order as the `moe_forward` grouped
10125    /// block; the selection indices/weights arrive via `moe_route_slots` into the baked
10126    /// slot addresses.
10127    fn moe_grouped_tail_slots(
10128        &self,
10129        e: &Engine,
10130        ws: &mut StepPool,
10131        ptrs: &CudaSlice<u64>,
10132        moe: &MoeW,
10133        planes: &mut [CudaSlice<f32>],
10134    ) -> Res<()> {
10135        let hidden = self.hidden;
10136        let ff = moe.plan.expert_intermediate_size as usize;
10137        let n_sel = moe.plan.experts_per_token as usize;
10138        let (
10139            BankHalf::Nvfp4 {
10140                codes: gc,
10141                scales: gs,
10142                macros_dev: gm,
10143                ..
10144            },
10145            BankHalf::Nvfp4 {
10146                codes: uc,
10147                scales: us,
10148                macros_dev: um,
10149                ..
10150            },
10151            BankHalf::Nvfp4 {
10152                codes: dc,
10153                scales: ds,
10154                macros_dev: dm,
10155                ..
10156            },
10157        ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
10158        else {
10159            return Err("qwen4exp_gpu: grouped tail on a non-NVFP4 bank".into());
10160        };
10161        let mixed = ws.take_f32(e, "hc.mixed", hidden, 0)?;
10162        let sel = ws
10163            .i32s
10164            .remove("moe.sel")
10165            .ok_or("step workspace: moe.sel is not parked")?;
10166        let w_dev = ws.take_f32(e, "moe.w", n_sel, 0)?;
10167        let mut act = ws.take_f32(e, "moe.act", n_sel * ff, 0)?;
10168        // Fused gate+up+silu (round 4): the graph bakes whichever arm is live at
10169        // capture (fresh state per A/B arm); bit-identical to the chain.
10170        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
10171            launch_nvfp4_sel_gu_silu(
10172                e,
10173                (gc, gs, gm),
10174                (uc, us, um),
10175                Some(&sel),
10176                0,
10177                n_sel,
10178                &mixed,
10179                &mut act,
10180                hidden,
10181                ff,
10182                None,
10183            )?;
10184        } else {
10185            let mut yg = ws.take_f32(e, "moe.yg", n_sel * ff, 0)?;
10186            let mut yu = ws.take_f32(e, "moe.yu", n_sel * ff, 0)?;
10187            launch_nvfp4_sel_matvec(e, gc, gs, gm, &sel, &mixed, &mut yg, n_sel, hidden, ff, 0)?;
10188            launch_nvfp4_sel_matvec(e, uc, us, um, &sel, &mixed, &mut yu, n_sel, hidden, ff, 0)?;
10189            e.silu_mul(&yg, &yu, &mut act, n_sel * ff)?;
10190            ws.put_f32("moe.yg", yg);
10191            ws.put_f32("moe.yu", yu);
10192        }
10193        let mut partial = ws.take_f32(e, "moe.partial", n_sel * hidden, 0)?;
10194        launch_nvfp4_sel_matvec(
10195            e,
10196            dc,
10197            ds,
10198            dm,
10199            &sel,
10200            &act,
10201            &mut partial,
10202            n_sel,
10203            ff,
10204            hidden,
10205            ff,
10206        )?;
10207        let mut out = ws.take_f32(e, "moe.out", hidden, 0)?;
10208        e.axpy_rows_seq_into(&partial, &w_dev, &mut out, hidden, n_sel)?;
10209        ws.put_i32("moe.sel", sel);
10210        ws.put_f32("moe.w", w_dev);
10211        ws.put_f32("moe.act", act);
10212        ws.put_f32("moe.partial", partial);
10213        let out = self.moe_shared_tail(e, ws, moe, &mixed, out, 1)?;
10214        ws.put_f32("hc.mixed", mixed);
10215        let inject = take_inject(e, ws, self.streams, 1)?;
10216        self.gate_write(e, planes, ptrs, &out, &inject, 1)?;
10217        ws.put_f32("moe.out", out);
10218        put_inject(ws, inject);
10219        Ok(())
10220    }
10221
10222    /// Graph-mode decode tail (item 2b): per layer, replay (or lazily capture) the
10223    /// interior graph, run the host routing boundary, replay the MoE-tail graph; then
10224    /// the exit graph and one logits dtoh. Falls back to the eager helpers per layer
10225    /// where a graph is structurally unavailable (QSA/PLE interiors — the indexer host
10226    /// twin and PLE host hashing live there; non-NVFP4 banks for the tail).
10227    fn forward_graphs_tail(
10228        &self,
10229        e: &Engine,
10230        state: &mut Qwen4ExpState,
10231        mut planes: Vec<CudaSlice<f32>>,
10232        ptrs: CudaSlice<u64>,
10233        base_pos: usize,
10234    ) -> Res<Vec<f32>> {
10235        let mut graphs = std::mem::take(&mut state.graphs);
10236        if graphs.a.len() != self.layers.len() {
10237            graphs.a = (0..self.layers.len()).map(|_| None).collect();
10238            graphs.b = (0..self.layers.len()).map(|_| None).collect();
10239        }
10240        let ws = &mut state.ws;
10241        let tokens = &state.tokens;
10242        for (li, (layer, lstate)) in self.layers.iter().zip(state.layers.iter_mut()).enumerate() {
10243            let a_ok = matches!(layer.mixer, MixerW::Gdn(_)) && layer.ple.is_none();
10244            if a_ok {
10245                if graphs.a[li].is_none() {
10246                    graphs.a[li] = Some(e.capture_graph_retained_nowarm(|eng| {
10247                        self.layer_interior(
10248                            eng,
10249                            ws,
10250                            &ptrs,
10251                            layer,
10252                            lstate,
10253                            &mut planes,
10254                            tokens,
10255                            base_pos,
10256                        )
10257                    })?);
10258                }
10259                graphs.a[li].as_ref().unwrap().0.launch()?;
10260            } else {
10261                self.layer_interior(e, ws, &ptrs, layer, lstate, &mut planes, tokens, base_pos)?;
10262            }
10263            let b_ok = moe_sel_path_on()
10264                && matches!(
10265                    (
10266                        &layer.moe.bank.gate,
10267                        &layer.moe.bank.up,
10268                        &layer.moe.bank.down
10269                    ),
10270                    (
10271                        BankHalf::Nvfp4 { .. },
10272                        BankHalf::Nvfp4 { .. },
10273                        BankHalf::Nvfp4 { .. }
10274                    )
10275                );
10276            if b_ok {
10277                self.moe_route_slots(e, ws, &layer.moe, layer.index)?;
10278                if graphs.b[li].is_none() {
10279                    graphs.b[li] = Some(e.capture_graph_retained_nowarm(|eng| {
10280                        self.moe_grouped_tail_slots(eng, ws, &ptrs, &layer.moe, &mut planes)
10281                    })?);
10282                }
10283                graphs.b[li].as_ref().unwrap().0.launch()?;
10284            } else {
10285                // Eager MoE (per-expert path routes internally) + mlp write.
10286                let mixed = ws.take_f32(e, "hc.mixed", self.hidden, 0)?;
10287                let mlp = self.moe_forward(e, ws, &layer.moe, &mixed, 1, false, layer.index)?;
10288                ws.put_f32("hc.mixed", mixed);
10289                let inject = take_inject(e, ws, self.streams, 1)?;
10290                self.gate_write(e, &mut planes, &ptrs, &mlp, &inject, 1)?;
10291                ws.put_f32("moe.out", mlp);
10292                put_inject(ws, inject);
10293            }
10294        }
10295        if graphs.exit.is_none() {
10296            graphs.exit = Some(e.capture_graph_retained_nowarm(|eng| {
10297                let x = self
10298                    .gate_read_inner(
10299                        eng,
10300                        ws,
10301                        &ptrs,
10302                        &self.exit_mixer,
10303                        &planes,
10304                        1,
10305                        self.exit_eps,
10306                        false,
10307                        false,
10308                    )?
10309                    .0;
10310                let mut logits = ws.take_f32(eng, "logits", self.vocab, 0)?;
10311                linear_trunk_into(
10312                    eng,
10313                    &self.output,
10314                    &self.output_b16,
10315                    &x,
10316                    &mut logits,
10317                    1,
10318                    self.hidden,
10319                    self.vocab,
10320                )?;
10321                ws.put_f32("hc.mixed", x);
10322                ws.put_f32("logits", logits);
10323                Ok(())
10324            })?);
10325        }
10326        graphs.exit.as_ref().unwrap().0.launch()?;
10327        let out = {
10328            let logits = ws.peek_f32("logits")?;
10329            e.dtoh_view(&logits.slice(0..self.vocab))?
10330        };
10331        for (s, plane) in planes.into_iter().enumerate() {
10332            ws.put_f32(PLANE_SLOTS[s], plane);
10333        }
10334        ws.put_u64("hc.ptrs", ptrs);
10335        state.pos += 1;
10336        state.graphs = graphs;
10337        Ok(out)
10338    }
10339
10340    /// QSA layer: fused [q|gate] projection, q/k RMSNorm, partial rope, KV append, the
10341    /// host indexer-selection twin, dense masked attention, sigmoid fused output gate.
10342    #[allow(clippy::too_many_arguments)]
10343    #[allow(clippy::too_many_arguments)]
10344    #[allow(clippy::too_many_arguments)]
10345
10346    /// Indexer update + selection for one chunk (factored from `qsa_forward` so the
10347    /// TP2 route shares it verbatim): idx projection, the idxcache device raw-key
10348    /// cache maintenance, host/pooled cache updates, the device-scorer selection, and
10349    /// the idxq audit twin. Returns per-row selections (`RowSel`).
10350    #[allow(clippy::too_many_arguments)]
10351    fn qsa_update_select(
10352        &self,
10353        e: &Engine,
10354        ws: &mut StepPool,
10355        qsa: &QsaW,
10356        eps: f32,
10357        mixed: &CudaSlice<f32>,
10358        raw_keys: &mut IdxRawCache,
10359        pooled_keys: &mut Vec<f32>,
10360        pooled_dev: &mut Option<CudaSlice<f32>>,
10361        pooled_dev_rows: &mut usize,
10362        raw_dev: &mut Option<IdxRawDev>,
10363        raw_dev_rows: &mut usize,
10364        mut idx_audit: Option<&mut Box<IdxAudit>>,
10365        base_pos: usize,
10366        t: usize,
10367        pos_off: usize,
10368        exact: bool,
10369    ) -> Res<Vec<RowSel>> {
10370        let hidden = self.hidden;
10371        let base = qsa.attn.rope.base;
10372        let t_kv = base_pos + t;
10373        // Indexer selection: host twin of micro_block_selection_mask over the raw-key cache.
10374        let overlay = &qsa.overlay;
10375        let idx_dim = overlay.head_dim as usize;
10376        let qk_width = (overlay.query_heads as usize + overlay.kv_heads as usize) * idx_dim;
10377        if overlay.kv_heads != 1 {
10378            return Err("qwen4exp_gpu: indexer with more than one key head".into());
10379        }
10380        let idx_proj = prof_section(e, "qsa.idx_proj", || {
10381            let mut idx_proj = ws.take_f32(e, "qsa.idxp", t * qk_width, 0)?;
10382            if exact && t > 1 {
10383                let wv = qsa.idx_proj.slice(0..qsa.idx_proj.len());
10384                for tok in 0..t {
10385                    let xv = mixed.slice(tok * hidden..(tok + 1) * hidden);
10386                    let mut yv = idx_proj.slice_mut(tok * qk_width..(tok + 1) * qk_width);
10387                    e.linear_device_into(&xv, &wv, &mut yv, 1, hidden, qk_width)?;
10388                }
10389            } else {
10390                e.linear_device_into(mixed, &qsa.idx_proj, &mut idx_proj, t, hidden, qk_width)?;
10391            }
10392            Ok(idx_proj)
10393        })?;
10394        // Device raw-key cache (devtwin stage 3, `idxcache`): row r of `raw_dev` is
10395        // absolute cache row r. Below the selection horizon ((base_pos + t)/block <=
10396        // budget — the indexer_select_rows fast path, decided from positions alone)
10397        // the selection needs NO device data, so the k-part rows append d2d and the
10398        // idx_proj dtoh dies; the host cache lags and materializes LAZILY at the first
10399        // scored chunk — the same bytes dtoh'd later, bit-identical by construction.
10400        // Mid-run seam flips on a live state pay their debt loudly here: OFF->ON
10401        // backfills the device from the host (h2d, exact bytes); any host lag is paid
10402        // BEFORE this chunk lands whenever the fast path does not take it.
10403        let dev_cache = idx_cache_on();
10404        let block_size = overlay.block_size as usize;
10405        let all_full = (base_pos + t) / block_size <= overlay.budget_blocks as usize;
10406        let host_rows = raw_keys.rows(idx_dim);
10407        if *raw_dev_rows > host_rows && !(dev_cache && all_full) {
10408            // Lazy host materialization (or an ON->OFF flip's debt): dtoh the delta
10409            // VERBATIM — quantized formats materialize their own bytes, no re-quant,
10410            // so the seam's bit-identity contract is preserved per format.
10411            idx_materialize_host(e, raw_keys, raw_dev, *raw_dev_rows, idx_dim)?;
10412        }
10413        if dev_cache {
10414            let host_rows = raw_keys.rows(idx_dim);
10415            let base_rows = (*raw_dev_rows).max(host_rows);
10416            let cap_rows = (base_rows + t).next_power_of_two().max(64);
10417            let q_off = overlay.query_heads as usize * idx_dim;
10418            match &mut *raw_keys {
10419                IdxRawCache::F32(h) => {
10420                    let want = (base_rows + t) * idx_dim;
10421                    let grow = match raw_dev.as_ref() {
10422                        Some(IdxRawDev::F32(m)) => m.len() < want,
10423                        Some(_) => return Err("idxcache: device format lag on f32".into()),
10424                        None => true,
10425                    };
10426                    if grow {
10427                        let mut fresh = e.uninit(cap_rows * idx_dim)?;
10428                        if let (Some(IdxRawDev::F32(old)), rows) = (raw_dev.as_ref(), *raw_dev_rows)
10429                        {
10430                            if rows > 0 {
10431                                e.copy_range_into(&mut fresh, 0, old, 0, rows * idx_dim)?;
10432                            }
10433                        }
10434                        *raw_dev = Some(IdxRawDev::F32(fresh));
10435                    }
10436                    let Some(IdxRawDev::F32(m)) = raw_dev.as_mut() else {
10437                        unreachable!("allocated above");
10438                    };
10439                    if host_rows > *raw_dev_rows {
10440                        // OFF->ON flip on a live state: backfill the device from host.
10441                        let mut view = m.slice_mut(*raw_dev_rows * idx_dim..host_rows * idx_dim);
10442                        e.gpu
10443                            .stream()
10444                            .memcpy_htod(&h[*raw_dev_rows * idx_dim..], &mut view)?;
10445                        *raw_dev_rows = host_rows;
10446                    }
10447                    launch_copy_rows_col(
10448                        e,
10449                        &idx_proj,
10450                        m,
10451                        t,
10452                        idx_dim,
10453                        qk_width,
10454                        q_off,
10455                        *raw_dev_rows,
10456                    )?;
10457                }
10458                IdxRawCache::Q8(h) => {
10459                    let rb = q8_row_bytes(idx_dim);
10460                    let want = (base_rows + t) * rb;
10461                    let grow = match raw_dev.as_ref() {
10462                        Some(IdxRawDev::Q8(m)) => m.len() < want,
10463                        Some(_) => return Err("idxcache: device format lag on q8".into()),
10464                        None => true,
10465                    };
10466                    if grow {
10467                        let mut fresh = e.alloc_u8_uninit(cap_rows * rb)?;
10468                        if let (Some(IdxRawDev::Q8(old)), rows) = (raw_dev.as_ref(), *raw_dev_rows)
10469                        {
10470                            if rows > 0 {
10471                                let mut dst = fresh.slice_mut(0..rows * rb);
10472                                e.gpu
10473                                    .stream()
10474                                    .memcpy_dtod(&old.slice(0..rows * rb), &mut dst)?;
10475                            }
10476                        }
10477                        *raw_dev = Some(IdxRawDev::Q8(fresh));
10478                    }
10479                    let Some(IdxRawDev::Q8(m)) = raw_dev.as_mut() else {
10480                        unreachable!("allocated above");
10481                    };
10482                    if host_rows > *raw_dev_rows {
10483                        let mut view = m.slice_mut(*raw_dev_rows * rb..host_rows * rb);
10484                        e.gpu
10485                            .stream()
10486                            .memcpy_htod(&h[*raw_dev_rows * rb..host_rows * rb], &mut view)?;
10487                        *raw_dev_rows = host_rows;
10488                    }
10489                    launch_q4e_idx_append_q8(
10490                        e,
10491                        &idx_proj,
10492                        m,
10493                        t,
10494                        idx_dim,
10495                        qk_width,
10496                        q_off,
10497                        *raw_dev_rows,
10498                    )?;
10499                }
10500                IdxRawCache::Bf16(h) => {
10501                    let want = (base_rows + t) * idx_dim;
10502                    let grow = match raw_dev.as_ref() {
10503                        Some(IdxRawDev::Bf16(m)) => m.len() < want,
10504                        Some(_) => return Err("idxcache: device format lag on bf16".into()),
10505                        None => true,
10506                    };
10507                    if grow {
10508                        let mut fresh = unsafe { e.gpu.stream().alloc::<u16>(cap_rows * idx_dim)? };
10509                        if let (Some(IdxRawDev::Bf16(old)), rows) =
10510                            (raw_dev.as_ref(), *raw_dev_rows)
10511                        {
10512                            if rows > 0 {
10513                                let mut dst = fresh.slice_mut(0..rows * idx_dim);
10514                                e.gpu
10515                                    .stream()
10516                                    .memcpy_dtod(&old.slice(0..rows * idx_dim), &mut dst)?;
10517                            }
10518                        }
10519                        *raw_dev = Some(IdxRawDev::Bf16(fresh));
10520                    }
10521                    let Some(IdxRawDev::Bf16(m)) = raw_dev.as_mut() else {
10522                        unreachable!("allocated above");
10523                    };
10524                    if host_rows > *raw_dev_rows {
10525                        let mut view = m.slice_mut(*raw_dev_rows * idx_dim..host_rows * idx_dim);
10526                        e.gpu.stream().memcpy_htod(
10527                            &h[*raw_dev_rows * idx_dim..host_rows * idx_dim],
10528                            &mut view,
10529                        )?;
10530                        *raw_dev_rows = host_rows;
10531                    }
10532                    launch_q4e_idx_append_bf16(
10533                        e,
10534                        &idx_proj,
10535                        m,
10536                        t,
10537                        idx_dim,
10538                        qk_width,
10539                        q_off,
10540                        *raw_dev_rows,
10541                    )?;
10542                }
10543            }
10544            *raw_dev_rows += t;
10545        }
10546        // idxq selection-identity audit (instrument): the f32 twin cache is fed on
10547        // EVERY chunk — this re-adds the idx_proj dtoh the idxcache seam removed, and
10548        // is never a perf arm. Fed BEFORE selection so the twin includes this chunk.
10549        if let Some(audit) = idx_audit.as_deref_mut() {
10550            let q_off = overlay.query_heads as usize * idx_dim;
10551            let rows_f = e.dtoh_view(&idx_proj.slice(0..t * qk_width))?;
10552            let IdxRawCache::F32(twin) = &mut audit.raw_f32 else {
10553                return Err("idxq audit: twin cache is not f32".into());
10554            };
10555            for row in 0..t {
10556                twin.extend_from_slice(&rows_f[row * qk_width + q_off..(row + 1) * qk_width]);
10557            }
10558        }
10559        let sels: Vec<RowSel> = if dev_cache && all_full {
10560            ws.put_f32("qsa.idxp", idx_proj);
10561            (0..t)
10562                .map(|qt| RowSel {
10563                    full: true,
10564                    blocks: Vec::new(),
10565                    visible: base_pos + qt + 1,
10566                })
10567                .collect()
10568        } else {
10569            let idx_rows = e.dtoh_view(&idx_proj.slice(0..t * qk_width))?;
10570            ws.put_f32("qsa.idxp", idx_proj);
10571            let q_off = overlay.query_heads as usize * idx_dim;
10572            for row in 0..t {
10573                raw_keys.append_rows_f32(
10574                    &idx_rows[row * qk_width + q_off..(row + 1) * qk_width],
10575                    1,
10576                    idx_dim,
10577                );
10578            }
10579            // Device block scorer (long-context lane): the host twin is O(context) per
10580            // token per layer — 52% of the decode token at a 32k fill (smoke ladder),
10581            // and quadratic across a long prefill. Scores are bit-identical (same
10582            // arithmetic order), so the selection is the same set. `idx_dev` (default
10583            // ON) is the rollback seam; the host twin remains the reference and the
10584            // TP2 path.
10585            let dev_scorer = idx_dev_on();
10586            let sels = prof_section(e, "qsa.idx_host", || {
10587                indexer_select_rows(
10588                    overlay,
10589                    base,
10590                    qsa.yarn.as_ref().map(|y| (y.ff_host.as_slice(), y.mscale)),
10591                    eps,
10592                    &qsa.idx_q_norm,
10593                    &qsa.idx_k_norm,
10594                    &idx_rows,
10595                    raw_keys,
10596                    pooled_keys,
10597                    if dev_scorer {
10598                        Some((e, pooled_dev, pooled_dev_rows))
10599                    } else {
10600                        None
10601                    },
10602                    base_pos,
10603                    t,
10604                    t_kv,
10605                    pos_off,
10606                )
10607            })?;
10608            // Audit compare: recompute every scored row's selection from the f32 twin
10609            // caches (host scorer) and count flipped sets. Full rows cannot flip (the
10610            // structural fast path reads no scores) and are skipped. BOUNDED to
10611            // decode/draft/verify shapes (t <= 8): a prefill chunk would pay the
10612            // O(context) host selection PER ROW x 2048 rows x every chunk — quadratic
10613            // across a long prefill, the exact cost the device scorer retired. Prefill
10614            // chunks still FEED the twin (above); the twin's pooled cache catches up
10615            // lazily inside its next compare. Stated in the receipt: the flip rate is
10616            // measured on decode/verify rows at depth.
10617            if let Some(audit) = idx_audit.as_deref_mut() {
10618                if t <= 8 && sels.iter().any(|s| !s.full) {
10619                    let twin_sels = indexer_select_rows(
10620                        overlay,
10621                        base,
10622                        qsa.yarn.as_ref().map(|y| (y.ff_host.as_slice(), y.mscale)),
10623                        eps,
10624                        &qsa.idx_q_norm,
10625                        &qsa.idx_k_norm,
10626                        &idx_rows,
10627                        &audit.raw_f32,
10628                        &mut audit.pooled_f32,
10629                        None,
10630                        base_pos,
10631                        t,
10632                        t_kv,
10633                        pos_off,
10634                    )?;
10635                    use std::sync::atomic::Ordering::Relaxed;
10636                    for (a, b) in sels.iter().zip(&twin_sels) {
10637                        if a.full && b.full {
10638                            continue;
10639                        }
10640                        IDXQ_AUDIT_ROWS.fetch_add(1, Relaxed);
10641                        if a.full != b.full || a.blocks != b.blocks {
10642                            IDXQ_AUDIT_FLIPPED.fetch_add(1, Relaxed);
10643                            let mut diff = 0u64;
10644                            let (sa, sb) = (&a.blocks, &b.blocks);
10645                            let seta: std::collections::BTreeSet<_> = sa.iter().collect();
10646                            let setb: std::collections::BTreeSet<_> = sb.iter().collect();
10647                            diff += seta.symmetric_difference(&setb).count() as u64;
10648                            IDXQ_AUDIT_BLOCKS.fetch_add(diff, Relaxed);
10649                        }
10650                    }
10651                }
10652            }
10653            sels
10654        };
10655        Ok(sels)
10656    }
10657
10658    fn qsa_forward(
10659        &self,
10660        e: &Engine,
10661        ws: &mut StepPool,
10662        layer: &LayerW,
10663        qsa: &QsaW,
10664        mixed: &CudaSlice<f32>,
10665        mstate: &mut MixerState,
10666        base_pos: usize,
10667        t: usize,
10668        // Rope/indexer position offset (0 = trunk; 1 = the MTP draft, see
10669        // `indexer_mask_rows`). Causality stays cache-row based either way.
10670        pos_off: usize,
10671        // Verify-exact rows (mtp-spec): per-token indexer-projection launches — the
10672        // one cuBLASLt op in this path whose m > 1 algorithm may differ from the
10673        // decode-shape GEMV; m == 1 per token keeps rows bit-identical to decode.
10674        exact: bool,
10675    ) -> Res<CudaSlice<f32>> {
10676        let MixerState::Qsa {
10677            kv,
10678            raw_keys,
10679            pooled_keys,
10680            pooled_dev,
10681            pooled_dev_rows,
10682            raw_dev,
10683            raw_dev_rows,
10684            idx_audit,
10685        } = mstate
10686        else {
10687            return Err(format!(
10688                "qwen4exp_gpu: QSA layer {} bound to non-QSA state",
10689                layer.index
10690            )
10691            .into());
10692        };
10693        let hidden = self.hidden;
10694        let nh = qsa.attn.query_heads as usize;
10695        let nkv = qsa.attn.kv_heads as usize;
10696        let hd = qsa.attn.key_head_dim as usize;
10697        let eps = layer.eps_attn;
10698        // Mask-slot reserve: [t, capacity] never grows mid-run (t_kv does, every step).
10699        let cap = kv.capacity_rows(nkv * hd);
10700
10701        let n_rot = qsa.attn.rope.dimensions as usize;
10702        let base = qsa.attn.rope.base;
10703        let (q, gate) = prof_section(e, "qsa.proj", || {
10704            let mut q_fused = ws.take_f32(e, "qsa.qf", t * 2 * nh * hd, 0)?;
10705            let mut k_new = ws.take_f32(e, "qsa.k", t * nkv * hd, 0)?;
10706            let mut v_new = ws.take_f32(e, "qsa.v", t * nkv * hd, 0)?;
10707            // Proj stack (round 4): wq/wk/wv in ONE launch over the row-stacked twin;
10708            // per-row bit-identical to the per-mat launches (OFF arm = row-offset views
10709            // of the same stack).
10710            if let (true, Some(stack)) = (
10711                t == 1 && proj_stack_on() && trunk_bf16_on(),
10712                qsa.proj_b16.as_ref(),
10713            ) {
10714                launch_qmatvec_bf16w_multi4(
10715                    e,
10716                    stack,
10717                    mixed,
10718                    &[
10719                        (&q_fused, 2 * nh * hd),
10720                        (&k_new, nkv * hd),
10721                        (&v_new, nkv * hd),
10722                    ],
10723                    hidden,
10724                )?;
10725            } else {
10726                linear_trunk_stacked_into(
10727                    e,
10728                    &qsa.wq,
10729                    &qsa.proj_b16,
10730                    0,
10731                    mixed,
10732                    &mut q_fused,
10733                    t,
10734                    hidden,
10735                    2 * nh * hd,
10736                )?;
10737                linear_trunk_stacked_into(
10738                    e,
10739                    &qsa.wk,
10740                    &qsa.proj_b16,
10741                    2 * nh * hd,
10742                    mixed,
10743                    &mut k_new,
10744                    t,
10745                    hidden,
10746                    nkv * hd,
10747                )?;
10748                linear_trunk_stacked_into(
10749                    e,
10750                    &qsa.wv,
10751                    &qsa.proj_b16,
10752                    2 * nh * hd + nkv * hd,
10753                    mixed,
10754                    &mut v_new,
10755                    t,
10756                    hidden,
10757                    nkv * hd,
10758                )?;
10759            }
10760            let mut q = ws.take_f32(e, "qsa.q", t * nh * hd, 0)?;
10761            let mut gate = ws.take_f32(e, "qsa.gate", t * nh * hd, 0)?;
10762            e.q_gate_split(&q_fused, &mut q, &mut gate, hd, nh, t)?;
10763            ws.put_f32("qsa.qf", q_fused);
10764            let mut q = if let Some(norm) = qsa.q_norm.as_ref() {
10765                let mut dst = ws.take_f32(e, "qsa.qn", t * nh * hd, 0)?;
10766                e.rms_norm(&q, norm, &mut dst, hd, t * nh, eps)?;
10767                ws.put_f32("qsa.q", q);
10768                dst
10769            } else {
10770                q
10771            };
10772            let mut k_new = if let Some(norm) = qsa.k_norm.as_ref() {
10773                let mut dst = ws.take_f32(e, "qsa.kn", t * nkv * hd, 0)?;
10774                e.rms_norm(&k_new, norm, &mut dst, hd, t * nkv, eps)?;
10775                ws.put_f32("qsa.k", k_new);
10776                dst
10777            } else {
10778                k_new
10779            };
10780            let positions: Vec<i32> = (0..t).map(|i| (base_pos + i + pos_off) as i32).collect();
10781            let pos_dev = ws.take_i32(e, "qsa.pos", &positions, 0)?;
10782            if let Some(yarn) = qsa.yarn.as_ref() {
10783                e.rope_neox_ffm(
10784                    &mut q,
10785                    &pos_dev,
10786                    hd,
10787                    n_rot,
10788                    nh,
10789                    t,
10790                    base,
10791                    1.0,
10792                    &yarn.ff,
10793                    yarn.mscale,
10794                )?;
10795                e.rope_neox_ffm(
10796                    &mut k_new,
10797                    &pos_dev,
10798                    hd,
10799                    n_rot,
10800                    nkv,
10801                    t,
10802                    base,
10803                    1.0,
10804                    &yarn.ff,
10805                    yarn.mscale,
10806                )?;
10807            } else {
10808                e.rope_neox(&mut q, &pos_dev, hd, n_rot, nh, t, base, 1.0)?;
10809                e.rope_neox(&mut k_new, &pos_dev, hd, n_rot, nkv, t, base, 1.0)?;
10810            }
10811            ws.put_i32("qsa.pos", pos_dev);
10812            // Explicit lengths: workspace slots may be larger than this chunk.
10813            match kv {
10814                QsaKvStore::F32 { k, v } => {
10815                    e.copy_range_into(k, base_pos * nkv * hd, &k_new, 0, t * nkv * hd)?;
10816                    e.copy_range_into(v, base_pos * nkv * hd, &v_new, 0, t * nkv * hd)?;
10817                }
10818                // kvq lane: append-quantize the post-RoPE rows in place (K=q8_0,
10819                // V=q5_1) — same slot addressing, no host round trip.
10820                QsaKvStore::Q8Q5 { k, v } => {
10821                    launch_q4e_kv_append(e, &k_new, &v_new, k, v, base_pos, t, nkv * hd)?;
10822                }
10823            }
10824            ws.put_f32(
10825                if qsa.k_norm.is_some() {
10826                    "qsa.kn"
10827                } else {
10828                    "qsa.k"
10829                },
10830                k_new,
10831            );
10832            ws.put_f32("qsa.v", v_new);
10833            Ok((q, gate))
10834        })?;
10835        let t_kv = base_pos + t;
10836        let sels = self.qsa_update_select(
10837            e,
10838            ws,
10839            qsa,
10840            eps,
10841            mixed,
10842            raw_keys,
10843            pooled_keys,
10844            pooled_dev,
10845            pooled_dev_rows,
10846            raw_dev,
10847            raw_dev_rows,
10848            idx_audit.as_mut(),
10849            base_pos,
10850            t,
10851            pos_off,
10852            exact,
10853        )?;
10854        let overlay = &qsa.overlay;
10855
10856        let scale = match qsa.attn.scale {
10857            memra_gguf::model_plan::AttentionScale::InverseSqrtKeyDim => 1.0 / (hd as f32).sqrt(),
10858            memra_gguf::model_plan::AttentionScale::Fixed(scale) => scale,
10859        };
10860        // Long-context attention form: past the masked kernel's smem bound the dense
10861        // [t, t_kv] mask is impossible (bytes scale with context), so the block-list
10862        // kernel consumes the selection directly — BIT-IDENTICAL math (the masked
10863        // kernel's -1e30 rows contribute exact 0.0 terms in the same ascending order;
10864        // gate arm `fixture-longatt` + the blocklist kernel oracle).
10865        //
10866        // AUTO engages when the block-list form reads STRICTLY FEWER KV rows than the
10867        // dense form — i.e. as soon as the indexer actually drops blocks (any non-full
10868        // row, which on real geometry means position >= 2051) — and always past the
10869        // masked kernel's smem bound. This is where QSA's bounded-attention claim
10870        // becomes real: the dense mask still READS every t_kv row (the mask only zeroes
10871        // scores), so masked decode is O(context) bytes, while the block-list form reads
10872        // the <= 2052 selected rows at ANY depth. Measured motivation (smoke ladder,
10873        // yarn-1M, KV on card 1): masked decode at a 4k fill spent 97% of the token in
10874        // `qsa.sdpa` at 673 ms/token. Below the drop point every row IS the full prefix,
10875        // so the two forms read the same rows and AUTO keeps the historical masked path
10876        // (byte-stable receipts). `MEMRA_Q4E_SEAMS=longatt` forces it for the gate A/B;
10877        // `longatt=0` restores the masked-only behavior (and its long-context refusal).
10878        // kvq lane: the quantized cache has no masked-kernel form — the block-list
10879        // program (with in-place dequant) is the ONLY read path, at every depth. Below
10880        // the drop point every row is the full prefix, so the block-list form reads the
10881        // same rows the masked kernel would; there is no byte-stability question because
10882        // a quantized state has no historical masked receipts.
10883        let long_att = if kv.is_quant() {
10884            if longatt_mode() == LongAttMode::Off {
10885                return Err(
10886                    "qwen4exp_gpu: kvq requires the block-list attention form (longatt=off)".into(),
10887                );
10888            }
10889            true
10890        } else {
10891            match longatt_mode() {
10892                LongAttMode::Force => true,
10893                LongAttMode::Auto => t_kv > SDPA_MASK_TKV_BOUND || sels.iter().any(|s| !s.full),
10894                LongAttMode::Off => false,
10895            }
10896        };
10897        let block_size = overlay.block_size as usize;
10898        let attended = if long_att {
10899            let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
10900            let pos_dev = prof_section(e, "qsa.mask_h2d", || {
10901                ws.take_i32(e, "qsa.selpos", &pos_flat, 0)
10902            })?;
10903            let meta_dev = ws.take_i32(e, "qsa.selmeta", &meta, 0)?;
10904            let attended = prof_section(e, "qsa.sdpa", || {
10905                let mut attended = ws.take_f32(e, "qsa.att", t * nh * hd, 0)?;
10906                match kv {
10907                    QsaKvStore::F32 { k, v } => {
10908                        let k_view = k.slice(0..t_kv * nkv * hd);
10909                        let v_view = v.slice(0..t_kv * nkv * hd);
10910                        launch_sdpa_blocklist(
10911                            e,
10912                            &q,
10913                            &k_view,
10914                            &v_view,
10915                            &mut attended,
10916                            &pos_dev,
10917                            &meta_dev,
10918                            hd,
10919                            nh,
10920                            nkv,
10921                            t,
10922                            max_count,
10923                            scale,
10924                        )?;
10925                    }
10926                    QsaKvStore::Q8Q5 { k, v } => {
10927                        launch_q4e_sdpa_blocklist_q8q5(
10928                            e,
10929                            &q,
10930                            k,
10931                            v,
10932                            &mut attended,
10933                            &pos_dev,
10934                            &meta_dev,
10935                            hd,
10936                            nh,
10937                            nkv,
10938                            t,
10939                            max_count,
10940                            scale,
10941                        )?;
10942                    }
10943                }
10944                Ok(attended)
10945            })?;
10946            ws.put_i32("qsa.selpos", pos_dev);
10947            ws.put_i32("qsa.selmeta", meta_dev);
10948            attended
10949        } else {
10950            let QsaKvStore::F32 { k, v } = &*kv else {
10951                return Err("qwen4exp_gpu: masked SDPA reached with a quantized cache".into());
10952            };
10953            let mask = rowsel_to_mask(&sels, block_size, t_kv);
10954            let mask_dev = prof_section(e, "qsa.mask_h2d", || {
10955                // Masked-kernel rows never exceed the smem bound, so the slot reserve is
10956                // bounded even on a long-context-capacity state.
10957                ws.take_u8_h2d(e, "qsa.mask", &mask, t * cap.min(SDPA_MASK_TKV_BOUND))
10958            })?;
10959            let attended = prof_section(e, "qsa.sdpa", || {
10960                let mut attended = ws.take_f32(e, "qsa.att", t * nh * hd, 0)?;
10961                let k_view = k.slice(0..t_kv * nkv * hd);
10962                let v_view = v.slice(0..t_kv * nkv * hd);
10963                launch_sdpa_mask(
10964                    e,
10965                    &q,
10966                    &k_view,
10967                    &v_view,
10968                    &mut attended,
10969                    &mask_dev,
10970                    hd,
10971                    nh,
10972                    nkv,
10973                    t,
10974                    t_kv,
10975                    scale,
10976                )?;
10977                Ok(attended)
10978            })?;
10979            ws.put_u8("qsa.mask", mask_dev);
10980            attended
10981        };
10982        ws.put_f32(
10983            if qsa.q_norm.is_some() {
10984                "qsa.qn"
10985            } else {
10986                "qsa.q"
10987            },
10988            q,
10989        );
10990        let out = prof_section(e, "qsa.gate_wo", || {
10991            // fused per-(head, dim) sigmoid output gate (family convention).
10992            let mut sg = ws.take_f32(e, "qsa.sg", t * nh * hd, 0)?;
10993            e.sigmoid(&gate, &mut sg, t * nh * hd)?;
10994            let mut gated = ws.take_f32(e, "qsa.gated", t * nh * hd, 0)?;
10995            e.mul(&attended, &sg, &mut gated, t * nh * hd)?;
10996            let mut out = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
10997            linear_trunk_into(
10998                e,
10999                &qsa.wo,
11000                &qsa.wo_b16,
11001                &gated,
11002                &mut out,
11003                t,
11004                nh * hd,
11005                hidden,
11006            )?;
11007            ws.put_f32("qsa.sg", sg);
11008            ws.put_f32("qsa.gated", gated);
11009            Ok(out)
11010        })?;
11011        ws.put_f32("qsa.att", attended);
11012        ws.put_f32("qsa.gate", gate);
11013        Ok(out)
11014    }
11015
11016    /// GDN layer (`gated_delta_net` twin): fused qkv/z/beta/alpha projections, causal
11017    /// conv (dilation 1, silu) over cached raw rows, the geometry-generic sequential scan,
11018    /// gated RMSNorm with the family's SIGMOID z-gate (SEMANTICS.md §GDN).
11019    #[allow(clippy::too_many_arguments)]
11020    fn gdn_forward(
11021        &self,
11022        e: &Engine,
11023        ws: &mut StepPool,
11024        layer: &LayerW,
11025        gdn: &GdnW,
11026        mixed: &CudaSlice<f32>,
11027        mstate: &mut MixerState,
11028        t: usize,
11029        // Verify-exact stash (mtp-spec): Some => per-token scan (each column the t == 1
11030        // decode kernel dispatch, bit-identical) + per-column state snapshots + the
11031        // chunk's conv-rewind inputs.
11032        mut stash: Option<&mut GdnStash>,
11033    ) -> Res<CudaSlice<f32>> {
11034        let MixerState::Gdn { conv, state } = mstate else {
11035            return Err(format!(
11036                "qwen4exp_gpu: GDN layer {} bound to non-GDN state",
11037                layer.index
11038            )
11039            .into());
11040        };
11041        let hidden = self.hidden;
11042        let p = &gdn.plan;
11043        let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
11044        let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
11045        let kernel = p.conv_kernel as usize;
11046        let pad = kernel - 1;
11047        let conv_dim = 2 * nk * hk + nv * hv;
11048        let eps = layer.eps_attn;
11049
11050        let (qkv, z, beta_raw, g_log) = prof_section(e, "gdn.proj", || {
11051            let mut qkv = ws.take_f32(e, "gdn.qkv", t * conv_dim, 0)?;
11052            let mut z = ws.take_f32(e, "gdn.z", t * nv * hv, 0)?;
11053            let mut beta_raw = ws.take_f32(e, "gdn.beta", t * nv, 0)?;
11054            let mut alpha = ws.take_f32(e, "gdn.alpha", t * nv, 0)?;
11055            // Proj stack (round 4): the 4 same-activation projections in ONE launch over
11056            // the row-stacked twin; per-row bit-identical to the per-mat launches (the
11057            // OFF arm reads row-offset views of the SAME stack — same bytes, same
11058            // kernel, VRAM-neutral residency).
11059            if let (true, Some(stack)) = (
11060                t == 1 && proj_stack_on() && trunk_bf16_on(),
11061                gdn.proj_b16.as_ref(),
11062            ) {
11063                launch_qmatvec_bf16w_multi4(
11064                    e,
11065                    stack,
11066                    mixed,
11067                    &[
11068                        (&qkv, conv_dim),
11069                        (&z, nv * hv),
11070                        (&beta_raw, nv),
11071                        (&alpha, nv),
11072                    ],
11073                    hidden,
11074                )?;
11075            } else {
11076                linear_trunk_stacked_into(
11077                    e,
11078                    &gdn.qkv,
11079                    &gdn.proj_b16,
11080                    0,
11081                    mixed,
11082                    &mut qkv,
11083                    t,
11084                    hidden,
11085                    conv_dim,
11086                )?;
11087                linear_trunk_stacked_into(
11088                    e,
11089                    &gdn.z,
11090                    &gdn.proj_b16,
11091                    conv_dim,
11092                    mixed,
11093                    &mut z,
11094                    t,
11095                    hidden,
11096                    nv * hv,
11097                )?;
11098                linear_trunk_stacked_into(
11099                    e,
11100                    &gdn.beta,
11101                    &gdn.proj_b16,
11102                    conv_dim + nv * hv,
11103                    mixed,
11104                    &mut beta_raw,
11105                    t,
11106                    hidden,
11107                    nv,
11108                )?;
11109                linear_trunk_stacked_into(
11110                    e,
11111                    &gdn.alpha,
11112                    &gdn.proj_b16,
11113                    conv_dim + nv * hv + nv,
11114                    mixed,
11115                    &mut alpha,
11116                    t,
11117                    hidden,
11118                    nv,
11119                )?;
11120            }
11121            let mut g_log = ws.take_f32(e, "gdn.glog", t * nv, 0)?;
11122            e.gdn_glog_v(&alpha.slice(0..t * nv), &gdn.dt, &gdn.a, &mut g_log, nv, t)?;
11123            ws.put_f32("gdn.alpha", alpha);
11124            Ok((qkv, z, beta_raw, g_log))
11125        })?;
11126
11127        let o = prof_section(e, "gdn.conv_scan", || {
11128            // Verify stash: the pre-chunk conv history + the chunk's raw rows are the
11129            // rewind rebuild inputs (pure retains — no kernel sees them). Kept OUTSIDE the
11130            // segment graph: they are the only part whose destination is the stash itself.
11131            if let Some(st) = stash.as_deref_mut() {
11132                e.copy_range_into(&mut st.conv_pre, 0, conv, 0, pad * conv_dim)?;
11133                e.copy_range_into(&mut st.qkv_rows, 0, &qkv, 0, t * conv_dim)?;
11134            }
11135            // Slots are taken (and so ALLOCATED, if this is their first use) before any
11136            // capture region opens; addresses are stable from here on.
11137            let mut conv_out = ws.take_f32(e, "gdn.conv_out", t * conv_dim, 0)?;
11138            let mut o = ws.take_f32(e, "gdn.o", t * nv * hv, 0)?;
11139            let mut tmp = if t >= pad {
11140                None
11141            } else {
11142                Some(ws.take_f32(e, "gdn.tmp", (pad - t) * conv_dim, 0)?)
11143            };
11144            let scale = 1.0 / (hk as f32).sqrt();
11145            let step_ok = gdn_step_on() && hk % 32 == 0 && hk <= 1024;
11146            // The dwconv -> per-column scan -> conv-history roll chain, as ONE callable
11147            // unit so the eager arm and the captured arm run the IDENTICAL launch
11148            // sequence (the graph A/B's bit-identity is by construction, not by review).
11149            //
11150            // Decode-step twin (perf round 3): one state element per thread instead of
11151            // one state row — geometry guard keeps the tiny plan (hk 4) on the naive
11152            // kernel; prefill (t > 1) always takes the naive sequential scan. VERIFY
11153            // chunks (stash Some) run per-token launches of the SAME dispatch decode
11154            // takes (step when the guard admits, else naive-at-1) with a per-column
11155            // state snapshot after each token — the rewind checkpoints.
11156            let chain = |eng: &Engine,
11157                         conv: &mut CudaSlice<f32>,
11158                         state: &mut CudaSlice<f32>,
11159                         states_snap: Option<&mut CudaSlice<f32>>,
11160                         conv_out: &mut CudaSlice<f32>,
11161                         o: &mut CudaSlice<f32>,
11162                         tmp: Option<&mut CudaSlice<f32>>|
11163             -> Res<()> {
11164                launch_dwconv(
11165                    eng,
11166                    &qkv,
11167                    conv,
11168                    &gdn.conv_w,
11169                    conv_out,
11170                    t,
11171                    pad,
11172                    conv_dim,
11173                    kernel,
11174                    1,
11175                    1,
11176                )?;
11177                match states_snap {
11178                    Some(states) => {
11179                        let state_len = nv * hv * hk;
11180                        for tok in 0..t {
11181                            if step_ok {
11182                                launch_gdn_scan_step_at(
11183                                    eng, conv_out, &g_log, &beta_raw, state, o, tok, nk, nv, hk,
11184                                    hv, scale, eps,
11185                                )?;
11186                            } else {
11187                                launch_gdn_scan_at(
11188                                    eng, conv_out, &g_log, &beta_raw, state, o, tok, nk, nv, hk,
11189                                    hv, scale, eps,
11190                                )?;
11191                            }
11192                            eng.copy_range_into(states, tok * state_len, state, 0, state_len)?;
11193                        }
11194                    }
11195                    None if t == 1 && step_ok => {
11196                        launch_gdn_scan_step(
11197                            eng, conv_out, &g_log, &beta_raw, state, o, nk, nv, hk, hv, scale, eps,
11198                        )?;
11199                    }
11200                    None => {
11201                        launch_gdn_scan(
11202                            eng, conv_out, &g_log, &beta_raw, state, o, nk, nv, hk, hv, t, scale,
11203                            eps,
11204                        )?;
11205                    }
11206                }
11207                // conv history <- last `pad` raw qkv rows (zeros keep their place when
11208                // t < pad).
11209                if t >= pad {
11210                    eng.copy_range_into(conv, 0, &qkv, (t - pad) * conv_dim, pad * conv_dim)?;
11211                } else {
11212                    let keep = pad - t;
11213                    let tmp = tmp.ok_or("qwen4exp_gpu: gdn conv roll needs the tmp slot")?;
11214                    eng.copy_range_into(tmp, 0, conv, t * conv_dim, keep * conv_dim)?;
11215                    eng.copy_range_into(conv, 0, tmp, 0, keep * conv_dim)?;
11216                    eng.copy_range_into(conv, keep * conv_dim, &qkv, 0, t * conv_dim)?;
11217                }
11218                Ok(())
11219            };
11220            // Segment graph (mtp9, default OFF): only the verify shape is graphed — plain
11221            // decode already has its own whole-interior graph, and prefill shapes vary.
11222            let graphable = stash.is_some() && verify_graphs_on() && step_ws_on() && !prof::on();
11223            match stash.as_deref_mut() {
11224                Some(st) if graphable => {
11225                    // Take the graph out so the snapshot buffer can be borrowed mutably.
11226                    // A different chunk width invalidates the capture (baked shapes).
11227                    let entry = match st.scan_graph.take() {
11228                        Some((gt, g)) if gt == t => Some(g),
11229                        _ => None,
11230                    };
11231                    let warm = st.scan_warm == Some(t);
11232                    st.scan_warm = Some(t);
11233                    // EXACTLY ONE of the three arms executes the chain once.
11234                    let entry = match (warm, entry) {
11235                        // First chunk at this width: eager, so every slot is allocated
11236                        // and parked before any capture region opens.
11237                        (false, _) => {
11238                            chain(
11239                                e,
11240                                conv,
11241                                state,
11242                                Some(&mut st.states),
11243                                &mut conv_out,
11244                                &mut o,
11245                                tmp.as_mut(),
11246                            )?;
11247                            None
11248                        }
11249                        // Captured at this width already: replay, no eager pass.
11250                        (true, Some(g)) => {
11251                            g.0.launch()?;
11252                            Some(g)
11253                        }
11254                        // Warm but not yet captured: capture WITHOUT executing
11255                        // (`nowarm`), then launch once — capture + launch is exactly one
11256                        // execution, so the column snapshots and the state advance happen
11257                        // exactly once.
11258                        (true, None) => {
11259                            let states = &mut st.states;
11260                            let mut tmp_ref = tmp.as_mut();
11261                            let g = e.capture_graph_retained_nowarm(|eng| {
11262                                chain(
11263                                    eng,
11264                                    conv,
11265                                    state,
11266                                    Some(states),
11267                                    &mut conv_out,
11268                                    &mut o,
11269                                    tmp_ref.as_deref_mut(),
11270                                )
11271                            })?;
11272                            g.0.launch()?;
11273                            Some(g)
11274                        }
11275                    };
11276                    if let Some(g) = entry {
11277                        st.scan_graph = Some((t, g));
11278                    }
11279                }
11280                Some(st) => chain(
11281                    e,
11282                    conv,
11283                    state,
11284                    Some(&mut st.states),
11285                    &mut conv_out,
11286                    &mut o,
11287                    tmp.as_mut(),
11288                )?,
11289                None => chain(e, conv, state, None, &mut conv_out, &mut o, tmp.as_mut())?,
11290            }
11291            ws.put_f32("gdn.conv_out", conv_out);
11292            if let Some(tmp) = tmp {
11293                ws.put_f32("gdn.tmp", tmp);
11294            }
11295            Ok(o)
11296        })?;
11297        ws.put_f32("gdn.qkv", qkv);
11298        ws.put_f32("gdn.beta", beta_raw);
11299        ws.put_f32("gdn.glog", g_log);
11300
11301        let out = prof_section(e, "gdn.norm_gate_out", || {
11302            let mut gated = ws.take_f32(e, "gdn.gated", t * nv * hv, 0)?;
11303            match p.gate_activation {
11304                // Fused norm+gate (perf round 3): one launch, bit-identical to the
11305                // rms_norm + sigmoid + mul chain below (rms_sigmul_f32 kernel doc).
11306                GdnGateActivation::Sigmoid if gdn_fuse_on() => {
11307                    launch_rms_sigmul(e, &o, &gdn.norm, &z, &mut gated, hv, t * nv, eps)?;
11308                }
11309                GdnGateActivation::Sigmoid => {
11310                    let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
11311                    e.rms_norm(&o, &gdn.norm, &mut normed, hv, t * nv, eps)?;
11312                    let mut sg = ws.take_f32(e, "gdn.sg", t * nv * hv, 0)?;
11313                    e.sigmoid(&z, &mut sg, t * nv * hv)?;
11314                    e.mul(&normed, &sg, &mut gated, t * nv * hv)?;
11315                    ws.put_f32("gdn.sg", sg);
11316                    ws.put_f32("gdn.normed", normed);
11317                }
11318                GdnGateActivation::Silu => {
11319                    let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
11320                    e.rms_norm(&o, &gdn.norm, &mut normed, hv, t * nv, eps)?;
11321                    e.silu_mul(&z, &normed, &mut gated, t * nv * hv)?;
11322                    ws.put_f32("gdn.normed", normed);
11323                }
11324            }
11325            let mut out = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
11326            linear_trunk_into(
11327                e,
11328                &gdn.out,
11329                &gdn.out_b16,
11330                &gated,
11331                &mut out,
11332                t,
11333                nv * hv,
11334                hidden,
11335            )?;
11336            ws.put_f32("gdn.gated", gated);
11337            Ok(out)
11338        })?;
11339        ws.put_f32("gdn.z", z);
11340        ws.put_f32("gdn.o", o);
11341        Ok(out)
11342    }
11343
11344    /// MoE (`moe_mlp` twin): device router GEMM, HOST softmax-top-k routing (reference
11345    /// tie rule + renorm floor), per-expert gathered GEMMs, slot scatter/FMA-reduce, and
11346    /// the sigmoid-gated shared expert.
11347    fn moe_forward(
11348        &self,
11349        e: &Engine,
11350        ws: &mut StepPool,
11351        moe: &MoeW,
11352        mixed: &CudaSlice<f32>,
11353        t: usize,
11354        // Rows mode (MTP draft + spec verify chunks): at t > 1, run the GROUPED decode
11355        // program per TOKEN — each token's launch sequence is the t == 1 program
11356        // verbatim (bit-identical rows), instead of the prefill per-expert executor.
11357        rows_grouped: bool,
11358        // Layer index, for the shared-format MoE route trace only (`MEMRA_MOE_TRACE`); it does
11359        // not select any behaviour. Threaded rather than kept in a thread-local because a hidden
11360        // ambient layer id is the kind of state that mislabels a whole trace file silently.
11361        layer: u32,
11362    ) -> Res<CudaSlice<f32>> {
11363        let hidden = self.hidden;
11364        let experts = moe.plan.expert_count as usize;
11365        let selected = moe.plan.experts_per_token as usize;
11366        let ff = moe.plan.expert_intermediate_size as usize;
11367
11368        // Device router engage (devtwin lane): grouped dispatch only — those consumers
11369        // read device sel/w(/tok) arrays, so the route never crosses. NVFP4 (trunk):
11370        // t == 1 decode or the merged verify path (the per-token grouped twin addresses
11371        // its sel slot per token, which needs the host arrays). DeviceBf16 (the card-1
11372        // draft bank, devtwin stage 2): all rows-mode shapes via `qmatvec_bf16w_sel_f32`
11373        // (per-token launches read sel at a device offset — no host expert ids). The
11374        // per-expert prefill executor keeps the host twin (host-gathered rows by
11375        // construction).
11376        let nvfp4_bank = matches!(
11377            (&moe.bank.gate, &moe.bank.up, &moe.bank.down),
11378            (
11379                BankHalf::Nvfp4 { .. },
11380                BankHalf::Nvfp4 { .. },
11381                BankHalf::Nvfp4 { .. }
11382            )
11383        );
11384        let devbf16_bank = matches!(
11385            (&moe.bank.gate, &moe.bank.up, &moe.bank.down),
11386            (
11387                BankHalf::DeviceBf16(_),
11388                BankHalf::DeviceBf16(_),
11389                BankHalf::DeviceBf16(_)
11390            )
11391        );
11392        let use_dev_router = router_dev_on()
11393            && moe_sel_path_on()
11394            && route_dev_geometry(experts, selected)
11395            && ((nvfp4_bank
11396                && hidden % 32 == 0
11397                && ff % 4 == 0
11398                && (t == 1
11399                    || (rows_grouped
11400                        && verify_mt_on()
11401                        && sel_gufuse_on()
11402                        && t * selected <= 8192)))
11403                || (devbf16_bank && hidden % 8 == 0 && ff % 8 == 0 && (t == 1 || rows_grouped)));
11404        // (routes, device route). Exactly one is populated: host routes for the host
11405        // twin arms, or the device sel/w(/tok) triplet for the grouped device arms.
11406        type DevRoute = (CudaSlice<i32>, CudaSlice<f32>, Option<CudaSlice<i32>>);
11407        let (routes, mut dev_route): (Vec<Vec<(usize, f32)>>, Option<DevRoute>) =
11408            prof_section(e, "moe.router", || {
11409                let mut router_out = ws.take_f32(e, "moe.router", t * experts, 0)?;
11410                let none: Option<CudaSlice<u8>> = None;
11411                let rb = if router_bf16_on() {
11412                    &moe.router_b16
11413                } else {
11414                    &none
11415                };
11416                linear_trunk_into(
11417                    e,
11418                    &moe.router,
11419                    rb,
11420                    mixed,
11421                    &mut router_out,
11422                    t,
11423                    hidden,
11424                    experts,
11425                )?;
11426                if use_dev_router {
11427                    let mut sel = ws.take_i32_slot(e, "moe.sel", t * selected, 0)?;
11428                    let mut w = ws.take_f32(e, "moe.w", t * selected, 0)?;
11429                    let mut tokm = if t > 1 {
11430                        Some(ws.take_i32_slot(e, "moe.tok", t * selected, 0)?)
11431                    } else {
11432                        None
11433                    };
11434                    route_topk_device(
11435                        e,
11436                        &router_out,
11437                        &mut sel,
11438                        &mut w,
11439                        tokm.as_mut().map(|m| (m, 0)),
11440                        experts,
11441                        selected,
11442                        t,
11443                        layer,
11444                    )?;
11445                    ws.put_f32("moe.router", router_out);
11446                    return Ok((Vec::new(), Some((sel, w, tokm))));
11447                }
11448                let logits = e.dtoh_view(&router_out.slice(0..t * experts))?;
11449                ws.put_f32("moe.router", router_out);
11450                let mut routes: Vec<Vec<(usize, f32)>> = Vec::with_capacity(t);
11451                for token in 0..t {
11452                    routes.push(host_route_softmax_topk(
11453                        &logits[token * experts..(token + 1) * experts],
11454                        selected,
11455                    ));
11456                }
11457                Ok((routes, None))
11458            })?;
11459        // Grouped decode path (perf-lane attack (a)): one kernel launch per PROJECTION
11460        // covers every selected expert — the per-expert dispatch below (dequant chain +
11461        // three tiny GEMVs + scatter per routed expert, ~52% of the decode token in
11462        // PROFILE-0) collapses to 6 launches per layer. NVFP4 banks + single-token decode
11463        // only (prefill keeps the gathered per-expert path); W4A16 — the kernel computes
11464        // the eager dequant chain's per-element products with a different summation order
11465        // (accumulation class, kernel doc), gated by the tiny four-arm + real gates.
11466        if (t == 1 || rows_grouped) && moe_sel_path_on() {
11467            if let (
11468                BankHalf::Nvfp4 {
11469                    codes: gc,
11470                    scales: gs,
11471                    macros_dev: gm,
11472                    ..
11473                },
11474                BankHalf::Nvfp4 {
11475                    codes: uc,
11476                    scales: us,
11477                    macros_dev: um,
11478                    ..
11479                },
11480                BankHalf::Nvfp4 {
11481                    codes: dc,
11482                    scales: ds,
11483                    macros_dev: dm,
11484                    ..
11485                },
11486            ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
11487            {
11488                // Merged verify columns (set_verify_mt): ONE gufuse launch over every
11489                // column's routed experts via the slot->token map + ONE down launch over
11490                // all slots + per-token windowed combines. Per-slot programs and the
11491                // per-token combine order are the decode program VERBATIM (bit-identical);
11492                // launch count per layer drops from 3t to 2 + t combines.
11493                if t > 1 && verify_mt_on() && sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
11494                    // Device-routed merged verify (devtwin): ONE batch (the engage
11495                    // guard bounds t*selected <= 8192 <= SLOT_CAP), per-slot programs
11496                    // and the per-token combine order the decode program VERBATIM —
11497                    // bit-identical rows; only the route's residency changed. The
11498                    // slot->token map comes from the route kernel, not a host build.
11499                    if let Some((sel, w_dev, tokm)) = dev_route.take() {
11500                        let tokm =
11501                            tokm.ok_or("moe_forward: device route at t > 1 without a tok map")?;
11502                        let out = prof_section(e, "moe.sel_grouped", || {
11503                            let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
11504                            let s_total = t * selected;
11505                            let mut act = ws.take_f32(e, "moe.act", s_total * ff, 0)?;
11506                            launch_nvfp4_sel_gu_silu(
11507                                e,
11508                                (gc, gs, gm),
11509                                (uc, us, um),
11510                                Some(&sel),
11511                                0,
11512                                s_total,
11513                                mixed,
11514                                &mut act,
11515                                hidden,
11516                                ff,
11517                                Some((&tokm, hidden)),
11518                            )?;
11519                            let mut partial = ws.take_f32(e, "moe.partial", s_total * hidden, 0)?;
11520                            launch_nvfp4_sel_matvec(
11521                                e,
11522                                dc,
11523                                ds,
11524                                dm,
11525                                &sel,
11526                                &act,
11527                                &mut partial,
11528                                s_total,
11529                                ff,
11530                                hidden,
11531                                ff,
11532                            )?;
11533                            for tok in 0..t {
11534                                launch_axpy_rows_seq_at(
11535                                    e,
11536                                    &partial,
11537                                    tok * selected,
11538                                    &w_dev,
11539                                    tok * selected,
11540                                    &mut out,
11541                                    tok,
11542                                    hidden,
11543                                    selected,
11544                                )?;
11545                            }
11546                            ws.put_i32("moe.sel", sel);
11547                            ws.put_i32("moe.tok", tokm);
11548                            ws.put_f32("moe.w", w_dev);
11549                            ws.put_f32("moe.act", act);
11550                            ws.put_f32("moe.partial", partial);
11551                            Ok(out)
11552                        })?;
11553                        return self.moe_shared_tail(e, ws, moe, mixed, out, t);
11554                    }
11555                    let out = prof_section(e, "moe.sel_grouped", || {
11556                        let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
11557                        // Slot sub-batching: the grouped kernels index slots on grid.y,
11558                        // which CUDA caps at 65,535 — a long-context prefill chunk
11559                        // (t 8192 x 10 selected = 81,920 slots) overflowed it with
11560                        // CUDA_ERROR_INVALID_VALUE (smoke ladder, rung 32768). Sub-batches
11561                        // also bound the transients (act s*ff, partial s*hidden) on a card
11562                        // already holding the trunk. Sub-batching changes NOTHING per slot
11563                        // or per token: each slot's program and each token's combine order
11564                        // are identical to one big batch (and to the t == 1 decode
11565                        // program) — the boundary only splits launches.
11566                        const SLOT_CAP: usize = 8192;
11567                        let tok_step = (SLOT_CAP / selected.max(1)).max(1);
11568                        let mut tok0 = 0usize;
11569                        while tok0 < t {
11570                            let tok_n = tok_step.min(t - tok0);
11571                            let batch = &routes[tok0..tok0 + tok_n];
11572                            let mut sel_all: Vec<i32> = Vec::with_capacity(tok_n * selected);
11573                            let mut w_all: Vec<f32> = Vec::with_capacity(tok_n * selected);
11574                            let mut tok_all: Vec<i32> = Vec::with_capacity(tok_n * selected);
11575                            let mut ranges: Vec<(usize, usize)> = Vec::with_capacity(tok_n);
11576                            for (i, route) in batch.iter().enumerate() {
11577                                ranges.push((sel_all.len(), route.len()));
11578                                for &(eid, wgt) in route {
11579                                    sel_all.push(eid as i32);
11580                                    w_all.push(wgt);
11581                                    // ABSOLUTE token index: the kernel reads the
11582                                    // activation row at tok * hidden from the same
11583                                    // `mixed` buffer, so a sub-batch reads exactly the
11584                                    // rows one big batch would (no view, no offset math).
11585                                    tok_all.push((tok0 + i) as i32);
11586                                }
11587                            }
11588                            let s_total = sel_all.len();
11589                            let sel = ws.take_i32(e, "moe.sel", &sel_all, 0)?;
11590                            let w_dev = ws.take_f32_h2d(e, "moe.w", &w_all, 0)?;
11591                            let tokm = ws.take_i32(e, "moe.tok", &tok_all, 0)?;
11592                            let mut act = ws.take_f32(e, "moe.act", s_total * ff, 0)?;
11593                            launch_nvfp4_sel_gu_silu(
11594                                e,
11595                                (gc, gs, gm),
11596                                (uc, us, um),
11597                                Some(&sel),
11598                                0,
11599                                s_total,
11600                                mixed,
11601                                &mut act,
11602                                hidden,
11603                                ff,
11604                                Some((&tokm, hidden)),
11605                            )?;
11606                            let mut partial = ws.take_f32(e, "moe.partial", s_total * hidden, 0)?;
11607                            launch_nvfp4_sel_matvec(
11608                                e,
11609                                dc,
11610                                ds,
11611                                dm,
11612                                &sel,
11613                                &act,
11614                                &mut partial,
11615                                s_total,
11616                                ff,
11617                                hidden,
11618                                ff,
11619                            )?;
11620                            for (i, &(start, len)) in ranges.iter().enumerate() {
11621                                launch_axpy_rows_seq_at(
11622                                    e,
11623                                    &partial,
11624                                    start,
11625                                    &w_dev,
11626                                    start,
11627                                    &mut out,
11628                                    tok0 + i,
11629                                    hidden,
11630                                    len,
11631                                )?;
11632                            }
11633                            ws.put_i32("moe.sel", sel);
11634                            ws.put_i32("moe.tok", tokm);
11635                            ws.put_f32("moe.w", w_dev);
11636                            ws.put_f32("moe.act", act);
11637                            ws.put_f32("moe.partial", partial);
11638                            tok0 += tok_n;
11639                        }
11640                        Ok(out)
11641                    })?;
11642                    return self.moe_shared_tail(e, ws, moe, mixed, out, t);
11643                }
11644                // Device-routed decode step (devtwin, t == 1 by the engage guard): the
11645                // grouped decode program launch-for-launch, sel/w read from the device
11646                // route — bit-identical to the host-routed chain on the same selection.
11647                if let Some((sel, w_dev, _)) = dev_route.take() {
11648                    let out = prof_section(e, "moe.sel_grouped", || {
11649                        let mut out = ws.take_f32(e, "moe.out", hidden, 0)?;
11650                        let mut act = ws.take_f32(e, "moe.act", selected * ff, 0)?;
11651                        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
11652                            launch_nvfp4_sel_gu_silu(
11653                                e,
11654                                (gc, gs, gm),
11655                                (uc, us, um),
11656                                Some(&sel),
11657                                0,
11658                                selected,
11659                                mixed,
11660                                &mut act,
11661                                hidden,
11662                                ff,
11663                                None,
11664                            )?;
11665                        } else {
11666                            let mut yg = ws.take_f32(e, "moe.yg", selected * ff, 0)?;
11667                            let mut yu = ws.take_f32(e, "moe.yu", selected * ff, 0)?;
11668                            launch_nvfp4_sel_matvec(
11669                                e, gc, gs, gm, &sel, mixed, &mut yg, selected, hidden, ff, 0,
11670                            )?;
11671                            launch_nvfp4_sel_matvec(
11672                                e, uc, us, um, &sel, mixed, &mut yu, selected, hidden, ff, 0,
11673                            )?;
11674                            e.silu_mul(&yg, &yu, &mut act, selected * 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", selected * hidden, 0)?;
11679                        launch_nvfp4_sel_matvec(
11680                            e,
11681                            dc,
11682                            ds,
11683                            dm,
11684                            &sel,
11685                            &act,
11686                            &mut partial,
11687                            selected,
11688                            ff,
11689                            hidden,
11690                            ff,
11691                        )?;
11692                        e.axpy_rows_seq_into(&partial, &w_dev, &mut out, hidden, selected)?;
11693                        ws.put_i32("moe.sel", sel);
11694                        ws.put_f32("moe.w", w_dev);
11695                        ws.put_f32("moe.act", act);
11696                        ws.put_f32("moe.partial", partial);
11697                        Ok(out)
11698                    })?;
11699                    return self.moe_shared_tail(e, ws, moe, mixed, out, t);
11700                }
11701                let out = prof_section(e, "moe.sel_grouped", || {
11702                    let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
11703                    for (tok, route) in routes.iter().enumerate() {
11704                        let n_sel = route.len();
11705                        let sel_host: Vec<i32> = route.iter().map(|&(x, _)| x as i32).collect();
11706                        let w_host: Vec<f32> = route.iter().map(|&(_, w)| w).collect();
11707                        let sel = ws.take_i32(e, "moe.sel", &sel_host, 0)?;
11708                        let w_dev = ws.take_f32_h2d(e, "moe.w", &w_host, 0)?;
11709                        // Activation operand: t == 1 reads `mixed` in place (the decode
11710                        // program, launch-for-launch unchanged); rows mode stages the
11711                        // token's row in a stable slot (exact copy — the kernel reads
11712                        // identical values, so rows stay bit-identical to decode).
11713                        let x_tok = if t == 1 {
11714                            None
11715                        } else {
11716                            let mut x = ws.take_f32(e, "moe.x", hidden, 0)?;
11717                            e.copy_range_into(&mut x, 0, mixed, tok * hidden, hidden)?;
11718                            Some(x)
11719                        };
11720                        let x_ref = x_tok.as_ref().unwrap_or(mixed);
11721                        let mut act = ws.take_f32(e, "moe.act", n_sel * ff, 0)?;
11722                        // Fused gate+up+silu (round 4): ONE launch, bit-identical to the
11723                        // three-op chain below (kernel doc + oracle gufuse mode).
11724                        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
11725                            launch_nvfp4_sel_gu_silu(
11726                                e,
11727                                (gc, gs, gm),
11728                                (uc, us, um),
11729                                Some(&sel),
11730                                0,
11731                                n_sel,
11732                                x_ref,
11733                                &mut act,
11734                                hidden,
11735                                ff,
11736                                None,
11737                            )?;
11738                        } else {
11739                            let mut yg = ws.take_f32(e, "moe.yg", n_sel * ff, 0)?;
11740                            let mut yu = ws.take_f32(e, "moe.yu", n_sel * ff, 0)?;
11741                            launch_nvfp4_sel_matvec(
11742                                e, gc, gs, gm, &sel, x_ref, &mut yg, n_sel, hidden, ff, 0,
11743                            )?;
11744                            launch_nvfp4_sel_matvec(
11745                                e, uc, us, um, &sel, x_ref, &mut yu, n_sel, hidden, ff, 0,
11746                            )?;
11747                            e.silu_mul(&yg, &yu, &mut act, n_sel * ff)?;
11748                            ws.put_f32("moe.yg", yg);
11749                            ws.put_f32("moe.yu", yu);
11750                        }
11751                        let mut partial = ws.take_f32(e, "moe.partial", n_sel * hidden, 0)?;
11752                        launch_nvfp4_sel_matvec(
11753                            e,
11754                            dc,
11755                            ds,
11756                            dm,
11757                            &sel,
11758                            &act,
11759                            &mut partial,
11760                            n_sel,
11761                            ff,
11762                            hidden,
11763                            ff,
11764                        )?;
11765                        // Slot-ordered sequential combine (axpy_rows_seq_f32
11766                        // self-initializes); rows mode lands the row by exact copy.
11767                        if t == 1 {
11768                            e.axpy_rows_seq_into(&partial, &w_dev, &mut out, hidden, n_sel)?;
11769                        } else {
11770                            let mut row = ws.take_f32(e, "moe.row", hidden, 0)?;
11771                            e.axpy_rows_seq_into(&partial, &w_dev, &mut row, hidden, n_sel)?;
11772                            e.copy_range_into(&mut out, tok * hidden, &row, 0, hidden)?;
11773                            ws.put_f32("moe.row", row);
11774                        }
11775                        ws.put_i32("moe.sel", sel);
11776                        ws.put_f32("moe.w", w_dev);
11777                        ws.put_f32("moe.act", act);
11778                        ws.put_f32("moe.partial", partial);
11779                        if let Some(x) = x_tok {
11780                            ws.put_f32("moe.x", x);
11781                        }
11782                    }
11783                    Ok(out)
11784                })?;
11785                return self.moe_shared_tail(e, ws, moe, mixed, out, t);
11786            }
11787            // DeviceBf16 bank (the MTP draft): per-selected-expert row-offset bf16
11788            // matvecs straight off the resident bytes — n_sel launches per projection
11789            // (arbitrary expert ids cannot batch through the strided kernel), silu and
11790            // combine exactly like the NVFP4 grouped chain.
11791            if let (BankHalf::DeviceBf16(gb), BankHalf::DeviceBf16(ub), BankHalf::DeviceBf16(db)) =
11792                (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
11793            {
11794                // Device-routed draft MoE (devtwin stage 2): per token, ONE
11795                // `qmatvec_bf16w_sel_f32` launch per projection reads its expert ids
11796                // from the device route at a sel offset — no host expert ids, no
11797                // per-slot launch chain. Per-row programs are the off_into chain
11798                // VERBATIM (kernel doc + the bf16 oracle's sel mode) and the combine
11799                // writes the same window `axpy_rows_seq` initialized — bit-identical.
11800                if let Some((sel, w_dev, _)) = dev_route.take() {
11801                    let out = prof_section(e, "moe.sel_bf16", || {
11802                        let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
11803                        for tok in 0..t {
11804                            let mut yg = ws.take_f32(e, "moe.yg", selected * ff, 0)?;
11805                            let mut yu = ws.take_f32(e, "moe.yu", selected * ff, 0)?;
11806                            launch_qmatvec_bf16w_sel(
11807                                e,
11808                                gb,
11809                                &sel,
11810                                tok * selected,
11811                                mixed,
11812                                tok * hidden,
11813                                0,
11814                                &mut yg,
11815                                selected,
11816                                hidden,
11817                                ff,
11818                            )?;
11819                            launch_qmatvec_bf16w_sel(
11820                                e,
11821                                ub,
11822                                &sel,
11823                                tok * selected,
11824                                mixed,
11825                                tok * hidden,
11826                                0,
11827                                &mut yu,
11828                                selected,
11829                                hidden,
11830                                ff,
11831                            )?;
11832                            let mut act = ws.take_f32(e, "moe.act", selected * ff, 0)?;
11833                            e.silu_mul(&yg, &yu, &mut act, selected * ff)?;
11834                            let mut partial =
11835                                ws.take_f32(e, "moe.partial", selected * hidden, 0)?;
11836                            launch_qmatvec_bf16w_sel(
11837                                e,
11838                                db,
11839                                &sel,
11840                                tok * selected,
11841                                &act,
11842                                0,
11843                                ff,
11844                                &mut partial,
11845                                selected,
11846                                ff,
11847                                hidden,
11848                            )?;
11849                            launch_axpy_rows_seq_at(
11850                                e,
11851                                &partial,
11852                                0,
11853                                &w_dev,
11854                                tok * selected,
11855                                &mut out,
11856                                tok,
11857                                hidden,
11858                                selected,
11859                            )?;
11860                            ws.put_f32("moe.yg", yg);
11861                            ws.put_f32("moe.yu", yu);
11862                            ws.put_f32("moe.act", act);
11863                            ws.put_f32("moe.partial", partial);
11864                        }
11865                        ws.put_i32("moe.sel", sel);
11866                        ws.put_f32("moe.w", w_dev);
11867                        Ok(out)
11868                    })?;
11869                    return self.moe_shared_tail(e, ws, moe, mixed, out, t);
11870                }
11871                let out = prof_section(e, "moe.sel_bf16", || {
11872                    let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
11873                    for (tok, route) in routes.iter().enumerate() {
11874                        let n_sel = route.len();
11875                        let w_host: Vec<f32> = route.iter().map(|&(_, w)| w).collect();
11876                        let w_dev = ws.take_f32_h2d(e, "moe.w", &w_host, 0)?;
11877                        let mut yg = ws.take_f32(e, "moe.yg", n_sel * ff, 0)?;
11878                        let mut yu = ws.take_f32(e, "moe.yu", n_sel * ff, 0)?;
11879                        for (slot, &(eid, _)) in route.iter().enumerate() {
11880                            launch_qmatvec_bf16w_off_into(
11881                                e,
11882                                gb,
11883                                eid * ff,
11884                                mixed,
11885                                tok * hidden,
11886                                &mut yg,
11887                                slot * ff,
11888                                hidden,
11889                                ff,
11890                            )?;
11891                            launch_qmatvec_bf16w_off_into(
11892                                e,
11893                                ub,
11894                                eid * ff,
11895                                mixed,
11896                                tok * hidden,
11897                                &mut yu,
11898                                slot * ff,
11899                                hidden,
11900                                ff,
11901                            )?;
11902                        }
11903                        let mut act = ws.take_f32(e, "moe.act", n_sel * ff, 0)?;
11904                        e.silu_mul(&yg, &yu, &mut act, n_sel * ff)?;
11905                        let mut partial = ws.take_f32(e, "moe.partial", n_sel * hidden, 0)?;
11906                        for (slot, &(eid, _)) in route.iter().enumerate() {
11907                            launch_qmatvec_bf16w_off_into(
11908                                e,
11909                                db,
11910                                eid * hidden,
11911                                &act,
11912                                slot * ff,
11913                                &mut partial,
11914                                slot * hidden,
11915                                ff,
11916                                hidden,
11917                            )?;
11918                        }
11919                        let mut row = ws.take_f32(e, "moe.row", hidden, 0)?;
11920                        e.axpy_rows_seq_into(&partial, &w_dev, &mut row, hidden, n_sel)?;
11921                        e.copy_range_into(&mut out, tok * hidden, &row, 0, hidden)?;
11922                        ws.put_f32("moe.row", row);
11923                        ws.put_f32("moe.w", w_dev);
11924                        ws.put_f32("moe.yg", yg);
11925                        ws.put_f32("moe.yu", yu);
11926                        ws.put_f32("moe.act", act);
11927                        ws.put_f32("moe.partial", partial);
11928                    }
11929                    Ok(out)
11930                })?;
11931                return self.moe_shared_tail(e, ws, moe, mixed, out, t);
11932            }
11933        }
11934
11935        // A device route that reaches here would feed the per-expert executor EMPTY
11936        // host routes and silently compute nothing — fail loud instead (the engage
11937        // guard and the dispatch arms must stay in lockstep).
11938        if dev_route.is_some() {
11939            return Err(
11940                "moe_forward: device route left unconsumed (engage guard drifted from the \
11941                 dispatch arms)"
11942                    .into(),
11943            );
11944        }
11945        // expert -> [(token, slot, weight)]
11946        let mut by_expert: Vec<Vec<(i32, i32, f32)>> = vec![Vec::new(); experts];
11947        for (token, token_routes) in routes.iter().enumerate() {
11948            for (slot, &(expert, weight)) in token_routes.iter().enumerate() {
11949                by_expert[expert].push((token as i32, slot as i32, weight));
11950            }
11951        }
11952        let mut slots = e.zeros(t * selected * hidden)?;
11953        let mut wbuf = e.zeros(t * selected)?;
11954        for (expert, entries) in by_expert.iter().enumerate() {
11955            if entries.is_empty() {
11956                continue;
11957            }
11958            let m_e = entries.len();
11959            let (tok_dev, slot_dev, w_dev, xg) = prof_section(e, "moe.idx_gather", || {
11960                let tok_idx: Vec<i32> = entries.iter().map(|&(tok, _, _)| tok).collect();
11961                let slot_idx: Vec<i32> = entries.iter().map(|&(_, slot, _)| slot).collect();
11962                let weights: Vec<f32> = entries.iter().map(|&(_, _, w)| w).collect();
11963                let tok_dev = e.htod_i32(&tok_idx)?;
11964                let slot_dev = e.htod_i32(&slot_idx)?;
11965                let w_dev = e.htod(&weights)?;
11966                let mut xg = e.uninit(m_e * hidden)?;
11967                e.gather_rows(mixed, &tok_dev, &mut xg, hidden, m_e)?;
11968                Ok((tok_dev, slot_dev, w_dev, xg))
11969            })?;
11970            // Resolve this expert's operand views per bank half (F32 = view into the
11971            // resident bank; NVFP4 = per-expert kernel dequant into a transient f32).
11972            let resolve = |half: &BankHalf,
11973                           out_f: usize,
11974                           in_f: usize|
11975             -> Res<(Option<CudaSlice<f32>>, usize)> {
11976                match half {
11977                    BankHalf::F32(_) => Ok((None, expert * out_f * in_f)),
11978                    BankHalf::Nvfp4 {
11979                        codes,
11980                        scales,
11981                        macros,
11982                        ..
11983                    } => Ok((
11984                        Some(dequant_nvfp4_expert_f32(
11985                            e,
11986                            codes,
11987                            scales,
11988                            macros[expert],
11989                            expert,
11990                            out_f,
11991                            in_f,
11992                        )?),
11993                        0,
11994                    )),
11995                    // Host-resident bf16 bank: upload THIS expert's rows and upcast
11996                    // (exact) — the per-routed-expert twin of the load-time dequant.
11997                    BankHalf::HostBf16(bytes) => {
11998                        let row_bytes = out_f * in_f * 2;
11999                        let dev =
12000                            e.htod_bytes(&bytes[expert * row_bytes..(expert + 1) * row_bytes])?;
12001                        Ok((
12002                            Some(e.bf16_to_f32(&dev.slice(0..row_bytes), out_f * in_f)?),
12003                            0,
12004                        ))
12005                    }
12006                    // Device-resident bf16 bank (MTP draft): widen THIS expert's rows
12007                    // in place (exact) — the multi-token replay/prefill arm; the t == 1
12008                    // draft decode takes the grouped row-offset matvec path instead.
12009                    BankHalf::DeviceBf16(bytes) => {
12010                        let row_bytes = out_f * in_f * 2;
12011                        let view = bytes.slice(expert * row_bytes..(expert + 1) * row_bytes);
12012                        Ok((Some(e.bf16_to_f32(&view, out_f * in_f)?), 0))
12013                    }
12014                }
12015            };
12016            let ((gate_owned, gate_base), (up_owned, up_base), (down_owned, down_base)) =
12017                prof_section(e, "moe.dequant", || {
12018                    Ok((
12019                        resolve(&moe.bank.gate, ff, hidden)?,
12020                        resolve(&moe.bank.up, ff, hidden)?,
12021                        resolve(&moe.bank.down, hidden, ff)?,
12022                    ))
12023                })?;
12024            let gate_view = match (&moe.bank.gate, &gate_owned) {
12025                (_, Some(owned)) => owned.slice(0..ff * hidden),
12026                (BankHalf::F32(bank), None) => bank.slice(gate_base..gate_base + ff * hidden),
12027                (
12028                    BankHalf::Nvfp4 { .. } | BankHalf::HostBf16(_) | BankHalf::DeviceBf16(_),
12029                    None,
12030                ) => {
12031                    unreachable!("quantized/host/device-bf16 halves always resolve owned")
12032                }
12033            };
12034            let up_view = match (&moe.bank.up, &up_owned) {
12035                (_, Some(owned)) => owned.slice(0..ff * hidden),
12036                (BankHalf::F32(bank), None) => bank.slice(up_base..up_base + ff * hidden),
12037                (
12038                    BankHalf::Nvfp4 { .. } | BankHalf::HostBf16(_) | BankHalf::DeviceBf16(_),
12039                    None,
12040                ) => {
12041                    unreachable!("quantized/host/device-bf16 halves always resolve owned")
12042                }
12043            };
12044            let down_view = match (&moe.bank.down, &down_owned) {
12045                (_, Some(owned)) => owned.slice(0..hidden * ff),
12046                (BankHalf::F32(bank), None) => bank.slice(down_base..down_base + hidden * ff),
12047                (
12048                    BankHalf::Nvfp4 { .. } | BankHalf::HostBf16(_) | BankHalf::DeviceBf16(_),
12049                    None,
12050                ) => {
12051                    unreachable!("quantized/host/device-bf16 halves always resolve owned")
12052                }
12053            };
12054            prof_section(e, "moe.expert_gemms", || {
12055                let down_out =
12056                    run_routed_expert(e, &xg, &gate_view, &up_view, &down_view, m_e, hidden, ff)?;
12057                e.scatter_slot(
12058                    &down_out, &tok_dev, &slot_dev, &w_dev, &mut slots, &mut wbuf, hidden,
12059                    selected, m_e,
12060                )
12061            })?;
12062        }
12063        let out = prof_section(e, "moe.reduce", || {
12064            let mut out = e.zeros(t * hidden)?;
12065            e.reduce_slots(&slots, &wbuf, &mut out, hidden, selected, t)?;
12066            Ok(out)
12067        })?;
12068        self.moe_shared_tail(e, ws, moe, mixed, out, t)
12069    }
12070
12071    /// Shared expert, sigmoid input gate (Qwen3NextSparseMoeBlock convention) — the
12072    /// common tail of both routed-expert executors.
12073    fn moe_shared_tail(
12074        &self,
12075        e: &Engine,
12076        ws: &mut StepPool,
12077        moe: &MoeW,
12078        mixed: &CudaSlice<f32>,
12079        mut out: CudaSlice<f32>,
12080        t: usize,
12081    ) -> Res<CudaSlice<f32>> {
12082        let hidden = self.hidden;
12083        let sff = moe
12084            .plan
12085            .shared
12086            .as_ref()
12087            .map(|s| s.intermediate_size as usize)
12088            .unwrap_or(0);
12089        if sff > 0 {
12090            prof_section(e, "moe.shared", || {
12091                // hcmicro: the shared-expert mats ride the bf16 trunk residency (their
12092                // f32 reads were ~2.5 GB/token); OFF keeps the f32 cuBLASLt chain.
12093                let none: Option<CudaSlice<u8>> = None;
12094                let (gu, db) = if micro_shexp_on() {
12095                    (&moe.shared_gu_b16, &moe.shared_down_b16)
12096                } else {
12097                    (&none, &none)
12098                };
12099                let mut gate = ws.take_f32(e, "moe.sh_gate", t * sff, 0)?;
12100                let mut up = ws.take_f32(e, "moe.sh_up", t * sff, 0)?;
12101                // Proj stack (round 4): shared gate/up in ONE launch (bit-identical
12102                // rows; OFF arm = row-offset views of the same stack).
12103                if let (true, Some(stack)) =
12104                    (t == 1 && proj_stack_on() && trunk_bf16_on(), gu.as_ref())
12105                {
12106                    launch_qmatvec_bf16w_multi4(
12107                        e,
12108                        stack,
12109                        mixed,
12110                        &[(&gate, sff), (&up, sff)],
12111                        hidden,
12112                    )?;
12113                } else {
12114                    linear_trunk_stacked_into(
12115                        e,
12116                        &moe.shared_gate,
12117                        gu,
12118                        0,
12119                        mixed,
12120                        &mut gate,
12121                        t,
12122                        hidden,
12123                        sff,
12124                    )?;
12125                    linear_trunk_stacked_into(
12126                        e,
12127                        &moe.shared_up,
12128                        gu,
12129                        sff,
12130                        mixed,
12131                        &mut up,
12132                        t,
12133                        hidden,
12134                        sff,
12135                    )?;
12136                }
12137                let mut act = ws.take_f32(e, "moe.sh_act", t * sff, 0)?;
12138                e.silu_mul(&gate, &up, &mut act, t * sff)?;
12139                let mut shared = ws.take_f32(e, "moe.sh_down", t * hidden, 0)?;
12140                linear_trunk_into(e, &moe.shared_down, db, &act, &mut shared, t, sff, hidden)?;
12141                if let Some(input_gate) = moe.shared_input_gate.as_ref() {
12142                    // Into-variant (same kernel, same launch shape as `sigmoid_dot_rows`;
12143                    // the owned form allocates per call — graph capture forbids that).
12144                    let mut g = ws.take_f32(e, "moe.g", t, 0)?;
12145                    e.sigmoid_dot_rows_into(mixed, input_gate, &mut g, hidden, t)?;
12146                    e.add_scaled_rows(&shared, &g, &mut out, hidden, t)?;
12147                    ws.put_f32("moe.g", g);
12148                } else {
12149                    let mut view = out.slice_mut(0..t * hidden);
12150                    e.axpy_into(&shared, 1.0, &mut view, t * hidden)?;
12151                }
12152                ws.put_f32("moe.sh_gate", gate);
12153                ws.put_f32("moe.sh_up", up);
12154                ws.put_f32("moe.sh_act", act);
12155                ws.put_f32("moe.sh_down", shared);
12156                Ok(())
12157            })?;
12158        }
12159        Ok(out)
12160    }
12161
12162    /// PLE block (`ple_block` twin): host n-gram hashing + host gather from the
12163    /// host-resident table, H2D of the gathered rows, device projections / grouped norms /
12164    /// dilated depthwise conv, host signed-sqrt sigmoid gate scalars.
12165    #[allow(clippy::too_many_arguments)]
12166    #[allow(clippy::too_many_arguments)]
12167    fn ple_block(
12168        &self,
12169        e: &Engine,
12170        layer: &LayerW,
12171        ple: &PleW,
12172        table: &NgramTable,
12173        ple_state: &mut PleState,
12174        planes: &mut [CudaSlice<f32>],
12175        tokens: &[u32],
12176        t: usize,
12177        // Verify-exact rows: per-token cuBLASLt launches (m == 1, the decode shape) so
12178        // chunk rows stay bit-identical to decode; `stash` retains the pre-chunk conv
12179        // history + the chunk's normed rows (the rewind rebuild inputs).
12180        exact: bool,
12181        mut stash: Option<&mut PleStash>,
12182    ) -> Res<()> {
12183        let hidden = self.hidden;
12184        let streams = self.streams;
12185        let plan = &ple.plan;
12186        let heads = plan.ngram_heads as usize;
12187        let head_dim = plan.head_embed_dim as usize;
12188        let embed_dim = plan.embed_dim as usize;
12189        let kernel = plan.conv_kernel as usize;
12190        let max_ngram = plan.max_ngram as usize;
12191        let dilation = max_ngram;
12192        let pad = (kernel - 1) * dilation;
12193        let eps = layer.eps_attn;
12194
12195        // Host n-gram ids over the FULL history (exact segment semantics), last t rows.
12196        let gathered = prof_section(e, "ple.host_ngram_gather", || {
12197            let total_heads = heads;
12198            // `plecache`: extend the state's id cache instead of rebuilding the whole
12199            // history's hashes. `ids` owns the vector only on the OFF arm; on the ON arm the
12200            // chunk rows are read in place out of the state (no O(context) clone).
12201            let mut ids: Vec<i64> = Vec::new();
12202            if ple_cache_on() {
12203                host_ngram_ids_cached(
12204                    &mut ple_state.ngram_ids,
12205                    &mut ple_state.ngram_history,
12206                    &mut ple_state.ngram_last_eos,
12207                    tokens,
12208                    &ple.multipliers,
12209                    &ple.sizes,
12210                    &ple.offsets,
12211                    max_ngram,
12212                    heads / (max_ngram - 1),
12213                    plan.eos_token_id,
12214                );
12215                if ple_cache_audit_on() {
12216                    let twin = host_ngram_ids(
12217                        tokens,
12218                        &ple.multipliers,
12219                        &ple.sizes,
12220                        &ple.offsets,
12221                        max_ngram,
12222                        heads / (max_ngram - 1),
12223                        plan.eos_token_id,
12224                    );
12225                    let from = (tokens.len() - t) * total_heads;
12226                    let mism = twin[from..]
12227                        .iter()
12228                        .zip(&ple_state.ngram_ids[from..])
12229                        .filter(|(a, b)| a != b)
12230                        .count() as u64;
12231                    PLE_CACHE_AUDIT_ROWS.fetch_add(t as u64, std::sync::atomic::Ordering::Relaxed);
12232                    PLE_CACHE_AUDIT_MISMATCH.fetch_add(mism, std::sync::atomic::Ordering::Relaxed);
12233                    PLE_CACHE_AUDIT_MAX_FILL
12234                        .fetch_max(tokens.len() as u64, std::sync::atomic::Ordering::Relaxed);
12235                    if mism > 0 {
12236                        return Err(format!(
12237                            "plecache audit: {mism} cached n-gram ids differ from the full twin \
12238                             at history {} (t={t})",
12239                            tokens.len()
12240                        )
12241                        .into());
12242                    }
12243                }
12244            } else {
12245                ids = host_ngram_ids(
12246                    tokens,
12247                    &ple.multipliers,
12248                    &ple.sizes,
12249                    &ple.offsets,
12250                    max_ngram,
12251                    heads / (max_ngram - 1),
12252                    plan.eos_token_id,
12253                );
12254            }
12255            let all_ids: &[i64] = if ple_cache_on() {
12256                &ple_state.ngram_ids
12257            } else {
12258                &ids
12259            };
12260            let chunk_ids = &all_ids[(tokens.len() - t) * total_heads..];
12261            let table_rows = table.rows(head_dim);
12262            let mut gathered = vec![0.0f32; t * embed_dim];
12263            for token in 0..t {
12264                for head in 0..heads {
12265                    let id = chunk_ids[token * total_heads + head];
12266                    if id < 0 || id as usize >= table_rows {
12267                        return Err("qwen4exp_gpu: n-gram id outside the embedding table".into());
12268                    }
12269                    table.gather_into(
12270                        id as usize,
12271                        head_dim,
12272                        &mut gathered[token * embed_dim + head * head_dim
12273                            ..token * embed_dim + (head + 1) * head_dim],
12274                    );
12275                }
12276            }
12277            Ok(gathered)
12278        })?;
12279        let emb = prof_section(e, "ple.h2d", || e.htod(&gathered))?;
12280
12281        // Per-token cuBLASLt twin (verify-exact): every m == 1 launch matches the
12282        // decode dispatch for that projection, so chunk rows equal decode rows bitwise.
12283        let lin_rows = |x: &CudaSlice<f32>,
12284                        w: &CudaSlice<f32>,
12285                        in_f: usize,
12286                        out_f: usize|
12287         -> Res<CudaSlice<f32>> {
12288            let mut out = e.uninit(t * out_f)?;
12289            if exact && t > 1 {
12290                let wv = w.slice(0..w.len());
12291                for tok in 0..t {
12292                    let xv = x.slice(tok * in_f..(tok + 1) * in_f);
12293                    let mut yv = out.slice_mut(tok * out_f..(tok + 1) * out_f);
12294                    e.linear_device_into(&xv, &wv, &mut yv, 1, in_f, out_f)?;
12295                }
12296            } else {
12297                e.linear_device_into(x, w, &mut out, t, in_f, out_f)?;
12298            }
12299            Ok(out)
12300        };
12301        let (value, mut dots_host) = prof_section(e, "ple.key_gate", || {
12302            let value = lin_rows(&emb, &ple.value_proj, embed_dim, hidden)?;
12303            let ones = e.htod(&vec![1.0f32; hidden])?;
12304            let mut dots_host = vec![0.0f32; streams * t];
12305            for s in 0..streams {
12306                let key = lin_rows(&emb, &ple.key_proj[s], embed_dim, hidden)?;
12307                let mut key_normed = e.uninit(t * hidden)?;
12308                e.rms_norm(&key, &ple.norm_key[s], &mut key_normed, hidden, t, eps)?;
12309                let mut query = e.uninit(t * hidden)?;
12310                e.rms_norm(&planes[s], &ple.norm_query[s], &mut query, hidden, t, eps)?;
12311                let mut prod = e.uninit(t * hidden)?;
12312                e.mul(&key_normed, &query, &mut prod, t * hidden)?;
12313                let dots = lin_rows(&prod, &ones, hidden, 1)?;
12314                dots_host[s * t..(s + 1) * t].copy_from_slice(&e.dtoh(&dots)?);
12315            }
12316            Ok((value, dots_host))
12317        })?;
12318        // signed sqrt + sigmoid (modular L770; torch sign(0) = 0) — host scalars.
12319        for dot in dots_host.iter_mut() {
12320            let gate = *dot / (hidden as f32).sqrt();
12321            let magnitude = gate.abs().max(1e-6).sqrt();
12322            let signed = if gate > 0.0 {
12323                magnitude
12324            } else if gate < 0.0 {
12325                -magnitude
12326            } else {
12327                0.0
12328            };
12329            *dot = host_sigmoid(signed);
12330        }
12331
12332        prof_section(e, "ple.conv_write", || {
12333            for s in 0..streams {
12334                let g = e.htod(&dots_host[s * t..(s + 1) * t])?;
12335                let mut gated = e.zeros(t * hidden)?;
12336                e.add_scaled_rows(&value, &g, &mut gated, hidden, t)?;
12337                let mut normed = e.uninit(t * hidden)?;
12338                e.rms_norm(&gated, &ple.norm_conv[s], &mut normed, hidden, t, eps)?;
12339                // Verify stash: pre-chunk history + this chunk's normed rows (rewind
12340                // rebuild inputs; pure retains).
12341                if let Some(st) = stash.as_deref_mut() {
12342                    e.copy_range_into(
12343                        &mut st.hist_pre[s],
12344                        0,
12345                        &ple_state.conv_hist[s],
12346                        0,
12347                        pad * hidden,
12348                    )?;
12349                    e.copy_range_into(&mut st.normed_rows[s], 0, &normed, 0, t * hidden)?;
12350                }
12351                // out = gated + silu(dilated causal conv(normed)) — dwconv mode 2 adds in place.
12352                launch_dwconv(
12353                    e,
12354                    &normed,
12355                    &ple_state.conv_hist[s],
12356                    &ple.conv_w[s],
12357                    &mut gated,
12358                    t,
12359                    pad,
12360                    hidden,
12361                    kernel,
12362                    dilation,
12363                    2,
12364                )?;
12365                // conv history <- last `pad` NORMED rows.
12366                let hist = &mut ple_state.conv_hist[s];
12367                if t >= pad {
12368                    e.copy_range_into(hist, 0, &normed, (t - pad) * hidden, pad * hidden)?;
12369                } else {
12370                    let keep = pad - t;
12371                    let mut tmp = e.uninit(keep * hidden)?;
12372                    e.copy_range_into(&mut tmp, 0, hist, t * hidden, keep * hidden)?;
12373                    e.copy_range_into(hist, 0, &tmp, 0, keep * hidden)?;
12374                    e.copy_range_into(hist, keep * hidden, &normed, 0, t * hidden)?;
12375                }
12376                // wide stream gains the PLE output BEFORE the attention read gate.
12377                let mut view = planes[s].slice_mut(0..t * hidden);
12378                e.axpy_into(&gated, 1.0, &mut view, t * hidden)?;
12379            }
12380            Ok(())
12381        })
12382    }
12383}
12384
12385// ---------------------------------------------------------------- MTP draft (mtp-spec lane)
12386
12387/// The MTP draft's persistent state: its own QSA KV rows + indexer raw-key cache + a
12388/// dedicated step workspace. DRAFT CACHE ROW i HOLDS TARGET POSITION i + 1 (position 0
12389/// never enters the draft — its first input pairs token x_1 with trunk hidden h_0), so
12390/// every spec-loop forward runs at `pos_off = 1`; the reference-parity gate runs at
12391/// `pos_off = 0` to match the reference executor's row-indexed positions.
12392pub struct MtpDraftState {
12393    mixer: MixerState,
12394    /// Rows currently in the cache (committed + speculative chain rows).
12395    rows: usize,
12396    /// Rows whose inputs were TRUE trunk hidden states (survive a round). The spec loop
12397    /// truncates to here and replays accepted tokens with verify-produced hiddens.
12398    pub committed: usize,
12399    capacity: usize,
12400    ws: StepPool,
12401}
12402
12403impl MtpDraftState {
12404    pub fn rows(&self) -> usize {
12405        self.rows
12406    }
12407}
12408
12409/// The draft forward's token source (mtp11): host ids (the mtp10 program), host ids
12410/// GATHERED ON DEVICE from the full-vocab chain table (the defer arm's prefill/replay
12411/// shape — a 4t-byte htod replaces t 10 KB pageable embed rows, the spec.rs
12412/// embed_gather_device_t precedent), or ONE device slot holding the previous chain
12413/// step's RAW argmax (the deferred chain).
12414#[derive(Clone, Copy)]
12415enum DraftTokSrc<'a> {
12416    Host(&'a [u32]),
12417    HostDev(&'a [u32]),
12418    DevSlot(&'a CudaSlice<u32>, usize),
12419}
12420
12421impl Qwen4ExpGpu {
12422    pub fn has_mtp(&self) -> bool {
12423        self.mtp.is_some()
12424    }
12425
12426    /// Card-1 draft placement armed? (`load_from_dir_dev1` — the draft's device tensors
12427    /// live on `mtp_dev1.dev`, and every draft call must present an engine there.)
12428    pub fn mtp_on_dev1(&self) -> bool {
12429        self.mtp_dev1.is_some()
12430    }
12431
12432    /// The draft's device tensors were built on ONE engine; a call presenting another
12433    /// engine would launch kernels on the wrong context (UVA would make it "work"
12434    /// slowly instead of failing). Enforced, never assumed.
12435    fn check_draft_engine(&self, e: &Engine) -> Res<()> {
12436        if let Some(d) = self.mtp_dev1.as_ref() {
12437            if e.ctx().ordinal() != d.dev {
12438                return Err(format!(
12439                    "qwen4exp_gpu: the draft lives on device {} (card-1 placement); \
12440                     this call presented device {}",
12441                    d.dev,
12442                    e.ctx().ordinal()
12443                )
12444                .into());
12445            }
12446        }
12447        Ok(())
12448    }
12449
12450    /// Allocate the draft's persistent state (its own KV plane; `capacity` rows).
12451    /// With the card-1 placement, `e` must be the DRAFT engine.
12452    pub fn mtp_state(&self, e: &Engine, capacity: usize) -> Res<MtpDraftState> {
12453        self.check_draft_engine(e)?;
12454        let mtp = self
12455            .mtp
12456            .as_ref()
12457            .ok_or("qwen4exp_gpu: no MTP block loaded (LoadOptions::load_mtp)")?;
12458        let MixerW::Qsa(qsa) = &mtp.layer.mixer else {
12459            return Err("qwen4exp_gpu: MTP mixer is not QSA".into());
12460        };
12461        let kv_width = qsa.attn.kv_heads as usize * qsa.attn.key_head_dim as usize;
12462        let v_width = qsa.attn.kv_heads as usize * qsa.attn.value_head_dim as usize;
12463        // kvq/idxq: the draft's QSA cache follows the same latched formats as the trunk
12464        // (uniform storage; the spec byte-identity gates run same-config on both arms).
12465        let kv = if kv_quant_on() {
12466            QsaKvStore::Q8Q5 {
12467                k: e.alloc_u8(capacity * q8_row_bytes(kv_width))?,
12468                v: e.alloc_u8(capacity * q5_row_bytes(v_width))?,
12469            }
12470        } else {
12471            QsaKvStore::F32 {
12472                k: e.zeros(capacity * kv_width)?,
12473                v: e.zeros(capacity * v_width)?,
12474            }
12475        };
12476        Ok(MtpDraftState {
12477            mixer: MixerState::Qsa {
12478                kv,
12479                raw_keys: IdxRawCache::new(idxq_mode()),
12480                pooled_keys: Vec::new(),
12481                pooled_dev: None,
12482                pooled_dev_rows: 0,
12483                raw_dev: None,
12484                raw_dev_rows: 0,
12485                idx_audit: None,
12486            },
12487            rows: 0,
12488            committed: 0,
12489            capacity,
12490            ws: StepPool::default(),
12491        })
12492    }
12493
12494    /// Truncate the draft cache to `rows` (speculative chain rows die; KV rows are
12495    /// overwritten in place by the next append, the host raw-key cache truncates).
12496    pub fn mtp_rewind(&self, dstate: &mut MtpDraftState, rows: usize) -> Res<()> {
12497        if rows > dstate.rows {
12498            return Err("qwen4exp_gpu: mtp_rewind past the cache".into());
12499        }
12500        let mtp = self.mtp.as_ref().ok_or("qwen4exp_gpu: no MTP block")?;
12501        let MixerW::Qsa(qsa) = &mtp.layer.mixer else {
12502            return Err("qwen4exp_gpu: MTP mixer is not QSA".into());
12503        };
12504        let MixerState::Qsa {
12505            raw_keys,
12506            pooled_keys,
12507            pooled_dev_rows,
12508            raw_dev_rows,
12509            ..
12510        } = &mut dstate.mixer
12511        else {
12512            return Err("qwen4exp_gpu: MTP state is not QSA".into());
12513        };
12514        let idx_dim = qsa.overlay.head_dim as usize;
12515        raw_keys.truncate_rows(rows, idx_dim);
12516        let block = qsa.overlay.block_size as usize;
12517        pooled_keys.truncate((rows / block) * idx_dim);
12518        // The device mirror's row count MUST follow the host truncation, or the next
12519        // scorer call skips the H2D of rebuilt rows and scores STALE keys (caught by the
12520        // spec byte-identity arms).
12521        *pooled_dev_rows = (*pooled_dev_rows).min(pooled_keys.len() / idx_dim);
12522        // Device raw-key cache (idxcache): clamp to the ABSOLUTE kept row count — the
12523        // host cache may legitimately lag below it (the lazy materialization).
12524        *raw_dev_rows = (*raw_dev_rows).min(rows);
12525        dstate.rows = rows;
12526        dstate.committed = dstate.committed.min(rows);
12527        Ok(())
12528    }
12529
12530    /// One MTP draft forward over `t` rows (SEMANTICS.md §MTP): fused input =
12531    /// `fc_embedding(norm(embed(tok)))` broadcast over streams + per-stream
12532    /// `fc_hidden(FLAT norm(wide hidden))`; ONE QSA+MoE decoder layer on the draft's own
12533    /// cache; exit through the draft mixer into the SHARED lm_head. Returns
12534    /// `(logits [t, vocab], carrier [t, wide])` — the carrier is the POST-LAYER wide
12535    /// state, the K > 1 multi-step seed. Recycle both via `mtp_recycle`.
12536    ///
12537    /// `hidden_wide` rows start at row `wide_off` of the given buffer; row r seeds
12538    /// token r. `pos_off` = 1 in the spec loop (draft row i ↔ target position i+1),
12539    /// 0 in the reference-parity gate.
12540    #[allow(clippy::too_many_arguments)]
12541    pub fn mtp_draft_forward(
12542        &self,
12543        e: &Engine,
12544        tokens: &[u32],
12545        hidden_wide: &CudaSlice<f32>,
12546        wide_off: usize,
12547        dstate: &mut MtpDraftState,
12548        pos_off: usize,
12549        // true => logits for EVERY row (the parity gates); false => the LAST row only
12550        // (the spec loop's shape — earlier rows exist for the KV cache + carrier, and
12551        // the full-vocab head must not scale with the replay length).
12552        logits_all: bool,
12553    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
12554        self.mtp_draft_forward_impl(
12555            e,
12556            DraftTokSrc::Host(tokens),
12557            hidden_wide,
12558            wide_off,
12559            dstate,
12560            pos_off,
12561            logits_all,
12562        )
12563    }
12564
12565    /// One DEFERRED chain step (mtp11): the input token is the previous step's device
12566    /// argmax, read from `toks[slot]` (RAW draft-index space; embeds through the armed
12567    /// chain table). t == 1 by construction; `pos_off` is the spec loop's 1.
12568    fn mtp_draft_forward_devslot(
12569        &self,
12570        e: &Engine,
12571        toks: &CudaSlice<u32>,
12572        slot: usize,
12573        hidden_wide: &CudaSlice<f32>,
12574        wide_off: usize,
12575        dstate: &mut MtpDraftState,
12576    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
12577        self.mtp_draft_forward_impl(
12578            e,
12579            DraftTokSrc::DevSlot(toks, slot),
12580            hidden_wide,
12581            wide_off,
12582            dstate,
12583            1,
12584            false,
12585        )
12586    }
12587
12588    /// Spec-loop host-token draft forward (prefill / bootstrap / replay shapes):
12589    /// `dev_embed` keys the defer arm's device-gather embed (full-vocab chain table)
12590    /// vs the mtp10 host embed — the control arm stays byte- AND structure-frozen.
12591    fn mtp_draft_forward_spec(
12592        &self,
12593        e: &Engine,
12594        tokens: &[u32],
12595        dev_embed: bool,
12596        hidden_wide: &CudaSlice<f32>,
12597        wide_off: usize,
12598        dstate: &mut MtpDraftState,
12599    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
12600        let src = if dev_embed {
12601            DraftTokSrc::HostDev(tokens)
12602        } else {
12603            DraftTokSrc::Host(tokens)
12604        };
12605        self.mtp_draft_forward_impl(e, src, hidden_wide, wide_off, dstate, 1, false)
12606    }
12607
12608    /// `mtp_draft_forward_spec` over RING-slotted seed rows: absolute seed row
12609    /// `first_row + i` lives at slot `(first_row + i) % ring`, and a range crossing the
12610    /// ring seam splits into two draft calls. The split changes the draft GEMM shape on
12611    /// seam rounds (drafted tokens may differ there — acceptance-only; commits are
12612    /// always the target rows, so spec byte-identity is untouched by construction).
12613    /// Returns the LAST piece's (logits row, carrier, piece length).
12614    fn draft_consume_ring(
12615        &self,
12616        de: &Engine,
12617        tokens: &[u32],
12618        dev_embed: bool,
12619        seed: &CudaSlice<f32>,
12620        ring: usize,
12621        first_row: usize,
12622        dstate: &mut MtpDraftState,
12623    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>, usize)> {
12624        let mut out: Option<(CudaSlice<f32>, CudaSlice<f32>, usize)> = None;
12625        let mut done = 0usize;
12626        while done < tokens.len() {
12627            let slot = (first_row + done) % ring;
12628            let len = (tokens.len() - done).min(ring - slot);
12629            let (l, c) = self.mtp_draft_forward_spec(
12630                de,
12631                &tokens[done..done + len],
12632                dev_embed,
12633                seed,
12634                slot,
12635                dstate,
12636            )?;
12637            if let Some((pl, pc, _)) = out.take() {
12638                self.mtp_recycle(dstate, pl, pc);
12639            }
12640            out = Some((l, c, len));
12641            done += len;
12642        }
12643        out.ok_or("qwen4exp_gpu: empty draft consume".into())
12644    }
12645
12646    #[allow(clippy::too_many_arguments)]
12647    fn mtp_draft_forward_impl(
12648        &self,
12649        e: &Engine,
12650        tok_src: DraftTokSrc<'_>,
12651        hidden_wide: &CudaSlice<f32>,
12652        wide_off: usize,
12653        dstate: &mut MtpDraftState,
12654        pos_off: usize,
12655        logits_all: bool,
12656    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
12657        self.check_draft_engine(e)?;
12658        let mtp = self
12659            .mtp
12660            .as_ref()
12661            .ok_or("qwen4exp_gpu: no MTP block loaded (LoadOptions::load_mtp)")?;
12662        let t = match tok_src {
12663            DraftTokSrc::Host(tokens) | DraftTokSrc::HostDev(tokens) => tokens.len(),
12664            DraftTokSrc::DevSlot(..) => 1,
12665        };
12666        let hidden = self.hidden;
12667        let streams = self.streams;
12668        let wide = streams * hidden;
12669        if t == 0 {
12670            return Err("qwen4exp_gpu: empty draft input".into());
12671        }
12672        if dstate.rows + t > dstate.capacity {
12673            return Err("qwen4exp_gpu: draft state capacity exceeded".into());
12674        }
12675        if hidden_wide.len() < (wide_off + t) * wide {
12676            return Err("qwen4exp_gpu: draft hidden seed rows out of range".into());
12677        }
12678        let base = dstate.rows;
12679        let ws = &mut dstate.ws;
12680        let cap = dstate.capacity;
12681
12682        // ---- input fusion
12683        let mut planes = prof_section(e, "mtp.fuse", || {
12684            let emb = match tok_src {
12685                DraftTokSrc::Host(tokens) => {
12686                    let mut embedded = vec![0.0f32; t * hidden];
12687                    for (row, &token) in tokens.iter().enumerate() {
12688                        let token = token as usize;
12689                        if token >= self.vocab {
12690                            return Err(
12691                                format!("qwen4exp_gpu: draft token {token} out of range").into()
12692                            );
12693                        }
12694                        embedded[row * hidden..(row + 1) * hidden].copy_from_slice(
12695                            &self.embed_host[token * hidden..(token + 1) * hidden],
12696                        );
12697                    }
12698                    ws.take_f32_h2d(e, "mtp.emb", &embedded, cap * hidden)?
12699                }
12700                DraftTokSrc::HostDev(tokens) => {
12701                    // Defer arm's prefill/replay embed (mtp11): host ids validated
12702                    // here, then a 4t-byte htod + device gather from the FULL-VOCAB
12703                    // chain table — bit-identical rows (ChainEmbed contract), no
12704                    // t x 10 KB pageable h2d. The caller keys this on a full-vocab
12705                    // table (a trim table cannot embed arbitrary target ids).
12706                    let ce = self
12707                        .chain_embed
12708                        .as_ref()
12709                        .filter(|ce| !ce.for_trim && ce.rows == self.vocab)
12710                        .ok_or("qwen4exp_gpu: HostDev embed needs the full-vocab chain table")?;
12711                    for &token in tokens {
12712                        if token as usize >= self.vocab {
12713                            return Err(
12714                                format!("qwen4exp_gpu: draft token {token} out of range").into()
12715                            );
12716                        }
12717                    }
12718                    let tok_d = e.gpu.stream().clone_htod(tokens)?;
12719                    let mut emb = ws.take_f32(e, "mtp.emb", t * hidden, cap * hidden)?;
12720                    let tv = tok_d.slice(0..t);
12721                    embed_gather_rows_into(
12722                        e,
12723                        &ce.table,
12724                        &tv,
12725                        &mut emb,
12726                        t,
12727                        hidden,
12728                        ce.qt,
12729                        ce.row_bytes,
12730                    )?;
12731                    emb
12732                }
12733                DraftTokSrc::DevSlot(toks, slot) => {
12734                    // Deferred chain (mtp11): gather THE row for the RAW draft index
12735                    // in `toks[slot]` from the armed chain table — bit-identical to
12736                    // the host row (ChainEmbed contract), no host round trip of the
12737                    // token id, no pageable h2d. Index bound is by construction:
12738                    // the argmax that wrote the slot scanned exactly `rows` columns.
12739                    let ce = self
12740                        .chain_embed
12741                        .as_ref()
12742                        .ok_or("qwen4exp_gpu: deferred draft step without arm_spec_devchain")?;
12743                    let mut emb = ws.take_f32(e, "mtp.emb", hidden, cap * hidden)?;
12744                    let tv = toks.slice(slot..slot + 1);
12745                    embed_gather_rows_into(
12746                        e,
12747                        &ce.table,
12748                        &tv,
12749                        &mut emb,
12750                        1,
12751                        hidden,
12752                        ce.qt,
12753                        ce.row_bytes,
12754                    )?;
12755                    emb
12756                }
12757            };
12758            let mut enorm = ws.take_f32(e, "mtp.enorm", t * hidden, 0)?;
12759            e.rms_norm(
12760                &emb,
12761                &mtp.pre_norm_embed,
12762                &mut enorm,
12763                hidden,
12764                t,
12765                mtp.eps_embed,
12766            )?;
12767            let mut evec = ws.take_f32(e, "mtp.evec", t * hidden, 0)?;
12768            linear_trunk_into(
12769                e,
12770                &mtp.fc_embed,
12771                &mtp.fc_embed_b16,
12772                &enorm,
12773                &mut evec,
12774                t,
12775                hidden,
12776                hidden,
12777            )?;
12778            // Stage the seed rows at offset 0 (exact copy), then FLAT-norm the whole
12779            // wide vector per token (GemmaRMSNorm_wide — SEMANTICS.md §MTP).
12780            let mut hin = ws.take_f32(e, "mtp.hin", t * wide, 0)?;
12781            e.copy_range_into(&mut hin, 0, hidden_wide, wide_off * wide, t * wide)?;
12782            let mut hnorm = ws.take_f32(e, "mtp.hnorm", t * wide, 0)?;
12783            e.rms_norm(
12784                &hin,
12785                &mtp.pre_norm_hidden,
12786                &mut hnorm,
12787                wide,
12788                t,
12789                mtp.eps_hidden,
12790            )?;
12791            // fc_hidden per stream = the same [H, H] mat over every (token, stream) row
12792            // of the normed wide buffer viewed [t*streams, H].
12793            let mut fused = ws.take_f32(e, "mtp.fused", t * wide, 0)?;
12794            linear_trunk_into(
12795                e,
12796                &mtp.fc_hidden,
12797                &mtp.fc_hidden_b16,
12798                &hnorm,
12799                &mut fused,
12800                t * streams,
12801                hidden,
12802                hidden,
12803            )?;
12804            let mut planes: Vec<CudaSlice<f32>> = Vec::with_capacity(streams);
12805            for s in 0..streams {
12806                let mut plane = ws.take_f32(e, PLANE_SLOTS[s], t * hidden, cap * hidden)?;
12807                for tok in 0..t {
12808                    e.copy_range_into(
12809                        &mut plane,
12810                        tok * hidden,
12811                        &fused,
12812                        (tok * streams + s) * hidden,
12813                        hidden,
12814                    )?;
12815                }
12816                let mut view = plane.slice_mut(0..t * hidden);
12817                e.axpy_into(&evec, 1.0, &mut view, t * hidden)?;
12818                planes.push(plane);
12819            }
12820            ws.put_f32("mtp.emb", emb);
12821            ws.put_f32("mtp.enorm", enorm);
12822            ws.put_f32("mtp.evec", evec);
12823            ws.put_f32("mtp.hin", hin);
12824            ws.put_f32("mtp.hnorm", hnorm);
12825            ws.put_f32("mtp.fused", fused);
12826            Ok(planes)
12827        })?;
12828
12829        let ptr_vals: Vec<u64> = {
12830            let stream = e.gpu.stream();
12831            planes.iter().map(|p| p.device_ptr(&stream).0).collect()
12832        };
12833        let ptrs = ws.take_u64_h2d(e, "hc.ptrs", &ptr_vals, 0)?;
12834
12835        // ---- the one decoder layer (trunk program, draft weights/cache)
12836        let layer = &mtp.layer;
12837        let (mixed, inject) = prof_section(e, "mtp.hyper.read", || {
12838            self.gate_read(
12839                e,
12840                ws,
12841                &ptrs,
12842                &layer.attn_gate,
12843                &planes,
12844                t,
12845                layer.eps_attn,
12846                false,
12847            )
12848        })?;
12849        let MixerW::Qsa(qsa) = &layer.mixer else {
12850            return Err("qwen4exp_gpu: MTP mixer is not QSA".into());
12851        };
12852        let block_out = prof_section(e, "mtp.qsa", || {
12853            self.qsa_forward(
12854                e,
12855                ws,
12856                layer,
12857                qsa,
12858                &mixed,
12859                &mut dstate.mixer,
12860                base,
12861                t,
12862                pos_off,
12863                false,
12864            )
12865        })?;
12866        ws.put_f32("hc.mixed", mixed);
12867        prof_section(e, "mtp.hyper.write", || {
12868            self.gate_write(e, &mut planes, &ptrs, &block_out, &inject, t)
12869        })?;
12870        ws.put_f32("mixer.out", block_out);
12871        put_inject(ws, inject);
12872        let (mixed, inject) = prof_section(e, "mtp.hyper.read", || {
12873            self.gate_read(
12874                e,
12875                ws,
12876                &ptrs,
12877                &layer.mlp_gate,
12878                &planes,
12879                t,
12880                layer.eps_mlp,
12881                false,
12882            )
12883        })?;
12884        let mlp = prof_section(e, "mtp.moe", || {
12885            // Rows mode for chain/replay shapes; the big draft PREFILL takes the
12886            // per-expert executor (each expert's rows widen once for all its tokens).
12887            self.moe_forward(e, ws, &layer.moe, &mixed, t, t <= 32, layer.index)
12888        })?;
12889        ws.put_f32("hc.mixed", mixed);
12890        prof_section(e, "mtp.hyper.write", || {
12891            self.gate_write(e, &mut planes, &ptrs, &mlp, &inject, t)
12892        })?;
12893        ws.put_f32("moe.out", mlp);
12894        put_inject(ws, inject);
12895
12896        // ---- carrier (post-layer wide state, PRE exit mixer — the K>1 seed)
12897        let mut carrier = ws.take_f32(e, "mtp.carrier", t * wide, 0)?;
12898        for (s, plane) in planes.iter().enumerate() {
12899            for tok in 0..t {
12900                e.copy_range_into(
12901                    &mut carrier,
12902                    tok * wide + s * hidden,
12903                    plane,
12904                    tok * hidden,
12905                    hidden,
12906                )?;
12907            }
12908        }
12909
12910        // ---- exit: the draft's own mixer read (no inject) -> shared lm_head.
12911        // Only the LAST row's logits are ever consumed (chain steps run t == 1; the
12912        // replay/prefill rows exist for the KV cache and the carrier), so the head
12913        // reads one hidden row — the full-vocab matvec is the draft's single largest
12914        // cost (mtp4 profile) and must not scale with the replay length.
12915        let x = prof_section(e, "mtp.exit", || {
12916            Ok(self
12917                .gate_read_inner(
12918                    e,
12919                    ws,
12920                    &ptrs,
12921                    &mtp.mixer,
12922                    &planes,
12923                    t,
12924                    self.exit_eps,
12925                    false,
12926                    false,
12927                )?
12928                .0)
12929        })?;
12930        ws.put_u64("hc.ptrs", ptrs);
12931        // The head is the SHARED trunk head, or its FR-Spec trimmed gather when the draft
12932        // trim is armed (mtp9): out_f drops from the 248,320 vocab to N, which is the
12933        // draft's single largest cost. Same bytes either way — a trimmed row's logit is
12934        // bit-identical to its full-vocab twin.
12935        let trim = self.draft_trim.as_ref();
12936        let out_f = trim.map_or(self.vocab, |t| t.n);
12937        // Card-1 placement reads its private head copy (same bytes, same program);
12938        // otherwise the shared trunk head. Trim + dev1 is refused at build time.
12939        let (head_w, head_b16) = match self.mtp_dev1.as_ref() {
12940            Some(d) => (&d.output, &d.output_b16),
12941            None => (&self.output, &self.output_b16),
12942        };
12943        let head_into =
12944            |e: &Engine, x: &CudaSlice<f32>, y: &mut CudaSlice<f32>, rows: usize| -> Res<()> {
12945                match trim {
12946                    Some(trim) => linear_trim_into(e, trim, x, y, rows, hidden),
12947                    None => linear_trunk_into(e, head_w, head_b16, x, y, rows, hidden, self.vocab),
12948                }
12949            };
12950        let logits = prof_section(e, "mtp.lm_head", || {
12951            if logits_all {
12952                let mut logits = ws.take_f32(e, "mtp.logits", t * out_f, 0)?;
12953                head_into(e, &x, &mut logits, t)?;
12954                return Ok(logits);
12955            }
12956            let mut logits = ws.take_f32(e, "mtp.logits", out_f, 0)?;
12957            let mut x_last = ws.take_f32(e, "mtp.xlast", hidden, 0)?;
12958            e.copy_range_into(&mut x_last, 0, &x, (t - 1) * hidden, hidden)?;
12959            head_into(e, &x_last, &mut logits, 1)?;
12960            ws.put_f32("mtp.xlast", x_last);
12961            Ok(logits)
12962        })?;
12963        ws.put_f32("hc.mixed", x);
12964        for (s, plane) in planes.into_iter().enumerate() {
12965            ws.put_f32(PLANE_SLOTS[s], plane);
12966        }
12967        dstate.rows += t;
12968        Ok((logits, carrier))
12969    }
12970
12971    /// Return a draft step's logits/carrier buffers to the draft workspace (address
12972    /// reuse across the hot loop).
12973    pub fn mtp_recycle(
12974        &self,
12975        dstate: &mut MtpDraftState,
12976        logits: CudaSlice<f32>,
12977        carrier: CudaSlice<f32>,
12978    ) {
12979        dstate.ws.put_f32("mtp.logits", logits);
12980        dstate.ws.put_f32("mtp.carrier", carrier);
12981    }
12982}
12983
12984// ---------------------------------------------------------------- spec decode (mtp-spec lane)
12985
12986/// Vendor-default sampling config for the SAMPLED spec run (the serving law's probe
12987/// shape): temp 1.0 / top_p 0.95 / top_k 20 on qwen4_exp. Greedy (None) stays the
12988/// byte-identity instrument.
12989#[derive(Clone, Copy)]
12990pub struct SpecSamplerCfg {
12991    pub temperature: f32,
12992    pub top_p: f32,
12993    pub top_k: usize,
12994    pub seed: u64,
12995}
12996
12997/// xorshift64* — deterministic, seedable, dependency-free (receipt reproducibility).
12998struct SpecRng(u64);
12999
13000impl SpecRng {
13001    fn next_f32(&mut self) -> f32 {
13002        let mut x = self.0;
13003        x ^= x >> 12;
13004        x ^= x << 25;
13005        x ^= x >> 27;
13006        self.0 = x;
13007        let bits = (x.wrapping_mul(0x2545_F491_4F6C_DD1D) >> 40) as u32;
13008        bits as f32 / (1u64 << 24) as f32
13009    }
13010}
13011
13012/// Host top-k/top-p/temperature sample over one logits row.
13013fn sample_row(cfg: &SpecSamplerCfg, rng: &mut SpecRng, row: &[f32]) -> u32 {
13014    let k = cfg.top_k.max(1).min(row.len());
13015    let mut idx: Vec<u32> = (0..row.len() as u32).collect();
13016    idx.select_nth_unstable_by(k - 1, |&a, &b| row[b as usize].total_cmp(&row[a as usize]));
13017    let mut top: Vec<(u32, f32)> = idx[..k].iter().map(|&i| (i, row[i as usize])).collect();
13018    top.sort_by(|a, b| b.1.total_cmp(&a.1));
13019    let temp = cfg.temperature.max(1e-6);
13020    let mx = top[0].1;
13021    let mut probs: Vec<f32> = top.iter().map(|&(_, v)| ((v - mx) / temp).exp()).collect();
13022    let sum: f32 = probs.iter().sum();
13023    for p in &mut probs {
13024        *p /= sum;
13025    }
13026    // top_p nucleus over the sorted tail.
13027    let mut cut = probs.len();
13028    let mut acc = 0.0f32;
13029    for (i, &p) in probs.iter().enumerate() {
13030        acc += p;
13031        if acc >= cfg.top_p {
13032            cut = i + 1;
13033            break;
13034        }
13035    }
13036    let renorm: f32 = probs[..cut].iter().sum();
13037    let draw = rng.next_f32() * renorm;
13038    let mut acc = 0.0f32;
13039    for (i, &p) in probs[..cut].iter().enumerate() {
13040        acc += p;
13041        if draw < acc {
13042            return top[i].0;
13043        }
13044    }
13045    top[cut - 1].0
13046}
13047
13048/// Host argmax with the plain chain's tie rule (strictly-greater keeps the smallest
13049/// index) — bit-identical to the device 2-pass argmax (argmax-gate contract), which is
13050/// what lets the trace and plain-tail paths commit host argmaxes without moving a chain.
13051fn host_argmax(row: &[f32]) -> usize {
13052    let mut best = 0usize;
13053    for (i, &v) in row.iter().enumerate() {
13054        if v > row[best] {
13055            best = i;
13056        }
13057    }
13058    best
13059}
13060
13061/// P2P-copy `t` wide rows at row offset `off` from the card-0 verify wide stash into
13062/// the card-1 mirror (mtp10 dev1 draft placement), issued on the DRAFT engine's stream
13063/// and host-synced — the sync is where the crossing is TIMED, and the draft's next
13064/// kernels queue behind the copy on the same stream either way. Host ordering
13065/// guarantees the source rows are complete: every call site sits after a `forward`
13066/// whose host dtoh (logits or argmax) synced card 0's stream.
13067/// Ring-contiguous pieces of an absolute wide-row range [off, off+t): (slot_off, len)
13068/// per piece — one piece unless the range crosses the ring seam (then two). Identity
13069/// slots when ring >= off + t never wraps (the historical whole-history stash).
13070fn ring_pieces(ring: usize, off: usize, t: usize) -> Vec<(usize, usize)> {
13071    debug_assert!(t <= ring, "wide-ring consumer wider than the ring");
13072    let slot = off % ring;
13073    if slot + t <= ring {
13074        vec![(slot, t)]
13075    } else {
13076        vec![(slot, ring - slot), (0, t - (ring - slot))]
13077    }
13078}
13079
13080fn cross_wide_rows(
13081    e: &Engine,
13082    de: &Engine,
13083    src: &CudaSlice<f32>,
13084    dst: &mut CudaSlice<f32>,
13085    off: usize,
13086    t: usize,
13087    wide: usize,
13088) -> Res<f64> {
13089    let t0 = std::time::Instant::now();
13090    let stream = de.gpu.stream();
13091    let bytes = t * wide * 4;
13092    let byte_off = (off * wide * 4) as u64;
13093    let (sp, _g0) = src.device_ptr(&stream);
13094    let (dp, _g1) = dst.device_ptr_mut(&stream);
13095    unsafe {
13096        cudarc::driver::result::memcpy_peer_async(
13097            de.ctx().cu_ctx(),
13098            dp + byte_off,
13099            e.ctx().cu_ctx(),
13100            sp + byte_off,
13101            bytes,
13102            stream.cu_stream(),
13103        )?;
13104    }
13105    stream.synchronize()?;
13106    Ok(t0.elapsed().as_secs_f64() * 1e3)
13107}
13108
13109/// Launch `embed_gather_u32_t` for ONE device-slot token into the pooled `mtp.emb`
13110/// buffer (mtp11 deferred chain). Same kernel as the lib.rs `embed_gather_device_*`
13111/// family — bit-identical rows by the same per-dtype deq contract. Lives here (not as
13112/// an Engine method) because the deferred chain is this module's machinery.
13113fn embed_gather_rows_into(
13114    e: &Engine,
13115    table: &CudaSlice<u8>,
13116    tok_v: &CudaView<u32>,
13117    x_out: &mut CudaSlice<f32>,
13118    t: usize,
13119    n_embd: usize,
13120    qtype: i32,
13121    row_bytes: usize,
13122) -> Res<()> {
13123    let f = e.func("embed_gather_u32_t");
13124    let cfg = LaunchConfig {
13125        grid_dim: (((n_embd as u32).div_ceil(256)).max(1), t as u32, 1),
13126        block_dim: (256, 1, 1),
13127        shared_mem_bytes: 0,
13128    };
13129    let (ne, qt, rb, ti) = (n_embd as i32, qtype, row_bytes as i64, t as i32);
13130    let stream = e.gpu.stream();
13131    let mut b = stream.launch_builder(&f);
13132    b.arg(table)
13133        .arg(tok_v)
13134        .arg(x_out)
13135        .arg(&ne)
13136        .arg(&qt)
13137        .arg(&rb)
13138        .arg(&ti);
13139    unsafe {
13140        b.launch(cfg)?;
13141    }
13142    Ok(())
13143}
13144
13145/// One spec run's counters (the accept-length table's source).
13146#[derive(Debug, Default, Clone)]
13147pub struct SpecReport {
13148    pub tokens: Vec<u32>,
13149    pub rounds: usize,
13150    pub drafted: u64,
13151    pub accepted: u64,
13152    /// hist[a] = rounds that accepted exactly `a` drafts (a in 0..=k).
13153    pub accept_hist: Vec<u64>,
13154    pub draft_ms: f64,
13155    pub verify_ms: f64,
13156    pub prefill_ms: f64,
13157    pub total_ms: f64,
13158    /// draft_ms split (the round-cost identity table): the K-step chain, the accepted-
13159    /// token catch-up replay, and the one-time draft prefill. draft_ms is their sum.
13160    pub chain_ms: f64,
13161    pub replay_ms: f64,
13162    pub draft_prefill_ms: f64,
13163    /// Card-1 crossing cost (mtp10 dev1 placement): wall time and bytes of the P2P
13164    /// wide-row copies (prefill seed + per-round replay seeds). 0 on one card.
13165    pub cross_ms: f64,
13166    pub cross_bytes: u64,
13167    /// Dynamic-K admission (mtp10): every decay as (round, new_k). Empty = K never moved.
13168    pub k_decays: Vec<(usize, usize)>,
13169    /// Token count at which the policy turned spec fully OFF (k reached 0); the rest of
13170    /// the generation ran plain decode steps (counted in `plain_steps`, not `rounds`).
13171    pub spec_off_at: Option<usize>,
13172    pub plain_steps: usize,
13173    /// Per-round wall samples: (tokens committed so far, ms since generation start),
13174    /// appended after every round/plain step — lets a caller derive N timing sub-rounds
13175    /// from ONE generation (the x3-rounds protocol where a fresh prefill per timing
13176    /// round is prohibitive, e.g. the 1M ladder).
13177    pub round_wall: Vec<(usize, f64)>,
13178    /// p-min guard accounting: rounds that drafted NOTHING (verify = plain t==1 step)
13179    /// and chain steps cut short (the sub-threshold token discarded uncounted).
13180    pub zero_draft_rounds: usize,
13181    pub guard_stops: usize,
13182}
13183
13184/// Bounded shape-aware spec admission (mtp10): rolling-accept-driven K decay. Every
13185/// round pushes its accept count into a window of the last `window` rounds; when the
13186/// window is full and its mean accept < `thr` (draft tokens per round, 0..=k), K steps
13187/// DOWN by one (never up — decay only, bounded and monotone) and the window resets so
13188/// decays are at least `window` rounds apart. At K = `k_floor` the decay stops; with
13189/// `k_floor` = 0 reaching it turns spec OFF for the REST of the generation (plain
13190/// greedy decode steps — the draft cost is what the collapsed shape was paying for).
13191/// Byte identity is untouched BY CONSTRUCTION at every K: committed tokens are always
13192/// the target rows' argmax, and the plain tail IS the plain program.
13193#[derive(Clone, Copy, Debug)]
13194pub struct DynKCfg {
13195    pub window: usize,
13196    pub thr: f64,
13197    pub k_floor: usize,
13198}
13199
13200/// Spec-round admission options (mtp10). Every knob defaults OFF; each is a bounded
13201/// policy that can only shrink the drafted window — the committed output is the target
13202/// rows' argmax at every setting, so byte identity is untouched by construction.
13203#[derive(Clone, Copy, Debug, Default)]
13204pub struct SpecOpts {
13205    /// Rolling-window K decay (the last-resort shape bound). See `DynKCfg`.
13206    pub dynk: Option<DynKCfg>,
13207    /// Adaptive per-round window (the dflash MEMRA_DFLASH_ADAPT "accepted+1" recipe):
13208    /// next round drafts clamp(last_accept + 1, k_lo, k). `Some(k_lo)` arms it.
13209    pub adapt_k_lo: Option<usize>,
13210    /// p-min draft-confidence guard (the MEMRA_SPEC_PMIN mechanism, sub-threshold token
13211    /// DISCARDED UNCOUNTED — the reference engines' normalization). Applies at j == 0
13212    /// too (the MEMRA_SPEC_PMIN0 zero-draft-round semantics): a low-confidence round
13213    /// drafts NOTHING and its verify is a plain t == 1 step that still commits one
13214    /// token — unpredictable stretches never pay draft + verify-column overhead.
13215    /// 0.0 = off.
13216    pub pmin: f32,
13217    /// Deferred round readback (mtp11, the spec.rs slice-2 structure ported): the
13218    /// chain's argmax feeds the next step ON DEVICE through the armed chain-embed
13219    /// table (`arm_spec_devchain` required), the guard's confidences land in device
13220    /// slots, and the chain drains ONCE per round before the verify (the PLE host
13221    /// n-gram gather needs the chunk's token ids, so this family's floor is a 2-drain
13222    /// round, not spec.rs's 1). t == 1 steps take the device-argmax fast path and the
13223    /// prefill dtoh shrinks to one row. Committed bytes identical BY CONSTRUCTION
13224    /// (same kernels, same picks; spec-gate arbitrates). Default OFF (flags law);
13225    /// mutually exclusive with `trace` (trace reads per-step host rows).
13226    pub defer: bool,
13227    /// With `defer` + `pmin`: keep the guard SEQUENTIAL — one 4-byte prob dtoh per
13228    /// chain step, the chain stops exactly at the sub-threshold step (today's cost
13229    /// shape). Default OFF = the deferred guard: probabilities drain with the chain
13230    /// and truncate at the FIRST sub-threshold step — same picks and counters
13231    /// bit-for-bit, but the dispatched suffix past the stop is work the sequential
13232    /// arm never paid. The guard-forces-a-readback A/B the owner asked to measure.
13233    pub defer_guard_sync: bool,
13234    /// Long-context lane: chunked co-prefill (trunk chunk forward with the head
13235    /// skipped, then the draft consumes that chunk's wide rows) instead of the one-shot
13236    /// prompt forward — the one-shot shape at 500k+ would materialize chunk-sized
13237    /// transients per plane AND a [n, vocab] logits block. `None` = the historical
13238    /// one-shot (byte-stable receipts).
13239    pub prefill_chunk: Option<usize>,
13240    /// Long-context lane: RING-bounded wide stash rows (`spec_arm_ring`) — at 1M
13241    /// capacity the whole-history stash is ~41 GB/card. Requires `prefill_chunk` (the
13242    /// co-prefill consumes each chunk before the ring overwrites it) and must be
13243    /// >= 2 * prefill_chunk. `None` = whole-history (the historical layout).
13244    pub wide_ring: Option<usize>,
13245}
13246
13247/// The deferred guard's drain-time truncation (mtp11): the FIRST sub-threshold
13248/// confidence (predicate `p < pmin` — the host chain's exact stop rule, boundary
13249/// p == pmin PASSES) ends the drafted window; picks before it survive, the
13250/// sub-threshold pick is discarded uncounted, everything after is dispatch the
13251/// sequential arm never paid. Pure so the tiny gate can pin the walk on arbitrary
13252/// windows: mid-chain dips are unreachable on the deterministic tiny fixture
13253/// (intra-round confidence never crosses a passed threshold there), so this pin plus
13254/// the real-model `--defer-ab` counter identity are the mid-chain coverage.
13255pub fn spec_guard_trunc(probs: &[f32], pmin: f32) -> usize {
13256    probs.iter().position(|&p| p < pmin).unwrap_or(probs.len())
13257}
13258
13259/// One traced spec round (the mtp10 thinkon-decay diagnosis instrument). Trace mode
13260/// changes NOTHING the accept walk sees — it only reads: draft logit rows, carrier
13261/// seeds, and the verify's captured wide rows come to host for margin/drift stats.
13262/// (Greedy trace runs with host-argmax targets — the same argmax the plain chain uses,
13263/// proven equal to the device walk by the spec-gate.)
13264#[derive(Debug, Default, Clone)]
13265pub struct SpecTraceRound {
13266    pub round: usize,
13267    /// Committed generation length BEFORE this round (position within the generation).
13268    pub gen_pos: usize,
13269    /// Trunk committed rows before the round (the tip's absolute position).
13270    pub base: usize,
13271    pub k: usize,
13272    pub a: usize,
13273    pub drafts: Vec<u32>,
13274    /// k+1 target rows (the committed prefix is targets[0..=a]).
13275    pub targets: Vec<u32>,
13276    /// Fork-row stats (row `a`, present when a < k): the draft's top-2 logits, the
13277    /// draft's logit and rank of the token the TARGET wanted, the target's top-2 logits,
13278    /// the target's logit of the token the DRAFT proposed, and the target row's softmax
13279    /// entropy (nats). NaN/0 when the round accepted everything (no fork).
13280    pub draft_top1: f32,
13281    pub draft_top2: f32,
13282    pub draft_tgt_logit: f32,
13283    pub draft_tgt_rank: usize,
13284    pub target_top1: f32,
13285    pub target_top2: f32,
13286    pub target_draft_logit: f32,
13287    pub target_entropy: f64,
13288    /// Carrier drift per carrier-seeded chain step j = 1..k-1: the seed the draft used
13289    /// (its own predicted wide for position base+j-1) vs the trunk's TRUE wide row at
13290    /// that position (captured by the verify chunk). rel_l2 = ||seed-true||/||true||.
13291    pub carrier_rel_l2: Vec<f32>,
13292    pub carrier_cos: Vec<f32>,
13293}
13294
13295impl SpecReport {
13296    pub fn accept_rate(&self) -> f64 {
13297        if self.drafted == 0 {
13298            0.0
13299        } else {
13300            self.accepted as f64 / self.drafted as f64
13301        }
13302    }
13303    /// Mean committed tokens per round (accepted + bonus).
13304    pub fn mean_accept_len(&self) -> f64 {
13305        if self.rounds == 0 {
13306            0.0
13307        } else {
13308            self.tokens.len() as f64 / self.rounds as f64
13309        }
13310    }
13311}
13312
13313impl Qwen4ExpGpu {
13314    /// Arm the verify instrument on `state`: absolute-position wide capture (the
13315    /// draft's hidden seeds) + per-column GDN/PLE stashes for chunks up to `k_cap`
13316    /// columns. Idempotent for the same k_cap.
13317    pub fn spec_arm(&self, e: &Engine, state: &mut Qwen4ExpState, k_cap: usize) -> Res<()> {
13318        self.spec_arm_ring(e, state, k_cap, state.capacity)
13319    }
13320
13321    /// `spec_arm` with a RING-bounded wide stash (long-context lane): the stash holds the
13322    /// last `ring_rows` wide rows (slot = row % ring_rows) instead of `capacity` rows —
13323    /// at 1M capacity the full stash is ~41 GB/card, the ring ~0.7 GB. Every consumer
13324    /// reads rows within `ring_rows` of the write head (chunked co-prefill consumes each
13325    /// chunk before the next lands; rounds read the last k+2 rows), asserted at the read
13326    /// helpers. `spec_arm` (ring = capacity) keeps the historical byte-stable layout.
13327    pub fn spec_arm_ring(
13328        &self,
13329        e: &Engine,
13330        state: &mut Qwen4ExpState,
13331        k_cap: usize,
13332        ring_rows: usize,
13333    ) -> Res<()> {
13334        let ring_rows = ring_rows.min(state.capacity).max(k_cap + 2);
13335        if let Some(v) = state.verify.as_ref() {
13336            if v.k_cap == k_cap && v.ring_rows == ring_rows {
13337                return Ok(());
13338            }
13339        }
13340        let wide = self.streams * self.hidden;
13341        let mut gdn = Vec::with_capacity(self.layers.len());
13342        let mut ple = Vec::with_capacity(self.layers.len());
13343        for layer in &self.layers {
13344            gdn.push(match &layer.mixer {
13345                MixerW::Gdn(g) => {
13346                    let p = &g.plan;
13347                    let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
13348                    let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
13349                    let conv_dim = 2 * nk * hk + nv * hv;
13350                    let pad = p.conv_kernel as usize - 1;
13351                    Some(GdnStash {
13352                        states: e.zeros(k_cap * nv * hv * hk)?,
13353                        conv_pre: e.zeros(pad * conv_dim)?,
13354                        qkv_rows: e.zeros(k_cap * conv_dim)?,
13355                        scan_graph: None,
13356                        scan_warm: None,
13357                    })
13358                }
13359                MixerW::Qsa(_) => None,
13360            });
13361            ple.push(match layer.ple.as_ref() {
13362                Some(pw) => {
13363                    let pad = (pw.plan.conv_kernel as usize - 1) * pw.plan.max_ngram as usize;
13364                    let mut hist_pre = Vec::with_capacity(self.streams);
13365                    let mut normed_rows = Vec::with_capacity(self.streams);
13366                    for _ in 0..self.streams {
13367                        hist_pre.push(e.zeros(pad * self.hidden)?);
13368                        normed_rows.push(e.zeros(k_cap * self.hidden)?);
13369                    }
13370                    Some(PleStash {
13371                        hist_pre,
13372                        normed_rows,
13373                    })
13374                }
13375                None => None,
13376            });
13377        }
13378        state.verify = Some(VerifyStash {
13379            k_cap,
13380            chunk: None,
13381            gdn,
13382            ple,
13383            wide: e.zeros(ring_rows * wide)?,
13384            ring_rows,
13385            wide_dev1: None,
13386            argmax: Vec::new(),
13387            toks: unsafe { e.gpu.stream().alloc::<u32>(k_cap)? },
13388            want_argmax: false,
13389            want_argmax_t1: false,
13390            last_row_only: false,
13391        });
13392        Ok(())
13393    }
13394
13395    pub fn spec_disarm(&self, state: &mut Qwen4ExpState) {
13396        state.verify = None;
13397    }
13398
13399    pub fn set_verify_want_argmax(&self, state: &mut Qwen4ExpState, on: bool) -> Res<()> {
13400        state
13401            .verify
13402            .as_mut()
13403            .ok_or("qwen4exp_gpu: verify not armed")?
13404            .want_argmax = on;
13405        Ok(())
13406    }
13407
13408    /// The last exact chunk's per-row device-argmax tokens (want_argmax mode).
13409    pub fn verify_argmax_rows<'s>(&self, state: &'s Qwen4ExpState) -> Res<&'s [u32]> {
13410        Ok(&state
13411            .verify
13412            .as_ref()
13413            .ok_or("qwen4exp_gpu: verify not armed")?
13414            .argmax)
13415    }
13416
13417    /// Rewind the trunk state to the first `keep` rows of the live verify chunk:
13418    /// bookkeeping truncation + GDN state restore from the per-column snapshots + GDN/
13419    /// PLE conv-history rebuild from the stashed pre-chunk history and chunk rows.
13420    /// `keep == t` is the all-accepted fast path (state already correct).
13421    pub fn verify_rewind(&self, e: &Engine, state: &mut Qwen4ExpState, keep: usize) -> Res<()> {
13422        let Some(v) = state.verify.as_mut() else {
13423            return Err("qwen4exp_gpu: verify not armed".into());
13424        };
13425        let Some((base, t)) = v.chunk.take() else {
13426            return Err("qwen4exp_gpu: no live verify chunk to rewind".into());
13427        };
13428        if keep == 0 || keep > t {
13429            return Err("qwen4exp_gpu: rewind keep out of range".into());
13430        }
13431        if keep == t {
13432            return Ok(());
13433        }
13434        state.pos = base + keep;
13435        state.tokens.truncate(base + keep);
13436        for (li, (layer, lstate)) in self.layers.iter().zip(state.layers.iter_mut()).enumerate() {
13437            match (&layer.mixer, &mut lstate.mixer) {
13438                (
13439                    MixerW::Qsa(qsa),
13440                    MixerState::Qsa {
13441                        raw_keys,
13442                        pooled_keys,
13443                        pooled_dev_rows,
13444                        raw_dev_rows,
13445                        idx_audit,
13446                        ..
13447                    },
13448                ) => {
13449                    let idx_dim = qsa.overlay.head_dim as usize;
13450                    raw_keys.truncate_rows(base + keep, idx_dim);
13451                    let block = qsa.overlay.block_size as usize;
13452                    pooled_keys.truncate(((base + keep) / block) * idx_dim);
13453                    // Device mirror follows the host truncation (see mtp_rewind).
13454                    *pooled_dev_rows = (*pooled_dev_rows).min(pooled_keys.len() / idx_dim);
13455                    // Device raw-key cache (idxcache): clamp to the ABSOLUTE kept row
13456                    // count (the host cache may lag below it — lazy materialization).
13457                    *raw_dev_rows = (*raw_dev_rows).min(base + keep);
13458                    // The audit twin tracks the cache rows exactly (instrument).
13459                    if let Some(audit) = idx_audit.as_deref_mut() {
13460                        audit.raw_f32.truncate_rows(base + keep, idx_dim);
13461                        audit.pooled_f32.truncate(((base + keep) / block) * idx_dim);
13462                    }
13463                }
13464                (MixerW::Gdn(g), MixerState::Gdn { conv, state: rec }) => {
13465                    let st = v.gdn[li]
13466                        .as_mut()
13467                        .ok_or("qwen4exp_gpu: GDN layer without a verify stash")?;
13468                    let p = &g.plan;
13469                    let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
13470                    let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
13471                    let conv_dim = 2 * nk * hk + nv * hv;
13472                    let pad = p.conv_kernel as usize - 1;
13473                    let state_len = nv * hv * hk;
13474                    e.copy_range_into(rec, 0, &st.states, (keep - 1) * state_len, state_len)?;
13475                    if keep >= pad {
13476                        e.copy_range_into(
13477                            conv,
13478                            0,
13479                            &st.qkv_rows,
13480                            (keep - pad) * conv_dim,
13481                            pad * conv_dim,
13482                        )?;
13483                    } else {
13484                        let keep_hist = pad - keep;
13485                        e.copy_range_into(
13486                            conv,
13487                            0,
13488                            &st.conv_pre,
13489                            keep * conv_dim,
13490                            keep_hist * conv_dim,
13491                        )?;
13492                        e.copy_range_into(
13493                            conv,
13494                            keep_hist * conv_dim,
13495                            &st.qkv_rows,
13496                            0,
13497                            keep * conv_dim,
13498                        )?;
13499                    }
13500                }
13501                _ => return Err("qwen4exp_gpu: mixer/state mismatch in rewind".into()),
13502            }
13503            if let (Some(pw), Some(ps)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
13504                let st = v.ple[li]
13505                    .as_mut()
13506                    .ok_or("qwen4exp_gpu: PLE layer without a verify stash")?;
13507                let pad = (pw.plan.conv_kernel as usize - 1) * pw.plan.max_ngram as usize;
13508                let hidden = self.hidden;
13509                for s in 0..self.streams {
13510                    let hist = &mut ps.conv_hist[s];
13511                    if keep >= pad {
13512                        e.copy_range_into(
13513                            hist,
13514                            0,
13515                            &st.normed_rows[s],
13516                            (keep - pad) * hidden,
13517                            pad * hidden,
13518                        )?;
13519                    } else {
13520                        let keep_hist = pad - keep;
13521                        e.copy_range_into(
13522                            hist,
13523                            0,
13524                            &st.hist_pre[s],
13525                            keep * hidden,
13526                            keep_hist * hidden,
13527                        )?;
13528                        e.copy_range_into(
13529                            hist,
13530                            keep_hist * hidden,
13531                            &st.normed_rows[s],
13532                            0,
13533                            keep * hidden,
13534                        )?;
13535                    }
13536                }
13537            }
13538        }
13539        Ok(())
13540    }
13541
13542    /// Device argmax of ONE draft-logits row (4-byte dtoh), returned as a TARGET vocab
13543    /// id: the row width is the trim width when armed and the winning row maps back
13544    /// through d2t (identity when the trim is off). `conf` (the p-min guard, prior art
13545    /// MEMRA_SPEC_PMIN / gemma confidence-adaptive draft depth — the SAME
13546    /// prob_of_token kernels) additionally returns the head's softmax confidence in its
13547    /// own pick: one extra 2-pass sum-exp launch + a 4-byte dtoh. Under a trim the
13548    /// confidence reads the TRIMMED row (inflated vs full softmax — thresholds are
13549    /// per-configuration, stated in the receipt).
13550    fn draft_row_argmax(
13551        &self,
13552        e: &Engine,
13553        logits: &CudaSlice<f32>,
13554        row: usize,
13555        conf: bool,
13556    ) -> Res<(u32, f32)> {
13557        let width = self.draft_logits_width();
13558        let mut tok = unsafe { e.gpu.stream().alloc::<u32>(1)? };
13559        e.argmax_token_device_col(logits, row, width, &mut tok, 0)?;
13560        let p = if conf {
13561            if row != 0 {
13562                // The chain shape is single-row; prob_of_token reads logits[0..width].
13563                return Err("qwen4exp_gpu: draft confidence reads row 0 (the chain shape)".into());
13564            }
13565            let pd = e.prob_of_token_device(logits, &tok, width)?;
13566            e.gpu.stream().clone_dtoh(&pd)?[0]
13567        } else {
13568            1.0
13569        };
13570        Ok((self.draft_token(e.gpu.stream().clone_dtoh(&tok)?[0])?, p))
13571    }
13572
13573    /// MTP speculative decode (mtp-spec lane): prefill, draft-prefill the MTP block
13574    /// over the prompt, then rounds of K-token drafting (single-layer draft, carrier-
13575    /// chained) + ONE trunk verify chunk (t = K+1, every row bit-identical to the
13576    /// t == 1 decode program) + greedy accept walk + replay-free partial rewind.
13577    ///
13578    /// Greedy (sampler None) is the byte-identity instrument: output must equal the
13579    /// spec-off greedy chain token for token. `Some(cfg)` runs the vendor-default
13580    /// sampled shape: targets are SAMPLED per verify row (draft accepted on exact
13581    /// match — distribution-preserving), the serving law's probe.
13582    ///
13583    /// This wrapper is the single-card, no-admission, no-trace shape; the full seam is
13584    /// `spec_generate_ext`.
13585    #[allow(clippy::too_many_arguments)]
13586    pub fn spec_generate(
13587        &self,
13588        e: &Engine,
13589        prompt: &[u32],
13590        max_new: usize,
13591        k: usize,
13592        state: &mut Qwen4ExpState,
13593        dstate: &mut MtpDraftState,
13594        sampler: Option<SpecSamplerCfg>,
13595    ) -> Res<SpecReport> {
13596        self.spec_generate_ext(
13597            e,
13598            e,
13599            prompt,
13600            max_new,
13601            k,
13602            state,
13603            dstate,
13604            sampler,
13605            SpecOpts::default(),
13606            None,
13607        )
13608    }
13609
13610    /// `spec_generate` with the mtp10 seams:
13611    /// - `de` — the DRAFT engine. Same card as `e` by default; the card-1 placement
13612    ///   (`load_from_dir_dev1`) requires the dev1 engine here and P2P-crosses the wide
13613    ///   seed rows per round (timed into `report.cross_ms`).
13614    /// - `opts` — bounded spec admission (p-min guard / adaptive K / dyn-K decay), all
13615    ///   default OFF. Every knob only shrinks the drafted window; commits are always
13616    ///   the target rows, so byte identity holds at every setting by construction.
13617    /// - `trace` — per-round diagnosis records (accept positions, fork margins, carrier
13618    ///   drift). Trace mode only ADDS reads (dtoh) and swaps the device accept-argmax
13619    ///   for the bit-identical host argmax; the committed chain is unchanged.
13620    #[allow(clippy::too_many_arguments)]
13621    pub fn spec_generate_ext(
13622        &self,
13623        e: &Engine,
13624        de: &Engine,
13625        prompt: &[u32],
13626        max_new: usize,
13627        k: usize,
13628        state: &mut Qwen4ExpState,
13629        dstate: &mut MtpDraftState,
13630        sampler: Option<SpecSamplerCfg>,
13631        opts: SpecOpts,
13632        mut trace: Option<&mut Vec<SpecTraceRound>>,
13633    ) -> Res<SpecReport> {
13634        use std::time::Instant;
13635        if k == 0 {
13636            return Err("qwen4exp_gpu: spec needs k >= 1".into());
13637        }
13638        let n = prompt.len();
13639        if n < 2 {
13640            return Err("qwen4exp_gpu: spec needs a >= 2 token prompt".into());
13641        }
13642        if state.pos != 0 || dstate.rows != 0 {
13643            return Err("qwen4exp_gpu: spec_generate wants FRESH trunk + draft states".into());
13644        }
13645        if state.capacity < n + max_new + k + 2 || dstate.capacity < n + max_new + k + 2 {
13646            return Err("qwen4exp_gpu: state capacity too small for prompt + max_new + k".into());
13647        }
13648        self.check_draft_engine(de)?;
13649        let dev1 = self.mtp_dev1.is_some();
13650        if !dev1 && de.ctx().ordinal() != e.ctx().ordinal() {
13651            return Err(
13652                "qwen4exp_gpu: draft engine on another card, but the draft was not \
13653                 built there (load_from_dir_dev1)"
13654                    .into(),
13655            );
13656        }
13657        let vocab = self.vocab;
13658        let wide_w = self.streams * self.hidden;
13659        let greedy = sampler.is_none();
13660        let tracing = trace.is_some();
13661        let guard = opts.pmin > 0.0;
13662        let deferred = opts.defer;
13663        if deferred && tracing {
13664            return Err(
13665                "qwen4exp_gpu: spec defer + trace are mutually exclusive (the trace \
13666                 instrument reads per-step host rows); run the trace on the host-chain arm"
13667                    .into(),
13668            );
13669        }
13670        if deferred {
13671            let ce = self.chain_embed.as_ref().ok_or(
13672                "qwen4exp_gpu: SpecOpts::defer needs arm_spec_devchain on the draft engine",
13673            )?;
13674            if ce.dev != de.ctx().ordinal() {
13675                return Err(format!(
13676                    "qwen4exp_gpu: the chain-embed table lives on device {} but the \
13677                     draft engine is device {} — re-arm arm_spec_devchain",
13678                    ce.dev,
13679                    de.ctx().ordinal()
13680                )
13681                .into());
13682            }
13683            if ce.for_trim != self.draft_trim.is_some() || ce.rows != self.draft_logits_width() {
13684                return Err(
13685                    "qwen4exp_gpu: the chain-embed table was armed for a different trim \
13686                     state — re-arm arm_spec_devchain after trim changes"
13687                        .into(),
13688                );
13689            }
13690        }
13691        // Deferred-round device slots (ONE alloc per generation, on the draft engine):
13692        // chain picks in RAW draft-index space + the guard's per-step confidence.
13693        let (mut chain_toks_d, mut chain_probs_d) = if deferred {
13694            (
13695                Some(unsafe { de.gpu.stream().alloc::<u32>(k)? }),
13696                Some(de.zeros(k)?),
13697            )
13698        } else {
13699            (None, None)
13700        };
13701        let mut rng = sampler
13702            .as_ref()
13703            .map(|cfg| SpecRng(cfg.seed | 1))
13704            .unwrap_or(SpecRng(1));
13705        let t_total = Instant::now();
13706        let mut report = SpecReport {
13707            accept_hist: vec![0; k + 1],
13708            ..Default::default()
13709        };
13710
13711        match opts.wide_ring {
13712            Some(ring) => {
13713                let chunk = opts
13714                    .prefill_chunk
13715                    .ok_or("qwen4exp_gpu: SpecOpts::wide_ring needs prefill_chunk")?;
13716                if ring < 2 * chunk || ring < 2 * (k + 2) {
13717                    return Err("qwen4exp_gpu: wide_ring must cover 2 prefill chunks".into());
13718                }
13719                self.spec_arm_ring(e, state, k + 1, ring)?;
13720            }
13721            None => self.spec_arm(e, state, k + 1)?,
13722        }
13723        self.set_verify_want_argmax(state, false)?;
13724        if let Some(v) = state.verify.as_mut() {
13725            // mtp11 deferred seam: t == 1 steps commit through the device argmax
13726            // (greedy only) and big-t prefills dtoh one row instead of the block.
13727            v.want_argmax_t1 = deferred && greedy && !tracing;
13728            v.last_row_only = deferred;
13729        }
13730        // Card-1 mirror of the wide stash (the draft's seed source on the dev1 route) —
13731        // ring-sized like the stash itself (same slot addressing on both cards).
13732        let ring = state.verify.as_ref().expect("armed above").ring_rows;
13733        if dev1 {
13734            let v = state.verify.as_mut().expect("armed above");
13735            if v.wide_dev1.as_ref().is_none_or(|m| m.len() < ring * wide_w) {
13736                v.wide_dev1 = Some(de.zeros(ring * wide_w)?);
13737            }
13738        }
13739        // Defer arm's draft-side embed route: device gather from the full-vocab chain
13740        // table (a trim table cannot embed arbitrary target/prompt ids — host embed
13741        // stays the trim fallback, stated). Control arm (defer off): host embed,
13742        // structure-frozen.
13743        let dev_embed = deferred
13744            && self
13745                .chain_embed
13746                .as_ref()
13747                .is_some_and(|ce| !ce.for_trim && ce.rows == self.vocab);
13748        let t_prefill = Instant::now();
13749        let mut draft_prefill_ms = 0f64;
13750        let x0: u32 = match opts.prefill_chunk {
13751            // ---- Long-context CO-PREFILL (chunked): trunk chunk forward with the head
13752            // skipped (LastRow on the final chunk — a [n, vocab] logits block at 500k
13753            // would be hundreds of GB), then the dev1 crossing + the draft consuming
13754            // THAT chunk's wide rows before the ring overwrites them. Piece boundaries
13755            // keep the final piece past k_cap so no prefill chunk takes the verify-exact
13756            // path.
13757            Some(chunk) if n > chunk => {
13758                let mut b = 0usize;
13759                let mut last = Vec::new();
13760                while b < n {
13761                    let mut t = chunk.min(n - b);
13762                    // Never leave a <= k_cap remainder as its own final piece.
13763                    if n - (b + t) > 0 && n - (b + t) <= k + 1 {
13764                        t = n - b;
13765                    }
13766                    let is_last = b + t == n;
13767                    let head = if is_last {
13768                        HeadMode::LastRow
13769                    } else {
13770                        HeadMode::Skip
13771                    };
13772                    let piece = self.forward_with(e, &prompt[b..b + t], state, None, head)?;
13773                    let t_draft = Instant::now();
13774                    if dev1 {
13775                        let v = state.verify.as_mut().expect("armed above");
13776                        let VerifyStash {
13777                            wide, wide_dev1, ..
13778                        } = v;
13779                        let mirror = wide_dev1.as_mut().expect("allocated above");
13780                        for (slot, len) in ring_pieces(ring, b, t) {
13781                            report.cross_ms +=
13782                                cross_wide_rows(e, de, wide, mirror, slot, len, wide_w)?;
13783                        }
13784                        report.cross_bytes += (t * wide_w * 4) as u64;
13785                    }
13786                    // Draft rows for positions [max(b,1), b+t): token p seeds wide[p-1]
13787                    // (the previous chunk's last row stays live: ring >= 2 chunks).
13788                    let p0 = b.max(1);
13789                    if b + t > p0 {
13790                        let v = state.verify.as_ref().expect("armed above");
13791                        let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
13792                        let (ld, cd, _) = self.draft_consume_ring(
13793                            de,
13794                            &prompt[p0..b + t],
13795                            dev_embed,
13796                            seed,
13797                            ring,
13798                            p0 - 1,
13799                            dstate,
13800                        )?;
13801                        self.mtp_recycle(dstate, ld, cd);
13802                    }
13803                    draft_prefill_ms += t_draft.elapsed().as_secs_f64() * 1e3;
13804                    b += t;
13805                    if is_last {
13806                        last = piece;
13807                    }
13808                }
13809                dstate.committed = n - 1;
13810                debug_assert_eq!(last.len(), vocab);
13811                match sampler.as_ref() {
13812                    None => host_argmax(&last) as u32,
13813                    Some(cfg) => sample_row(cfg, &mut rng, &last),
13814                }
13815            }
13816            // ---- Historical one-shot prefill (byte-stable receipts).
13817            _ => {
13818                let prefill = self.forward(e, prompt, state, None)?;
13819                // Shape-agnostic last-row read: the deferred seam's prefill dtoh is ONE
13820                // row (last_row_only), the control arm's is the full block; both end at
13821                // the row x0 reads. (A prompt shorter than k+2 runs the prefill as an
13822                // exact chunk and returns full rows on both arms.)
13823                let last = &prefill[prefill.len() - vocab..];
13824                let x0 = match sampler.as_ref() {
13825                    None => host_argmax(last) as u32,
13826                    Some(cfg) => sample_row(cfg, &mut rng, last),
13827                };
13828                let t_draft0 = Instant::now();
13829                if dev1 {
13830                    let v = state.verify.as_mut().expect("armed above");
13831                    let VerifyStash {
13832                        wide, wide_dev1, ..
13833                    } = v;
13834                    let mirror = wide_dev1.as_mut().expect("allocated above");
13835                    for (slot, len) in ring_pieces(ring, 0, n) {
13836                        report.cross_ms += cross_wide_rows(e, de, wide, mirror, slot, len, wide_w)?;
13837                    }
13838                    report.cross_bytes += (n * wide_w * 4) as u64;
13839                }
13840                {
13841                    let v = state.verify.as_ref().expect("armed above");
13842                    let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
13843                    if n >= 2 {
13844                        let (ld, cd, _) = self.draft_consume_ring(
13845                            de,
13846                            &prompt[1..],
13847                            dev_embed,
13848                            seed,
13849                            ring,
13850                            0,
13851                            dstate,
13852                        )?;
13853                        self.mtp_recycle(dstate, ld, cd);
13854                    }
13855                    dstate.committed = n - 1;
13856                }
13857                draft_prefill_ms += t_draft0.elapsed().as_secs_f64() * 1e3;
13858                x0
13859            }
13860        };
13861        report.prefill_ms = t_prefill.elapsed().as_secs_f64() * 1e3 - draft_prefill_ms;
13862        // Trace mode keeps the full verify-logits dtoh (want_argmax off) so fork
13863        // margins can be read; targets then come from the bit-identical host argmax.
13864        self.set_verify_want_argmax(state, greedy && !tracing)?;
13865        // x0 is the first generated token (parity with the plain chain's first argmax).
13866        report.tokens.push(x0);
13867
13868        // Bootstrap tip row: (x0 at position n, hidden wide[n-1]).
13869        let t_boot = Instant::now();
13870        let (mut tip_logits, mut tip_carrier) = {
13871            let v = state.verify.as_ref().expect("armed above");
13872            let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
13873            self.mtp_draft_forward_spec(de, &[x0], dev_embed, seed, (n - 1) % ring, dstate)?
13874        };
13875        let mut tip_rows = 1usize;
13876        dstate.committed = dstate.rows;
13877        report.draft_prefill_ms = draft_prefill_ms + t_boot.elapsed().as_secs_f64() * 1e3;
13878        report.draft_ms += report.draft_prefill_ms;
13879
13880        let mut m = n; // trunk committed rows; tip sits at position m
13881        let mut tip = x0;
13882        // Admission state: k_cur = the dyn-K ceiling (decay-only), k_next = the
13883        // adaptive per-round window (accepted+1 recipe), window = the dyn-K ring.
13884        let mut k_cur = k;
13885        let mut k_next = k;
13886        let mut window: Vec<usize> = Vec::new();
13887        let mut round_idx = 0usize;
13888        while report.tokens.len() < max_new {
13889            if k_cur == 0 {
13890                // Dyn-K floored at 0: spec OFF for the remainder. Plain decode steps
13891                // (host argmax = the plain program — byte identity by construction);
13892                // the draft never runs again, which is exactly the saved cost.
13893                let row = self.forward(e, &[tip], state, None)?;
13894                let next: u32 = match sampler.as_ref() {
13895                    // Deferred seam: the plain step's token is the device argmax
13896                    // (bit-identical, argmax-gate contract); `row` is empty here.
13897                    None if deferred => self.verify_argmax_rows(state)?[0],
13898                    None => host_argmax(&row) as u32,
13899                    Some(cfg) => sample_row(cfg, &mut rng, &row),
13900                };
13901                report.tokens.push(next);
13902                report.plain_steps += 1;
13903                report
13904                    .round_wall
13905                    .push((report.tokens.len(), t_total.elapsed().as_secs_f64() * 1e3));
13906                m += 1;
13907                tip = next;
13908                continue;
13909            }
13910            let k_round = k_next.min(k_cur).max(1);
13911            // ---- draft chain: d1 from the tip row; steps 2..k_round carrier-chained.
13912            // The p-min guard stops the chain at the first sub-threshold pick (token
13913            // discarded uncounted); at j == 0 that makes a ZERO-draft round whose
13914            // verify is a plain t == 1 step.
13915            let t_draft = Instant::now();
13916            let mut drafts: Vec<u32> = Vec::with_capacity(k_round);
13917            let mut chain_rows_h: Vec<Vec<f32>> = Vec::new(); // trace: draft logit rows
13918            let mut seeds_h: Vec<Vec<f32>> = Vec::new(); // trace: carrier seeds used
13919            if let (Some(toks), Some(probs)) = (chain_toks_d.as_mut(), chain_probs_d.as_mut()) {
13920                // ---- DEFERRED chain (mtp11): picks and confidences stay in device
13921                // slots; the next step's embed gathers from the chain table, so host
13922                // dispatch of step j+1 overlaps device execution of step j and the
13923                // round drains ONCE (below) instead of blocking 2 dtoh per step.
13924                let width = self.draft_logits_width();
13925                de.argmax_token_device_col(&tip_logits, 0, width, toks, 0)?;
13926                if guard {
13927                    de.prob_of_token_device_col(&tip_logits, toks, 0, probs, 0, width)?;
13928                }
13929                let mut prev_logits = tip_logits;
13930                let mut prev_carrier = tip_carrier;
13931                let mut prev_rows = tip_rows;
13932                // Device slots holding a pick so far (guard_sync: a CHECKED pick).
13933                let mut drafted = 1usize;
13934                let mut stopped = false;
13935                if guard && opts.defer_guard_sync {
13936                    // Sequential-guard sub-arm: one 4-byte prob dtoh per step, the
13937                    // chain stops exactly where the host arm would (the discarded
13938                    // sub-threshold pick stays in its slot, uncounted).
13939                    let p = de.gpu.stream().clone_dtoh(&probs.slice(0..1))?[0];
13940                    if p < opts.pmin {
13941                        drafted = 0;
13942                        stopped = true;
13943                        report.guard_stops += 1;
13944                    }
13945                }
13946                while !stopped && drafted < k_round {
13947                    let (l2, c2) = self.mtp_draft_forward_devslot(
13948                        de,
13949                        toks,
13950                        drafted - 1,
13951                        &prev_carrier,
13952                        prev_rows - 1,
13953                        dstate,
13954                    )?;
13955                    self.mtp_recycle(dstate, prev_logits, prev_carrier);
13956                    prev_logits = l2;
13957                    prev_carrier = c2;
13958                    prev_rows = 1;
13959                    de.argmax_token_device_col(&prev_logits, 0, width, toks, drafted)?;
13960                    if guard {
13961                        de.prob_of_token_device_col(
13962                            &prev_logits,
13963                            toks,
13964                            drafted,
13965                            probs,
13966                            drafted,
13967                            width,
13968                        )?;
13969                        if opts.defer_guard_sync {
13970                            let p = de
13971                                .gpu
13972                                .stream()
13973                                .clone_dtoh(&probs.slice(drafted..drafted + 1))?[0];
13974                            if p < opts.pmin {
13975                                report.guard_stops += 1;
13976                                break;
13977                            }
13978                        }
13979                    }
13980                    drafted += 1;
13981                }
13982                self.mtp_recycle(dstate, prev_logits, prev_carrier);
13983                // ---- the round's ONE chain drain: the picks (and the deferred
13984                // guard's confidences) cross together; raw indices map to target ids
13985                // through draft_token, and the deferred guard truncates at the FIRST
13986                // sub-threshold step — the same discard the sequential arm makes.
13987                if drafted > 0 {
13988                    let raw = de.gpu.stream().clone_dtoh(&toks.slice(0..drafted))?;
13989                    let trunc = if guard && !opts.defer_guard_sync {
13990                        let pw = de.gpu.stream().clone_dtoh(&probs.slice(0..drafted))?;
13991                        let trunc = spec_guard_trunc(&pw, opts.pmin);
13992                        if trunc < drafted {
13993                            report.guard_stops += 1;
13994                        }
13995                        trunc
13996                    } else {
13997                        drafted
13998                    };
13999                    for &r in raw.iter().take(trunc) {
14000                        drafts.push(self.draft_token(r)?);
14001                    }
14002                }
14003            } else {
14004                let (d1, c1) = self.draft_row_argmax(de, &tip_logits, 0, guard)?;
14005                if !(guard && c1 < opts.pmin) {
14006                    drafts.push(d1);
14007                    if tracing {
14008                        chain_rows_h
14009                            .push(de.dtoh_view(&tip_logits.slice(0..self.draft_logits_width()))?);
14010                    }
14011                } else {
14012                    report.guard_stops += 1;
14013                }
14014                let mut prev_logits = tip_logits;
14015                let mut prev_carrier = tip_carrier;
14016                let mut prev_rows = tip_rows;
14017                while !drafts.is_empty() && drafts.len() < k_round {
14018                    if tracing {
14019                        seeds_h.push(de.dtoh_view(
14020                            &prev_carrier.slice((prev_rows - 1) * wide_w..prev_rows * wide_w),
14021                        )?);
14022                    }
14023                    let lastd = *drafts.last().expect("non-empty");
14024                    let (l2, c2) = self.mtp_draft_forward(
14025                        de,
14026                        &[lastd],
14027                        &prev_carrier,
14028                        prev_rows - 1,
14029                        dstate,
14030                        1,
14031                        false,
14032                    )?;
14033                    self.mtp_recycle(dstate, prev_logits, prev_carrier);
14034                    prev_logits = l2;
14035                    prev_carrier = c2;
14036                    prev_rows = 1;
14037                    let (dn, cn) = self.draft_row_argmax(de, &prev_logits, 0, guard)?;
14038                    if guard && cn < opts.pmin {
14039                        report.guard_stops += 1;
14040                        break;
14041                    }
14042                    drafts.push(dn);
14043                    if tracing {
14044                        chain_rows_h
14045                            .push(de.dtoh_view(&prev_logits.slice(0..self.draft_logits_width()))?);
14046                    }
14047                }
14048                self.mtp_recycle(dstate, prev_logits, prev_carrier);
14049            }
14050            let chain_ms = t_draft.elapsed().as_secs_f64() * 1e3;
14051            report.chain_ms += chain_ms;
14052            report.draft_ms += chain_ms;
14053
14054            // ---- verify chunk [tip, d1..] at base m (t == 1 on a zero-draft round —
14055            // a plain decode step that still commits one token).
14056            let t_ver = Instant::now();
14057            let mut chunk = Vec::with_capacity(drafts.len() + 1);
14058            chunk.push(tip);
14059            chunk.extend_from_slice(&drafts);
14060            let tlen = chunk.len();
14061            let host_logits = self.forward(e, &chunk, state, None)?;
14062            // Deferred seam: the t == 1 zero-draft verify also commits through the
14063            // device argmax (want_argmax_t1) — no [1, vocab] row + host scan.
14064            let targets: Vec<u32> = if greedy && !tracing && (tlen > 1 || deferred) {
14065                self.verify_argmax_rows(state)?.to_vec()
14066            } else if greedy {
14067                (0..tlen)
14068                    .map(|row| host_argmax(&host_logits[row * vocab..(row + 1) * vocab]) as u32)
14069                    .collect()
14070            } else {
14071                let cfg = sampler.as_ref().expect("sampled mode");
14072                (0..tlen)
14073                    .map(|row| {
14074                        sample_row(cfg, &mut rng, &host_logits[row * vocab..(row + 1) * vocab])
14075                    })
14076                    .collect()
14077            };
14078            report.verify_ms += t_ver.elapsed().as_secs_f64() * 1e3;
14079            if targets.len() != tlen {
14080                return Err("qwen4exp_gpu: verify produced the wrong row count".into());
14081            }
14082
14083            // ---- greedy accept walk (exact match to the target row).
14084            let mut a = 0usize;
14085            while a < drafts.len() && drafts[a] == targets[a] {
14086                a += 1;
14087            }
14088            report.rounds += 1;
14089            report.drafted += drafts.len() as u64;
14090            report.accepted += a as u64;
14091            report.accept_hist[a] += 1;
14092            if drafts.is_empty() {
14093                report.zero_draft_rounds += 1;
14094            }
14095            report.tokens.extend_from_slice(&targets[0..=a]);
14096
14097            // ---- trace record (fork margins from the stashed rows; carrier drift vs
14098            // the verify chunk's TRUE wide rows).
14099            if let Some(tr) = trace.as_deref_mut() {
14100                let mut rec = SpecTraceRound {
14101                    round: round_idx,
14102                    gen_pos: report.tokens.len() - (a + 1),
14103                    base: m,
14104                    k: drafts.len(),
14105                    a,
14106                    drafts: drafts.clone(),
14107                    targets: targets.clone(),
14108                    draft_top1: f32::NAN,
14109                    draft_top2: f32::NAN,
14110                    draft_tgt_logit: f32::NAN,
14111                    draft_tgt_rank: 0,
14112                    target_top1: f32::NAN,
14113                    target_top2: f32::NAN,
14114                    target_draft_logit: f32::NAN,
14115                    target_entropy: 0.0,
14116                    carrier_rel_l2: Vec::new(),
14117                    carrier_cos: Vec::new(),
14118                };
14119                if a < drafts.len() {
14120                    let drow = &chain_rows_h[a];
14121                    let trow = &host_logits[a * vocab..(a + 1) * vocab];
14122                    let tgt = targets[a] as usize;
14123                    let dtok = drafts[a] as usize;
14124                    let (mut d1v, mut d2v) = (f32::NEG_INFINITY, f32::NEG_INFINITY);
14125                    let mut rank = 0usize;
14126                    let dt = drow[tgt];
14127                    for &v in drow.iter() {
14128                        if v > d1v {
14129                            d2v = d1v;
14130                            d1v = v;
14131                        } else if v > d2v {
14132                            d2v = v;
14133                        }
14134                        if v > dt {
14135                            rank += 1;
14136                        }
14137                    }
14138                    let (mut t1v, mut t2v) = (f32::NEG_INFINITY, f32::NEG_INFINITY);
14139                    for &v in trow.iter() {
14140                        if v > t1v {
14141                            t2v = t1v;
14142                            t1v = v;
14143                        } else if v > t2v {
14144                            t2v = v;
14145                        }
14146                    }
14147                    // Softmax entropy of the target row (nats), f64 accumulation.
14148                    let mx = t1v as f64;
14149                    let mut z = 0.0f64;
14150                    let mut sxl = 0.0f64;
14151                    for &v in trow.iter() {
14152                        let ev = ((v as f64) - mx).exp();
14153                        z += ev;
14154                        sxl += ev * ((v as f64) - mx);
14155                    }
14156                    rec.draft_top1 = d1v;
14157                    rec.draft_top2 = d2v;
14158                    rec.draft_tgt_logit = dt;
14159                    rec.draft_tgt_rank = rank;
14160                    rec.target_top1 = t1v;
14161                    rec.target_top2 = t2v;
14162                    rec.target_draft_logit = trow[dtok];
14163                    rec.target_entropy = z.ln() - sxl / z;
14164                }
14165                let v = state.verify.as_ref().expect("armed above");
14166                for (j, seed) in seeds_h.iter().enumerate() {
14167                    let slot = (m + j) % ring;
14168                    let truth = e.dtoh_view(&v.wide.slice(slot * wide_w..(slot + 1) * wide_w))?;
14169                    let mut dd = 0.0f64;
14170                    let mut tt = 0.0f64;
14171                    let mut st = 0.0f64;
14172                    let mut ss = 0.0f64;
14173                    for (&s, &t) in seed.iter().zip(truth.iter()) {
14174                        let (s, t) = (s as f64, t as f64);
14175                        dd += (s - t) * (s - t);
14176                        tt += t * t;
14177                        st += s * t;
14178                        ss += s * s;
14179                    }
14180                    rec.carrier_rel_l2
14181                        .push((dd.sqrt() / tt.sqrt().max(1e-30)) as f32);
14182                    rec.carrier_cos
14183                        .push((st / (ss.sqrt() * tt.sqrt()).max(1e-30)) as f32);
14184                }
14185                tr.push(rec);
14186            }
14187
14188            // ---- rewind trunk to the accepted rows; draft catch-up replay.
14189            if tlen > 1 {
14190                self.verify_rewind(e, state, a + 1)?;
14191            }
14192            self.mtp_rewind(dstate, m)?;
14193            let t_draft2 = Instant::now();
14194            let x_next = targets[a];
14195            let mut replay: Vec<u32> = drafts[0..a].to_vec();
14196            replay.push(x_next);
14197            if dev1 {
14198                let v = state.verify.as_mut().expect("armed above");
14199                let VerifyStash {
14200                    wide, wide_dev1, ..
14201                } = v;
14202                let mirror = wide_dev1.as_mut().expect("allocated above");
14203                for (slot, len) in ring_pieces(ring, m, replay.len()) {
14204                    report.cross_ms += cross_wide_rows(e, de, wide, mirror, slot, len, wide_w)?;
14205                }
14206                report.cross_bytes += (replay.len() * wide_w * 4) as u64;
14207            }
14208            let (l, c, last_len) = {
14209                let v = state.verify.as_ref().expect("armed above");
14210                let seed: &CudaSlice<f32> = v.wide_dev1.as_ref().unwrap_or(&v.wide);
14211                self.draft_consume_ring(de, &replay, dev_embed, seed, ring, m, dstate)?
14212            };
14213            tip_logits = l;
14214            tip_carrier = c;
14215            tip_rows = last_len;
14216            dstate.committed = dstate.rows;
14217            let replay_ms = t_draft2.elapsed().as_secs_f64() * 1e3;
14218            report.replay_ms += replay_ms;
14219            report.draft_ms += replay_ms;
14220            m += a + 1;
14221            tip = x_next;
14222            report
14223                .round_wall
14224                .push((report.tokens.len(), t_total.elapsed().as_secs_f64() * 1e3));
14225
14226            // ---- bounded admission updates (both decay-only within the round budget).
14227            if let Some(lo) = opts.adapt_k_lo {
14228                k_next = (a + 1).clamp(lo.max(1), k);
14229            }
14230            if let Some(cfg) = opts.dynk {
14231                window.push(a);
14232                if window.len() >= cfg.window.max(1) {
14233                    let mean = window.iter().sum::<usize>() as f64 / window.len() as f64;
14234                    if mean < cfg.thr {
14235                        let new_k = k_cur.saturating_sub(1).max(cfg.k_floor);
14236                        if new_k < k_cur {
14237                            k_cur = new_k;
14238                            report.k_decays.push((round_idx, k_cur));
14239                            if k_cur == 0 {
14240                                report.spec_off_at = Some(report.tokens.len());
14241                            }
14242                        }
14243                    }
14244                    window.clear();
14245                }
14246            }
14247            round_idx += 1;
14248        }
14249        report.tokens.truncate(max_new);
14250        report.total_ms = t_total.elapsed().as_secs_f64() * 1e3;
14251        Ok(report)
14252    }
14253}
14254
14255// ---------------------------------------------------------------- checkpoint loading
14256//
14257// The pack/plan/contract walk over an HF safetensors dir. The loader PROBES the artifact
14258// for its routed-expert dialect (ExpertDialect: the BF16 export's fused 3D banks, or the
14259// NVFP4 mint's per-expert modelopt projections — census receipt
14260// research/qwen4exp-bringup-20260829/raw/nvfp4-census-names.tsv) and binds through the
14261// pack's dialect contract. Trunk + globals materialize into reference-layout weights; the
14262// n-gram table stays host-resident (sharded or the mint's single tensor); expert banks
14263// admit BF16 (dequantized) or modelopt NVFP4 (as-stored device residency). `input_scale`
14264// (modelopt static activation scale) is contract-declared as an auxiliary, VALIDATED here
14265// (F32 scalar) and deliberately UNUSED: the eager arm is W4A16-class (weights dequantize
14266// to f32, activations stay f32), so the scale has no consumer until the W4A4 kernel lane
14267// quantizes activations — the dsv4 precedent ("W4A8 activation scale, unused for decode").
14268// MTP and vision tensors are validated owners but not materialized — the eager arm
14269// executes neither (module header).
14270
14271/// One expert bank tensor (one PROJECTION: gate, up, or down), assembled across experts.
14272enum BankTensorSrc {
14273    /// Dequantized f32, logical [n_expert, out_f, in_f].
14274    F32(Vec<f32>),
14275    /// modelopt NVFP4: e2m1 codes [E, out, in/2], e4m3 scales [E, out, in/16],
14276    /// per-expert finite macro scales (the real mint's are amax-derived non-pow2), and
14277    /// the projection's STATIC ACTIVATION scale — the max of the per-expert
14278    /// `input_scale` siblings. RECORDED-ONLY by owner order (2026-08-30): activation
14279    /// quantization is retired as a serving lever (it measurably moved decode argmax —
14280    /// perf22 seam-gate receipt, PROFILE-4 §W4A4); no compute path consumes this value,
14281    /// and no future lane re-proposes consuming it without a fresh owner ruling.
14282    Nvfp4 {
14283        codes: Vec<u8>,
14284        scales: Vec<u8>,
14285        macros: Vec<f32>,
14286        act_scale: Option<f32>,
14287    },
14288    /// Raw bf16 bytes at the logical shape [n_expert, out_f, in_f] — kept when
14289    /// `LoadOptions::host_bf16_banks` asks for the host-resident gate residency.
14290    Bf16(Vec<u8>),
14291}
14292
14293struct BankSrc {
14294    gate: BankTensorSrc, // logical [E, ff, H]
14295    up: BankTensorSrc,   // logical [E, ff, H]
14296    down: BankTensorSrc, // logical [E, H, ff]
14297    n_expert: usize,
14298    ff: usize,
14299    hidden: usize,
14300}
14301
14302/// A checkpoint materialized through the pack contract: reference-layout weights for the
14303/// trunk + globals (effective norms — the (1+w) fold applied per the module-header rule),
14304/// plus the bank/table carriers that stay out of `ReferenceWeights`.
14305pub struct LoadedCheckpoint {
14306    pub plan: ModelPlan,
14307    pub weights: ReferenceWeights,
14308    banks: std::collections::BTreeMap<u32, BankSrc>,
14309    tables: std::collections::BTreeMap<u32, Vec<u8>>, // bf16 bytes, [rows, head_dim]
14310}
14311
14312/// (1+w) fold rule for checkpoint norm rows — the qwen35 receipt (hf_mapping.rs,
14313/// qwen.py:302-303): every `*norm*.weight` EXCEPT `linear_attn.norm` (RMSNormGated binds
14314/// raw weights; SEMANTICS.md §GDN keeps the qwen3_5 GDN program). VERIFY vs the goldens
14315/// lane for the indexer layernorms (assumed the family (1+w) class — the zero-init
14316/// receipt, modular L860).
14317fn norm_fold_add_one(name: &str) -> bool {
14318    name.contains("norm") && name.ends_with(".weight") && !name.ends_with("linear_attn.norm.weight")
14319}
14320
14321/// The QSA indexer's q/k layernorm rows — the SEMANTICS.md VERIFY subject. The default
14322/// fold treats them as family (1+w); `LoadOptions::indexer_norm_raw` binds them raw so
14323/// the real-checkpoint per-layer gate can measure both arms and settle the question.
14324fn indexer_layernorm(name: &str) -> bool {
14325    name.contains(".indexer.")
14326        && (name.ends_with("q_layernorm.weight") || name.ends_with("k_layernorm.weight"))
14327}
14328
14329/// Real-checkpoint loader knobs (defaults = the tiny-gate behavior).
14330#[derive(Default, Clone, Copy)]
14331pub struct LoadOptions {
14332    /// Keep BF16 expert banks HOST-resident (raw bf16) and upload+upcast per ROUTED
14333    /// expert at forward time. Gate-mode residency for artifacts whose f32 banks
14334    /// exceed device memory; value chain identical to the f32 device arm (bf16→f32
14335    /// is exact). Never a serving configuration.
14336    pub host_bf16_banks: bool,
14337    /// Bind the indexer q/k layernorms RAW (skip the (1+w) fold) — the two-arm probe
14338    /// for the SEMANTICS.md VERIFY marker. Default keeps the family fold.
14339    pub indexer_norm_raw: bool,
14340    /// Materialize the mtp.* namespace (the NextN draft block) — the mtp-spec lane.
14341    /// The MTP expert bank keeps its raw BF16 bytes at read time and goes DEVICE
14342    /// bf16-resident at build (`BankHalf::DeviceBf16`, ~5 GB beside the NVFP4 trunk).
14343    /// Default OFF: the plain eager arm executes no draft.
14344    pub load_mtp: bool,
14345}
14346
14347fn bridge_transform(
14348    transform: memra_gguf::tensor_contract::TensorTransform,
14349) -> Res<memra_gguf::hf_mapping::TransformKind> {
14350    use memra_gguf::hf_mapping::TransformKind as K;
14351    use memra_gguf::tensor_contract::TensorTransform as T;
14352    Ok(match transform {
14353        T::Identity => K::Identity,
14354        T::NormAddOne => K::NormPlusOne,
14355        T::QkvVReorderRows => K::QkvVReorderRows,
14356        T::ZReorderRows => K::ZReorderRows,
14357        T::AbReorderRows => K::AbReorderRows,
14358        T::NegExpReorderHeads => K::NegExpReorderHeads,
14359        T::ReorderHeads => K::ReorderHeads,
14360        T::Conv1dSqueezeReorder => K::Conv1dSqueezeReorder,
14361        T::OutReorderColumns => K::OutReorderCols,
14362        other => return Err(format!("qwen4exp_gpu: unsupported transform {other:?}").into()),
14363    })
14364}
14365
14366fn dequant_float(
14367    name: &str,
14368    info: &memra_gguf::safetensors::StInfo,
14369    bytes: &[u8],
14370) -> Res<Vec<f32>> {
14371    let elements: usize = info.shape.iter().map(|&d| d as usize).product();
14372    match info.dtype.as_str() {
14373        "BF16" | "F32" => Ok(memra_gguf::dequant::dequantize(
14374            info.ggml_type(),
14375            bytes,
14376            elements,
14377        )),
14378        other => Err(format!("qwen4exp_gpu: {name} has unsupported float dtype {other}").into()),
14379    }
14380}
14381
14382fn read_i64(name: &str, info: &memra_gguf::safetensors::StInfo, bytes: &[u8]) -> Res<Vec<i64>> {
14383    if info.dtype != "I64" {
14384        return Err(format!("qwen4exp_gpu: {name} must be I64, got {}", info.dtype).into());
14385    }
14386    Ok(bytes
14387        .chunks_exact(8)
14388        .map(|chunk| i64::from_le_bytes(chunk.try_into().unwrap()))
14389        .collect())
14390}
14391
14392/// Macro-scale validation. The dsv4 pow2 law does NOT apply here: this module's dequant
14393/// chain applies the macro post-upcast in f32 (`dequant_nvfp4_expert_f32`), which is
14394/// exact-then-single-rounding for ANY finite positive macro — and the real qwen4_exp
14395/// mint ships modelopt's amax-derived NON-pow2 `weight_scale_2` (first value refused by
14396/// the inherited pow2 assert on the fleet box, 2026-08-29: 5.9945243e-5 on
14397/// layers.0.mlp.experts.0.down_proj). Refusal is reserved for values that poison the
14398/// arithmetic outright.
14399fn validate_macro(stem: &str, value: f32) -> Res<()> {
14400    if !(value.is_finite() && value > 0.0) {
14401        return Err(format!(
14402            "qwen4exp_gpu: {stem}.weight_scale_2 carries a non-finite/non-positive \
14403             macro {value}"
14404        )
14405        .into());
14406    }
14407    Ok(())
14408}
14409
14410/// Read one STACKED expert bank (FusedBanks dialect): BF16 at the declared logical shape,
14411/// or the modelopt-NVFP4 stacked triplet whose validation mirrors
14412/// `find_nvfp4_stacked_native` (source.rs): U8 codes [E, out, in/2] + F8_E4M3
14413/// `weight_scale` [E, out, in/16] + optional F32 `weight_scale_2` [E] (absent -> 1.0).
14414fn read_bank_tensor(
14415    model: &memra_gguf::safetensors::StModel,
14416    name: &str,
14417    n_expert: usize,
14418    out_f: usize,
14419    in_f: usize,
14420    host_bf16: bool,
14421) -> Res<BankTensorSrc> {
14422    let (info, bytes) = model
14423        .raw(name)
14424        .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
14425    match info.dtype.as_str() {
14426        "BF16" | "F32" => {
14427            if info.shape != [n_expert as u64, out_f as u64, in_f as u64] {
14428                return Err(format!("qwen4exp_gpu: {name} bank shape mismatch").into());
14429            }
14430            if host_bf16 && info.dtype == "BF16" {
14431                if bytes.len() != n_expert * out_f * in_f * 2 {
14432                    return Err(format!("qwen4exp_gpu: {name} bank byte-length mismatch").into());
14433                }
14434                return Ok(BankTensorSrc::Bf16(bytes.to_vec()));
14435            }
14436            Ok(BankTensorSrc::F32(dequant_float(name, info, bytes)?))
14437        }
14438        "U8" => {
14439            if in_f % 16 != 0
14440                || info.shape != [n_expert as u64, out_f as u64, (in_f / 2) as u64]
14441                || bytes.len() != n_expert * out_f * in_f / 2
14442            {
14443                return Err(format!("qwen4exp_gpu: {name} NVFP4 code shape mismatch").into());
14444            }
14445            let stem = name.strip_suffix(".weight").unwrap_or(name);
14446            let scale_name = format!("{stem}.weight_scale");
14447            let (scale_info, scale_bytes) = model
14448                .raw(&scale_name)
14449                .ok_or_else(|| format!("qwen4exp_gpu: missing {scale_name}"))?;
14450            if scale_info.dtype != "F8_E4M3"
14451                || scale_info.shape != [n_expert as u64, out_f as u64, (in_f / 16) as u64]
14452                || scale_bytes.len() != n_expert * out_f * in_f / 16
14453            {
14454                return Err(format!("qwen4exp_gpu: {scale_name} shape mismatch").into());
14455            }
14456            let macros = match model.raw(&format!("{stem}.weight_scale_2")) {
14457                Some((macro_info, macro_bytes))
14458                    if macro_info.dtype == "F32" && macro_bytes.len() == n_expert * 4 =>
14459                {
14460                    macro_bytes
14461                        .chunks_exact(4)
14462                        .map(|chunk| f32::from_le_bytes(chunk.try_into().unwrap()))
14463                        .collect()
14464                }
14465                None => vec![1.0; n_expert],
14466                _ => return Err(format!("qwen4exp_gpu: {stem}.weight_scale_2 malformed").into()),
14467            };
14468            for &m in &macros {
14469                validate_macro(stem, m)?;
14470            }
14471            // Optional stacked input_scale [E] (the per-expert mint carries scalars via
14472            // the PerExpertModelopt path; a stacked artifact may carry the vector) —
14473            // reduced to the per-layer max for the W4A4 activation quantization.
14474            let act_scale = match model.raw(&format!("{stem}.input_scale")) {
14475                Some((is_info, is_bytes))
14476                    if is_info.dtype == "F32" && is_bytes.len() == n_expert * 4 =>
14477                {
14478                    let mut mx = 0.0f32;
14479                    for chunk in is_bytes.chunks_exact(4) {
14480                        let v = f32::from_le_bytes(chunk.try_into().unwrap());
14481                        if !(v.is_finite() && v > 0.0) {
14482                            return Err(format!(
14483                                "qwen4exp_gpu: {stem}.input_scale carries a non-finite/\
14484                                 non-positive value {v}"
14485                            )
14486                            .into());
14487                        }
14488                        mx = mx.max(v);
14489                    }
14490                    Some(mx)
14491                }
14492                Some(_) => {
14493                    return Err(format!("qwen4exp_gpu: {stem}.input_scale malformed").into());
14494                }
14495                None => None,
14496            };
14497            Ok(BankTensorSrc::Nvfp4 {
14498                codes: bytes.to_vec(),
14499                scales: scale_bytes.to_vec(),
14500                macros,
14501                act_scale,
14502            })
14503        }
14504        other => Err(format!("qwen4exp_gpu: {name} bank dtype {other} unsupported").into()),
14505    }
14506}
14507
14508/// Split a FUSED gate_up source ([E, 2ff, H], gate rows first per expert) into per-
14509/// projection gate/up sources. F32 splits data rows; NVFP4 splits code/scale byte rows
14510/// (row-granular, byte-clean) and duplicates the per-expert macro to both halves.
14511fn split_fused_gate_up(
14512    fused: BankTensorSrc,
14513    n_expert: usize,
14514    ff: usize,
14515    hidden: usize,
14516) -> Res<(BankTensorSrc, BankTensorSrc)> {
14517    match fused {
14518        BankTensorSrc::F32(data) => {
14519            if data.len() != n_expert * 2 * ff * hidden {
14520                return Err("qwen4exp_gpu: fused gate_up bank size mismatch".into());
14521            }
14522            let mut gate = Vec::with_capacity(n_expert * ff * hidden);
14523            let mut up = Vec::with_capacity(n_expert * ff * hidden);
14524            for expert in 0..n_expert {
14525                let base = expert * 2 * ff * hidden;
14526                gate.extend_from_slice(&data[base..base + ff * hidden]);
14527                up.extend_from_slice(&data[base + ff * hidden..base + 2 * ff * hidden]);
14528            }
14529            Ok((BankTensorSrc::F32(gate), BankTensorSrc::F32(up)))
14530        }
14531        BankTensorSrc::Bf16(bytes) => {
14532            let row = hidden * 2; // bf16 bytes per fused row
14533            if bytes.len() != n_expert * 2 * ff * row {
14534                return Err("qwen4exp_gpu: fused bf16 gate_up bank size mismatch".into());
14535            }
14536            let mut gate = Vec::with_capacity(n_expert * ff * row);
14537            let mut up = Vec::with_capacity(n_expert * ff * row);
14538            for expert in 0..n_expert {
14539                let base = expert * 2 * ff * row;
14540                gate.extend_from_slice(&bytes[base..base + ff * row]);
14541                up.extend_from_slice(&bytes[base + ff * row..base + 2 * ff * row]);
14542            }
14543            Ok((BankTensorSrc::Bf16(gate), BankTensorSrc::Bf16(up)))
14544        }
14545        BankTensorSrc::Nvfp4 {
14546            codes,
14547            scales,
14548            macros,
14549            act_scale,
14550        } => {
14551            let code_row = hidden / 2;
14552            let scale_row = hidden / 16;
14553            let mut gate_codes = Vec::with_capacity(n_expert * ff * code_row);
14554            let mut up_codes = Vec::with_capacity(n_expert * ff * code_row);
14555            let mut gate_scales = Vec::with_capacity(n_expert * ff * scale_row);
14556            let mut up_scales = Vec::with_capacity(n_expert * ff * scale_row);
14557            for expert in 0..n_expert {
14558                let cbase = expert * 2 * ff * code_row;
14559                gate_codes.extend_from_slice(&codes[cbase..cbase + ff * code_row]);
14560                up_codes
14561                    .extend_from_slice(&codes[cbase + ff * code_row..cbase + 2 * ff * code_row]);
14562                let sbase = expert * 2 * ff * scale_row;
14563                gate_scales.extend_from_slice(&scales[sbase..sbase + ff * scale_row]);
14564                up_scales
14565                    .extend_from_slice(&scales[sbase + ff * scale_row..sbase + 2 * ff * scale_row]);
14566            }
14567            Ok((
14568                BankTensorSrc::Nvfp4 {
14569                    codes: gate_codes,
14570                    scales: gate_scales,
14571                    macros: macros.clone(),
14572                    act_scale,
14573                },
14574                BankTensorSrc::Nvfp4 {
14575                    codes: up_codes,
14576                    scales: up_scales,
14577                    macros,
14578                    act_scale,
14579                },
14580            ))
14581        }
14582    }
14583}
14584
14585/// One PER-EXPERT projection (PerExpertModelopt dialect): the modelopt sibling schema
14586/// (`nvfp4_quant`'s modelopt arm, source.rs — weight U8 [out, in/2] + weight_scale +
14587/// scalar weight_scale_2), or a plain BF16 row where geometry forbids per-16 groups.
14588/// `input_scale` is validated (F32 scalar) and dropped — see the section header.
14589enum PerExpertSrc {
14590    F32(Vec<f32>),
14591    Nvfp4 {
14592        codes: Vec<u8>,
14593        scales: Vec<u8>,
14594        macro_scale: f32,
14595        input_scale: Option<f32>,
14596    },
14597}
14598
14599fn read_per_expert(
14600    model: &memra_gguf::safetensors::StModel,
14601    name: &str,
14602    out_f: usize,
14603    in_f: usize,
14604    quant: memra_gguf::tensor_contract::QuantConstraint,
14605) -> Res<PerExpertSrc> {
14606    use memra_gguf::tensor_contract::QuantConstraint;
14607    let (info, bytes) = model
14608        .raw(name)
14609        .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
14610    match quant {
14611        QuantConstraint::ExactFloat(_) => {
14612            if info.shape != [out_f as u64, in_f as u64] {
14613                return Err(format!("qwen4exp_gpu: {name} shape mismatch").into());
14614            }
14615            Ok(PerExpertSrc::F32(dequant_float(name, info, bytes)?))
14616        }
14617        QuantConstraint::Nvfp4 => {
14618            if info.dtype != "U8"
14619                || in_f % 16 != 0
14620                || info.shape != [out_f as u64, (in_f / 2) as u64]
14621                || bytes.len() != out_f * in_f / 2
14622            {
14623                return Err(format!("qwen4exp_gpu: {name} NVFP4 code shape mismatch").into());
14624            }
14625            let stem = name.strip_suffix(".weight").unwrap_or(name);
14626            let (scale_info, scale_bytes) = model
14627                .raw(&format!("{stem}.weight_scale"))
14628                .ok_or_else(|| format!("qwen4exp_gpu: missing {stem}.weight_scale"))?;
14629            if scale_info.dtype != "F8_E4M3"
14630                || scale_info.shape != [out_f as u64, (in_f / 16) as u64]
14631                || scale_bytes.len() != out_f * in_f / 16
14632            {
14633                return Err(format!("qwen4exp_gpu: {stem}.weight_scale shape mismatch").into());
14634            }
14635            let macro_scale = match model.raw(&format!("{stem}.weight_scale_2")) {
14636                Some((macro_info, macro_bytes))
14637                    if macro_info.dtype == "F32" && macro_bytes.len() == 4 =>
14638                {
14639                    f32::from_le_bytes(macro_bytes.try_into().unwrap())
14640                }
14641                None => 1.0,
14642                _ => return Err(format!("qwen4exp_gpu: {stem}.weight_scale_2 malformed").into()),
14643            };
14644            validate_macro(stem, macro_scale)?;
14645            // input_scale: modelopt's STATIC ACTIVATION scale (= calibrated amax /
14646            // (448*6)) — validated AND consumed since round 4: the W4A4 expert path
14647            // quantizes activations against the per-layer max of these (see
14648            // BankTensorSrc::Nvfp4::act_scale).
14649            let input_scale = match model.raw(&format!("{stem}.input_scale")) {
14650                Some((input_info, input_bytes)) => {
14651                    if input_info.dtype != "F32" || input_bytes.len() != 4 {
14652                        return Err(format!("qwen4exp_gpu: {stem}.input_scale malformed").into());
14653                    }
14654                    let v = f32::from_le_bytes(input_bytes.try_into().unwrap());
14655                    if !(v.is_finite() && v > 0.0) {
14656                        return Err(format!(
14657                            "qwen4exp_gpu: {stem}.input_scale carries a non-finite/non-positive \
14658                             value {v}"
14659                        )
14660                        .into());
14661                    }
14662                    Some(v)
14663                }
14664                None => None,
14665            };
14666            Ok(PerExpertSrc::Nvfp4 {
14667                codes: bytes.to_vec(),
14668                scales: scale_bytes.to_vec(),
14669                macro_scale,
14670                input_scale,
14671            })
14672        }
14673        other => Err(format!("qwen4exp_gpu: per-expert quant {other:?} unsupported").into()),
14674    }
14675}
14676
14677/// Concatenate per-expert sources (expert order 0..E) into one stacked BankTensorSrc.
14678/// Kinds must be uniform across a projection (the census derives them per geometry).
14679fn assemble_per_expert_bank(experts: Vec<PerExpertSrc>) -> Res<BankTensorSrc> {
14680    let mut f32_data: Vec<f32> = Vec::new();
14681    let mut codes: Vec<u8> = Vec::new();
14682    let mut scales: Vec<u8> = Vec::new();
14683    let mut macros: Vec<f32> = Vec::new();
14684    let mut act_scale: Option<f32> = None;
14685    let mut act_scale_complete = true;
14686    let mut kinds = (false, false);
14687    for expert in experts {
14688        match expert {
14689            PerExpertSrc::F32(data) => {
14690                kinds.0 = true;
14691                f32_data.extend_from_slice(&data);
14692            }
14693            PerExpertSrc::Nvfp4 {
14694                codes: c,
14695                scales: s,
14696                macro_scale,
14697                input_scale,
14698            } => {
14699                kinds.1 = true;
14700                codes.extend_from_slice(&c);
14701                scales.extend_from_slice(&s);
14702                macros.push(macro_scale);
14703                match input_scale {
14704                    Some(v) => act_scale = Some(act_scale.map_or(v, |a: f32| a.max(v))),
14705                    None => act_scale_complete = false,
14706                }
14707            }
14708        }
14709    }
14710    match kinds {
14711        (true, false) => Ok(BankTensorSrc::F32(f32_data)),
14712        (false, true) => Ok(BankTensorSrc::Nvfp4 {
14713            codes,
14714            scales,
14715            macros,
14716            act_scale: if act_scale_complete { act_scale } else { None },
14717        }),
14718        _ => Err("qwen4exp_gpu: mixed per-expert kinds within one projection".into()),
14719    }
14720}
14721
14722/// Trunk layer index of a family-keyed requirement (`trunk.layers.{il}. ...`).
14723fn family_layer_index(key: &str) -> Option<u32> {
14724    key.strip_prefix("trunk.layers.")?
14725        .split('.')
14726        .next()?
14727        .parse()
14728        .ok()
14729}
14730
14731/// Walk the pack contract over an HF safetensors dir and materialize the eager arm's
14732/// weight set. The expert dialect is PROBED from the artifact (per-expert names present
14733/// => the NVFP4 mint layout). Fails loudly on any missing name, shape/dtype mismatch, or
14734/// unsupported transform — nothing is skipped silently except the declared MTP/vision
14735/// owners.
14736/// Resolve a layer plan by GLOBAL index: trunk layers [0, n_trunk), then MTP blocks at
14737/// n_trunk + depth (the pack's mtp.layers.* mapping).
14738fn plan_layer_at(plan: &ModelPlan, index: u32) -> Option<&memra_gguf::model_plan::LayerPlan> {
14739    let n_trunk = plan.layers.len() as u32;
14740    if index < n_trunk {
14741        plan.layers.get(index as usize)
14742    } else {
14743        plan.mtp_blocks
14744            .iter()
14745            .find(|block| block.layer.index == index)
14746            .map(|block| &block.layer)
14747    }
14748}
14749
14750pub fn read_checkpoint(dir: &std::path::Path) -> Res<LoadedCheckpoint> {
14751    read_checkpoint_with(dir, LoadOptions::default())
14752}
14753
14754/// `read_checkpoint` with real-checkpoint loader knobs (`LoadOptions`).
14755pub fn read_checkpoint_with(dir: &std::path::Path, opts: LoadOptions) -> Res<LoadedCheckpoint> {
14756    use memra_gguf::model_packs::qwen4_exp::{ExpertDialect, tensor_contract_for};
14757    use memra_gguf::tensor_contract::{TensorMatch, TensorOwner};
14758    let config = std::fs::read_to_string(dir.join("config.json"))?;
14759    let cfg =
14760        memra_gguf::config::ModelConfig::from_hf(&memra_gguf::config::HfConfig::parse(&config));
14761    let pack = memra_gguf::model_packs::for_config(&cfg)
14762        .ok_or("qwen4exp_gpu: no model pack matches this config")?;
14763    if pack.family != "qwen4_exp" {
14764        return Err(format!("qwen4exp_gpu: config resolves to pack {}", pack.family).into());
14765    }
14766    let plan = pack.compile_plan(&cfg)?;
14767    let model = memra_gguf::safetensors::StModel::open(dir)?;
14768    // Dialect probe: layer 0 is always MoE; the mint un-fuses its experts.
14769    let dialect = if model
14770        .raw("model.language_model.layers.0.mlp.experts.0.gate_proj.weight")
14771        .is_some()
14772    {
14773        ExpertDialect::PerExpertModelopt
14774    } else {
14775        ExpertDialect::FusedBanks
14776    };
14777    let contract = tensor_contract_for(&cfg, &plan, dialect)?;
14778
14779    let mut weights = ReferenceWeights::new();
14780    let mut gate_up_banks: std::collections::BTreeMap<u32, BankTensorSrc> = Default::default();
14781    // Keyed by numeric expert index: the contract iterates the census BTreeMap in
14782    // LEXICOGRAPHIC name order (experts.10 before experts.2), so per-expert rows arrive
14783    // out of numeric order on any E > 9 — assembly must not assume arrival order.
14784    let mut per_expert: std::collections::BTreeMap<
14785        (u32, u8),
14786        std::collections::BTreeMap<u32, PerExpertSrc>,
14787    > = Default::default();
14788    let mut down_banks: std::collections::BTreeMap<u32, BankTensorSrc> = Default::default();
14789    let mut tables: std::collections::BTreeMap<u32, Vec<u8>> = Default::default();
14790    let n_trunk = plan.layers.len() as u32;
14791
14792    for requirement in &contract.requirements {
14793        match requirement.owner {
14794            // The eager trunk executes neither; vision rows stay contract-declared for
14795            // the census/checkpoint-parity gates but are never materialized here. MTP
14796            // rows materialize when the mtp-spec lane asks (`LoadOptions::load_mtp`).
14797            TensorOwner::Mtp(_) if !opts.load_mtp => continue,
14798            TensorOwner::Vision(_) => continue,
14799            TensorOwner::Global | TensorOwner::Layer(_) | TensorOwner::Mtp(_) => {}
14800        }
14801        // The n-gram shard bank: one semantic tensor, `names` in shard order (pack sorts).
14802        if requirement.match_mode == TensorMatch::All {
14803            let TensorId::Family { key, .. } = &requirement.id else {
14804                return Err("qwen4exp_gpu: unexpected All-mode requirement".into());
14805            };
14806            let layer =
14807                family_layer_index(key).ok_or("qwen4exp_gpu: n-gram bank outside a trunk layer")?;
14808            let mut bytes = Vec::new();
14809            for name in &requirement.names {
14810                let (info, shard) = model
14811                    .raw(name)
14812                    .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
14813                if info.dtype != "BF16" || info.shape != requirement.shape {
14814                    return Err(format!("qwen4exp_gpu: {name} shard shape/dtype mismatch").into());
14815                }
14816                bytes.extend_from_slice(shard);
14817            }
14818            tables.insert(layer, bytes);
14819            continue;
14820        }
14821        let name = &requirement.names[0];
14822        // The mint's UNSHARDED table: same Family bank id, one BF16 tensor — read raw
14823        // bytes (a host f32 materialization of 51B rows is not a thing).
14824        if let TensorId::Family { key, .. } = &requirement.id {
14825            if key.ends_with(".ple_embedding.ngram_embedding") {
14826                let layer = family_layer_index(key)
14827                    .ok_or("qwen4exp_gpu: n-gram table outside a trunk layer")?;
14828                let (info, bytes) = model
14829                    .raw(name)
14830                    .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
14831                if info.dtype != "BF16" || info.shape != requirement.shape {
14832                    return Err(format!("qwen4exp_gpu: {name} table shape/dtype mismatch").into());
14833                }
14834                tables.insert(layer, bytes.to_vec());
14835                continue;
14836            }
14837        }
14838        // Per-expert projections (PerExpertModelopt).
14839        if let TensorId::Expert {
14840            layer,
14841            expert,
14842            tensor,
14843        } = requirement.id
14844        {
14845            let (out_f, in_f) = (requirement.shape[0] as usize, requirement.shape[1] as usize);
14846            let src = read_per_expert(&model, name, out_f, in_f, requirement.quant)?;
14847            let proj = match tensor {
14848                memra_gguf::tensor_contract::ExpertTensor::Gate => 0u8,
14849                memra_gguf::tensor_contract::ExpertTensor::Up => 1,
14850                memra_gguf::tensor_contract::ExpertTensor::Down => 2,
14851            };
14852            if per_expert
14853                .entry((layer, proj))
14854                .or_default()
14855                .insert(expert, src)
14856                .is_some()
14857            {
14858                return Err(format!(
14859                    "qwen4exp_gpu: duplicate per-expert row layer {layer} expert {expert}"
14860                )
14861                .into());
14862            }
14863            continue;
14864        }
14865        // Fused expert banks (FusedBanks) bypass ReferenceWeights (device residency).
14866        if let TensorId::Layer { index, tensor } = requirement.id {
14867            if matches!(
14868                tensor,
14869                LayerTensor::MoeExpertGateUpBank | LayerTensor::MoeExpertDownBank
14870            ) {
14871                let (n_expert, out_f, in_f) = (
14872                    requirement.shape[0] as usize,
14873                    requirement.shape[1] as usize,
14874                    requirement.shape[2] as usize,
14875                );
14876                // The MTP bank (index >= n_trunk) keeps raw bf16 bytes: it goes DEVICE
14877                // bf16-resident at build (never f32-expanded — 10 GB vs 5 GB).
14878                let keep_bf16 = opts.host_bf16_banks || index >= n_trunk;
14879                let bank = read_bank_tensor(&model, name, n_expert, out_f, in_f, keep_bf16)?;
14880                if tensor == LayerTensor::MoeExpertGateUpBank {
14881                    gate_up_banks.insert(index, bank);
14882                } else {
14883                    down_banks.insert(index, bank);
14884                }
14885                continue;
14886            }
14887        }
14888        let (info, bytes) = model
14889            .raw(name)
14890            .ok_or_else(|| format!("qwen4exp_gpu: checkpoint is missing {name}"))?;
14891        if info.shape != requirement.shape {
14892            return Err(format!(
14893                "qwen4exp_gpu: {name} shape {:?} != contract {:?}",
14894                info.shape, requirement.shape
14895            )
14896            .into());
14897        }
14898        if info.dtype == "I64" {
14899            let ints = read_i64(name, info, bytes)?;
14900            let shape: Vec<usize> = info.shape.iter().map(|&d| d as usize).collect();
14901            weights.insert(
14902                requirement.id.clone(),
14903                ReferenceTensor::new_i64(shape, ints)?,
14904            );
14905            continue;
14906        }
14907        let mut data = dequant_float(name, info, bytes)?;
14908        if norm_fold_add_one(name) && !(opts.indexer_norm_raw && indexer_layernorm(name)) {
14909            for value in &mut data {
14910                *value += 1.0;
14911            }
14912        }
14913        let kind = bridge_transform(requirement.transform)?;
14914        let (ne_out, out_bytes) = kind.apply(&mut data, info.ne(), &cfg);
14915        let data: Vec<f32> = out_bytes
14916            .chunks_exact(4)
14917            .map(|chunk| f32::from_le_bytes(chunk.try_into().unwrap()))
14918            .collect();
14919        let mut shape: Vec<usize> = ne_out.iter().rev().map(|&d| d as usize).collect();
14920        // The PLE conv ships [wide, 1, K]; the reference executor (and the depthwise
14921        // kernel) consume the squeezed [wide, K] form — same bytes, GDN-conv precedent.
14922        if name.ends_with("ple.conv1d.weight") && shape.len() == 3 && shape[1] == 1 {
14923            shape = vec![shape[0], shape[2]];
14924        }
14925        // shared_expert_gate ships [1, H]; the reference binds the squeezed [H] row.
14926        if name.ends_with("mlp.shared_expert_gate.weight") && shape.len() == 2 && shape[0] == 1 {
14927            shape = vec![shape[1]];
14928        }
14929        weights.insert(requirement.id.clone(), ReferenceTensor::new(shape, data)?);
14930    }
14931
14932    let mut banks = std::collections::BTreeMap::new();
14933    // FusedBanks: split the fused gate_up into per-projection halves (trunk layers AND
14934    // the MTP block, whose layer plan lives at index n_trunk in plan.mtp_blocks).
14935    for (index, gate_up) in gate_up_banks {
14936        let down = down_banks
14937            .remove(&index)
14938            .ok_or_else(|| format!("qwen4exp_gpu: layer {index} has gate_up but no down bank"))?;
14939        let layer_plan = plan_layer_at(&plan, index)
14940            .ok_or_else(|| format!("qwen4exp_gpu: bank at unknown layer index {index}"))?;
14941        let MlpPlan::Moe(moe) = &layer_plan.mlp else {
14942            return Err(format!("qwen4exp_gpu: bank on non-MoE layer {index}").into());
14943        };
14944        let (n_expert, ff) = (
14945            moe.expert_count as usize,
14946            moe.expert_intermediate_size as usize,
14947        );
14948        let hidden = plan.hidden_size as usize;
14949        let (gate, up) = split_fused_gate_up(gate_up, n_expert, ff, hidden)?;
14950        banks.insert(
14951            index,
14952            BankSrc {
14953                gate,
14954                up,
14955                down,
14956                n_expert,
14957                ff,
14958                hidden,
14959            },
14960        );
14961    }
14962    if !down_banks.is_empty() {
14963        return Err("qwen4exp_gpu: down bank without a gate_up twin".into());
14964    }
14965    // PerExpertModelopt: assemble per-projection stacks in expert order.
14966    let mut per_layer: std::collections::BTreeMap<u32, [Option<BankTensorSrc>; 3]> =
14967        Default::default();
14968    for ((layer, proj), experts) in per_expert {
14969        let layer_plan = plan_layer_at(&plan, layer)
14970            .ok_or_else(|| format!("qwen4exp_gpu: per-expert rows at unknown layer {layer}"))?;
14971        let MlpPlan::Moe(moe) = &layer_plan.mlp else {
14972            return Err(format!("qwen4exp_gpu: per-expert rows on non-MoE layer {layer}").into());
14973        };
14974        let count = moe.expert_count as usize;
14975        // Contiguity check: BTreeMap<u32, _> iteration is numeric order; every expert
14976        // index 0..E must be present exactly once.
14977        if experts.len() != count || experts.keys().last().copied() != Some(count as u32 - 1) {
14978            return Err(format!(
14979                "qwen4exp_gpu: layer {layer} proj {proj} has {} experts, plan says {count}",
14980                experts.len()
14981            )
14982            .into());
14983        }
14984        per_layer.entry(layer).or_default()[proj as usize] =
14985            Some(assemble_per_expert_bank(experts.into_values().collect())?);
14986    }
14987    for (layer, mut projections) in per_layer {
14988        let MlpPlan::Moe(moe) = &plan_layer_at(&plan, layer).expect("checked above").mlp else {
14989            unreachable!("checked above");
14990        };
14991        let take = |slot: &mut Option<BankTensorSrc>, what: &str| -> Res<BankTensorSrc> {
14992            slot.take()
14993                .ok_or_else(|| format!("qwen4exp_gpu: layer {layer} missing {what} experts").into())
14994        };
14995        banks.insert(
14996            layer,
14997            BankSrc {
14998                gate: take(&mut projections[0], "gate")?,
14999                up: take(&mut projections[1], "up")?,
15000                down: take(&mut projections[2], "down")?,
15001                n_expert: moe.expert_count as usize,
15002                ff: moe.expert_intermediate_size as usize,
15003                hidden: plan.hidden_size as usize,
15004            },
15005        );
15006    }
15007    Ok(LoadedCheckpoint {
15008        plan,
15009        weights,
15010        banks,
15011        tables,
15012    })
15013}
15014
15015impl LoadedCheckpoint {
15016    /// Expand banks and n-gram tables into plain `ReferenceWeights` entries so
15017    /// memra-reference can execute the checkpoint. TINY/SIBLING SCALE ONLY — the real
15018    /// artifact's banks/table do not fit host f32; the GPU path never takes this.
15019    pub fn into_reference_weights(mut self) -> Res<ReferenceWeights> {
15020        for (index, bank) in self.banks {
15021            let gate = bank_to_f32(&bank.gate, bank.n_expert, bank.ff, bank.hidden)?;
15022            let up = bank_to_f32(&bank.up, bank.n_expert, bank.ff, bank.hidden)?;
15023            let down = bank_to_f32(&bank.down, bank.n_expert, bank.hidden, bank.ff)?;
15024            self.weights.insert(
15025                layer_id(index, LayerTensor::MoeExpertGateBank),
15026                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], gate)?,
15027            );
15028            self.weights.insert(
15029                layer_id(index, LayerTensor::MoeExpertUpBank),
15030                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], up)?,
15031            );
15032            self.weights.insert(
15033                layer_id(index, LayerTensor::MoeExpertDownBank),
15034                ReferenceTensor::new(vec![bank.n_expert, bank.hidden, bank.ff], down)?,
15035            );
15036        }
15037        for (index, bytes) in self.tables {
15038            let ple = self.plan.layers[index as usize]
15039                .ple
15040                .as_ref()
15041                .ok_or("qwen4exp_gpu: table on a non-PLE layer")?;
15042            let head_dim = ple.head_embed_dim as usize;
15043            let table = NgramTable::Bf16(bytes);
15044            let rows = table.rows(head_dim);
15045            let mut data = vec![0.0f32; rows * head_dim];
15046            for row in 0..rows {
15047                table.gather_into(
15048                    row,
15049                    head_dim,
15050                    &mut data[row * head_dim..(row + 1) * head_dim],
15051                );
15052            }
15053            self.weights.insert(
15054                family_id(format!(
15055                    "trunk.layers.{index}.ple.ple_embedding.ngram_embedding"
15056                )),
15057                ReferenceTensor::new(vec![rows, head_dim], data)?,
15058            );
15059        }
15060        Ok(self.weights)
15061    }
15062}
15063
15064impl LoadedCheckpoint {
15065    /// CLONE the float weights and expand ONLY the MTP bank(s) into `ReferenceWeights`
15066    /// entries — the real-checkpoint draft-parity instrument (mtp-spec lane): the host
15067    /// reference twin needs the mtp.* rows + embed/head, and must NOT expand the trunk
15068    /// banks (48 layers of f32 experts do not fit anywhere). Borrowing form so ONE
15069    /// checkpoint read serves both the engine model and the host twin.
15070    pub fn mtp_reference_weights(&self) -> Res<ReferenceWeights> {
15071        let mut weights = self.weights.clone();
15072        let n_trunk = self.plan.layers.len() as u32;
15073        for (index, bank) in &self.banks {
15074            if *index < n_trunk {
15075                continue;
15076            }
15077            let gate = bank_to_f32(&bank.gate, bank.n_expert, bank.ff, bank.hidden)?;
15078            let up = bank_to_f32(&bank.up, bank.n_expert, bank.ff, bank.hidden)?;
15079            let down = bank_to_f32(&bank.down, bank.n_expert, bank.hidden, bank.ff)?;
15080            weights.insert(
15081                layer_id(*index, LayerTensor::MoeExpertGateBank),
15082                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], gate)?,
15083            );
15084            weights.insert(
15085                layer_id(*index, LayerTensor::MoeExpertUpBank),
15086                ReferenceTensor::new(vec![bank.n_expert, bank.ff, bank.hidden], up)?,
15087            );
15088            weights.insert(
15089                layer_id(*index, LayerTensor::MoeExpertDownBank),
15090                ReferenceTensor::new(vec![bank.n_expert, bank.hidden, bank.ff], down)?,
15091            );
15092        }
15093        Ok(weights)
15094    }
15095}
15096
15097/// Host-dequant a bank tensor to f32 [E, out, in] (NVFP4 via the pub dsv4 decoder — the
15098/// same value chain the device kernel reproduces).
15099fn bank_to_f32(bank: &BankTensorSrc, n_expert: usize, out_f: usize, in_f: usize) -> Res<Vec<f32>> {
15100    match bank {
15101        BankTensorSrc::F32(data) => Ok(data.clone()),
15102        BankTensorSrc::Bf16(bytes) => Ok(bytes
15103            .chunks_exact(2)
15104            .map(|b| f32::from_bits(u32::from(u16::from_le_bytes([b[0], b[1]])) << 16))
15105            .collect()),
15106        BankTensorSrc::Nvfp4 {
15107            codes,
15108            scales,
15109            macros,
15110            ..
15111        } => {
15112            let mut out = Vec::with_capacity(n_expert * out_f * in_f);
15113            let wbytes = out_f * in_f / 2;
15114            let sbytes = out_f * in_f / 16;
15115            for expert in 0..n_expert {
15116                out.extend(memra_gguf::dsv4::dequant_nvfp4_expert(
15117                    &codes[expert * wbytes..(expert + 1) * wbytes],
15118                    &scales[expert * sbytes..(expert + 1) * sbytes],
15119                    macros[expert],
15120                    out_f,
15121                    in_f,
15122                ));
15123            }
15124            Ok(out)
15125        }
15126    }
15127}
15128
15129impl Qwen4ExpGpu {
15130    /// Load a qwen4_exp checkpoint dir (config.json + safetensors; the BF16 export or the
15131    /// per-expert modelopt NVFP4 mint) through the pack/plan/contract into engine-resident
15132    /// weights: trunk f32 on device, n-gram table host-resident bf16, NVFP4 expert banks
15133    /// as-stored on device.
15134    pub fn load_from_dir(e: &Engine, dir: &std::path::Path) -> Res<Self> {
15135        Self::from_loaded_checkpoint(e, read_checkpoint(dir)?)
15136    }
15137
15138    /// `load_from_dir` with real-checkpoint loader knobs (`LoadOptions`).
15139    pub fn load_from_dir_with(e: &Engine, dir: &std::path::Path, opts: LoadOptions) -> Res<Self> {
15140        Self::from_loaded_checkpoint(e, read_checkpoint_with(dir, opts)?)
15141    }
15142
15143    /// Card-1 draft placement (mtp10): the trunk builds on `e` (card 0) and the MTP
15144    /// draft block — weights, ~5 GB DeviceBf16 expert bank, private lm-head copy — on
15145    /// `draft_e` (card 1). Requires `opts.load_mtp` and P2P between the pair
15146    /// (`tp2_enable_p2p`); the spec loop's wide rows cross per round.
15147    pub fn load_from_dir_dev1(
15148        e: &Engine,
15149        draft_e: &Engine,
15150        dir: &std::path::Path,
15151        opts: LoadOptions,
15152    ) -> Res<Self> {
15153        Self::from_loaded_checkpoint_dual(e, Some(draft_e), read_checkpoint_with(dir, opts)?)
15154    }
15155
15156    /// Consume a `LoadedCheckpoint` into the engine-resident model. Banks and n-gram
15157    /// tables MOVE (the real artifact's 102 GB table must not be cloned).
15158    pub fn from_loaded_checkpoint(e: &Engine, checkpoint: LoadedCheckpoint) -> Res<Self> {
15159        Self::from_loaded_checkpoint_dual(e, None, checkpoint)
15160    }
15161
15162    /// `from_loaded_checkpoint` with the optional card-1 draft engine: the MTP bank
15163    /// (layer index >= n_trunk) uploads to `draft_e` when given; the trunk banks stay
15164    /// on `e` either way.
15165    pub fn from_loaded_checkpoint_dual(
15166        e: &Engine,
15167        draft_e: Option<&Engine>,
15168        checkpoint: LoadedCheckpoint,
15169    ) -> Res<Self> {
15170        let LoadedCheckpoint {
15171            plan,
15172            weights,
15173            banks,
15174            tables,
15175        } = checkpoint;
15176        let mut parts = ExternalParts::default();
15177        let n_trunk = plan.layers.len() as u32;
15178        let upload_half = |e: &Engine, src: BankTensorSrc, device_bf16: bool| -> Res<BankHalf> {
15179            Ok(match src {
15180                BankTensorSrc::F32(data) => BankHalf::F32(e.htod(&data)?),
15181                BankTensorSrc::Nvfp4 {
15182                    codes,
15183                    scales,
15184                    macros,
15185                    ..
15186                } => BankHalf::Nvfp4 {
15187                    codes: e.htod_bytes(&codes)?,
15188                    scales: e.htod_bytes(&scales)?,
15189                    macros_dev: e.htod(&macros)?,
15190                    macros,
15191                },
15192                // Residency was decided at read time (LoadOptions::host_bf16_banks /
15193                // load_mtp): trunk bf16 stays host (gate-mode); the MTP draft bank goes
15194                // device-resident bf16 (the draft decode path reads it in place).
15195                BankTensorSrc::Bf16(bytes) if device_bf16 => {
15196                    BankHalf::DeviceBf16(e.htod_bytes(&bytes)?)
15197                }
15198                BankTensorSrc::Bf16(bytes) => BankHalf::HostBf16(bytes),
15199            })
15200        };
15201        for (index, bank) in banks {
15202            let device_bf16 = index >= n_trunk;
15203            // The MTP bank follows the draft's placement (card 1 when dev1 is armed).
15204            let bank_e = if device_bf16 { draft_e.unwrap_or(e) } else { e };
15205            parts.expert_banks.insert(
15206                index,
15207                ExpertBank {
15208                    gate: upload_half(bank_e, bank.gate, device_bf16)?,
15209                    up: upload_half(bank_e, bank.up, device_bf16)?,
15210                    down: upload_half(bank_e, bank.down, device_bf16)?,
15211                },
15212            );
15213        }
15214        for (index, bytes) in tables {
15215            parts.ngram_tables.insert(index, NgramTable::Bf16(bytes));
15216        }
15217        Self::from_reference_weights_with(e, draft_e, &plan, &weights, parts)
15218    }
15219}
15220
15221// ==================================== TP2 (perf round 3) ====================================
15222//
15223// Two-card tensor-parallel DECODE over PCIe P2P (no NVLink) — the PROFILE-2 §TP2
15224// projection made real. Structure (the tp2-join-diet playbook, step37 lane):
15225//
15226// - The RESIDUAL IS REPLICATED: both cards hold the wide planes and run the entry embed,
15227//   PLE block, hyper-connection read/write gates, and exit mixer with bit-identical
15228//   weights on bit-identical inputs (replicated deterministic compute — kills every
15229//   broadcast except the two joins below). All replicated device math runs deterministic
15230//   kernels (bf16w matvecs, fused gates); TP2 therefore REQUIRES the bf16 trunk twins.
15231// - SPLIT: GDN by key-head blocks (card d owns orig key heads [d·nk/2, (d+1)·nk/2) and
15232//   the value heads mapping to them — compact per-card head order keeps kh = h % nk_h)),
15233//   QSA by head halves (12/12 query heads, 1/1 KV heads), MoE routed experts by expert-id
15234//   halves (card d owns experts [d·E/2, (d+1)·E/2); top-10 splits ~5/5 on average),
15235//   shared expert by ff halves, lm_head by vocab halves (card 0 reads the resident twin's
15236//   row prefix; card 1 holds the suffix copy).
15237// - JOINS: exactly 2 per layer (mixer out-proj partials, MoE+shared partials), each a
15238//   [hidden] f32 row pushed as a P2P kernel store into the peer's resident staging buffer
15239//   (`q4e_push_f32`, the direct-join mechanism) + one cross-device event wait each way;
15240//   BOTH cards then compute out = partial0 + partial1 in the SAME rank order, so the
15241//   replicated residual stays bit-identical across cards.
15242// - HOST twins unchanged: MoE routing (router GEMV + dtoh on card 0, top-k once, filtered
15243//   selection H2D to both), QSA indexer (card 0 projects + host mask, mask H2D to both),
15244//   PLE n-gram hashing (host, gathered rows H2D to both; the 102 GB table stays host-
15245//   resident and SHARED — the card-1 PLE replica carries no table).
15246// - Decode graphs stay OFF in TP2 (eager issue; the joins are the schedule). Prefill
15247//   stays single-card; the first `decode_step_tp2` migrates the mixer state into
15248//   per-card halves (host bounce, one-time) and the state is TP2-latched from then on.
15249//
15250// EXACTNESS CLASS (the gate statement): TP2 output matches single-card to TOLERANCE, not
15251// bit — the split out-projections sum row halves in a different association than the
15252// full GEMV, the expert combine becomes (Σ card-0 slots) + (Σ card-1 slots) instead of
15253// the slot-sequential chain, and the join add reorders those partial sums. Same
15254// accumulation class as every banked seam; gated by `--tp2-gate` per-row envelope +
15255// argmax vs the single-card twin, plus the greedy-divergence battery.
15256
15257/// Per-card compact GDN half (see the head-map comment on `tp2_gdn_head_map`).
15258struct GdnHalfW {
15259    nk_h: usize,
15260    nv_h: usize,
15261    hk: usize,
15262    hv: usize,
15263    kernel: usize,
15264    gate_activation: GdnGateActivation,
15265    /// Row-stacked [qkv; z; beta; alpha] half twin (proj-stack residency: per-mat
15266    /// launches read row-offset views; the seam launches the whole stack).
15267    proj_b16: CudaSlice<u8>,
15268    out_b16: CudaSlice<u8>, // [hidden, nv_h*hv] (compact column block)
15269    conv_w: CudaSlice<f32>, // [conv_dim_h, K]
15270    a: CudaSlice<f32>,      // [nv_h]
15271    dt: CudaSlice<f32>,     // [nv_h]
15272    norm: CudaSlice<f32>,   // [hv] (replicated)
15273}
15274
15275/// Per-card QSA half: query heads [d*nh_h, (d+1)*nh_h), KV heads [d*nkv_h, ...).
15276struct QsaHalfW {
15277    nh_h: usize,
15278    nkv_h: usize,
15279    hd: usize,
15280    n_rot: usize,
15281    rope_base: f32,
15282    scale: f32,
15283    /// Row-stacked [wq; wk; wv] half twin (proj-stack residency; wq rows are the fused
15284    /// [q|gate] block).
15285    proj_b16: CudaSlice<u8>,
15286    wo_b16: CudaSlice<u8>, // [hidden, nh_h*hd] (compact column block)
15287    q_norm: Option<CudaSlice<f32>>,
15288    k_norm: Option<CudaSlice<f32>>,
15289    /// YaRN tables on THIS half's card (long-context lane); `None` on the shipped config.
15290    yarn: Option<YarnRopeW>,
15291}
15292
15293enum MixerHalfW {
15294    Gdn(GdnHalfW),
15295    Qsa(QsaHalfW),
15296}
15297
15298/// Card-1 NVFP4 expert-bank half (experts [E/2, E), local ids 0..E/2).
15299struct Nvfp4Half {
15300    codes: CudaSlice<u8>,
15301    scales: CudaSlice<u8>,
15302    macros_dev: CudaSlice<f32>,
15303}
15304
15305struct MoeHalfW {
15306    /// Card-1 bank halves (card 0 addresses the resident full bank with original ids).
15307    gate1: Nvfp4Half,
15308    up1: Nvfp4Half,
15309    down1: Nvfp4Half,
15310    /// Shared expert: card 0 reads the resident full twins' ROW PREFIX (gate/up) and its
15311    /// own compact down-column block; card 1 holds suffix/compact copies.
15312    shared_down0: CudaSlice<u8>, // card0 [hidden, sff_h]
15313    shared_down1: CudaSlice<u8>,                // card1 [hidden, sff_h]
15314    shared_input_gate1: Option<CudaSlice<f32>>, // card1 [hidden]
15315    /// Row-stacked [gate_half; up_half] twins (proj-stack residency): card 0 stacks the
15316    /// ROW PREFIXES of the full mats (not contiguous in the resident full stack), card 1
15317    /// its suffix copies. Per-mat launches read row-offset views (0 / sff_h).
15318    shared_gu0_b16: CudaSlice<u8>,
15319    shared_gu1_b16: CudaSlice<u8>,
15320}
15321
15322struct Tp2LayerW {
15323    attn_gate1: GateW,
15324    mlp_gate1: GateW,
15325    mixer0: MixerHalfW,
15326    mixer1: MixerHalfW,
15327    moe: MoeHalfW,
15328    ple1: Option<PleW>,
15329    /// This layer's resolved expert placement — the SAME object that chose which expert
15330    /// rows were gathered into `moe`'s card-1 bank. One source of truth for the upload
15331    /// and for the route split is what keeps a placement from being applied to one and
15332    /// not the other (the failure mode that would read as a model bug, not a config bug).
15333    place: LayerPlacement,
15334}
15335
15336/// The TP2 shard: card-1 replicas + both cards' split halves + join plumbing.
15337pub struct Tp2Shard {
15338    layers: Vec<Tp2LayerW>,
15339    exit_gate1: GateW,
15340    lm_head1: CudaSlice<u8>, // card1 bf16 [vocab - vsplit, hidden]
15341    vsplit: usize,
15342    /// Join staging, TWO buffers per direction alternating by join parity. Two is
15343    /// provably enough: the overwrite of buffer (j+2 mod 2) is transitively ordered
15344    /// after the peer's read at join j (the peer's push at j+1 follows its add at j on
15345    /// its in-order stream, and our wait on that push precedes our overwrite).
15346    stage0: [CudaSlice<f32>; 2], // card0 staging (receives card1 partials)
15347    stage1: [CudaSlice<f32>; 2], // card1 staging (receives card0 partials)
15348    stage0_raw: [u64; 2],
15349    stage1_raw: [u64; 2],
15350    ev0: [cudarc::driver::CudaEvent; 2], // card0 push done, by join parity
15351    ev1: [cudarc::driver::CudaEvent; 2], // card1 push done, by join parity
15352}
15353
15354enum MixerHalfState {
15355    Gdn {
15356        conv: CudaSlice<f32>,  // [pad, conv_dim_h]
15357        state: CudaSlice<f32>, // [nv_h, hv, hk]
15358    },
15359    Qsa {
15360        /// This card's KV half [cap, nkv_h*hd] — f32 or the kvq q8_0/q5_1 byte caches
15361        /// (format follows the single-card store; head halves are 32-block aligned at
15362        /// hd % 32 == 0, so quantized migration gathers BYTES verbatim).
15363        kv: QsaKvStore,
15364    },
15365}
15366
15367struct Tp2LayerState {
15368    m0: MixerHalfState,
15369    m1: MixerHalfState,
15370    ple1: Option<PleState>,
15371}
15372
15373struct Tp2State {
15374    ws1: StepPool,
15375    layers: Vec<Tp2LayerState>,
15376    graphs: Tp2Graphs,
15377    /// TP2-PREFILL join staging (chunk-sized [t*hidden] per direction, two buffers per
15378    /// direction by join parity — the decode stage buffers' proof carries over
15379    /// verbatim). Lazily sized at the first `forward_tp2` chunk; `raw` = the peer's
15380    /// UVA pointers baked for `launch_push`.
15381    pf_stage0: Option<[CudaSlice<f32>; 2]>, // on card0 (receives card1 partials)
15382    pf_stage1: Option<[CudaSlice<f32>; 2]>,
15383    pf_stage0_raw: [u64; 2],
15384    pf_stage1_raw: [u64; 2],
15385    pf_rows: usize,
15386}
15387
15388/// Captured TP2 decode segments per card (the single-card StepGraphs pattern applied
15389/// per rank): `a[d][li]` = attn gate_read + GDN half + join push, `b[d][li]` = join add
15390/// + gate_write + mlp gate_read (+ card1 shared-half prestage), `exit[d]` = exit mixer
15391/// + lm_head half. GDN layers without PLE only; QSA/PLE layers, the router boundary,
15392/// the variable-shape MoE tail, and the MoE join stay eager. Event records/waits sit
15393/// BETWEEN segment launches (not capturable) — same choreography in warm and replay
15394/// modes. The first TP2 decode step runs fully eager to park every slot (allocations
15395/// inside a capture become graph mem nodes); captures are lazy on the second step.
15396#[derive(Default)]
15397struct Tp2Graphs {
15398    warm: bool,
15399    a: [Vec<Option<GraphEntry>>; 2],
15400    b: [Vec<Option<GraphEntry>>; 2],
15401    /// Count-gated MoE tail (routed half + shared add + join push) — fixed launch
15402    /// shapes via the pack blob, so the variable expert split still captures.
15403    c: [Vec<Option<GraphEntry>>; 2],
15404    /// MoE join add + gate_write.
15405    d: [Vec<Option<GraphEntry>>; 2],
15406    exit: [Option<GraphEntry>; 2],
15407}
15408
15409/// Compact value-head order for card `d`: heads h with h % nk in [d*nk_h, (d+1)*nk_h),
15410/// ascending. With nv % nk == 0 this is exactly `(j / nk_h) * nk + (j % nk_h) + d*nk_h`,
15411/// and the compact system stays self-consistent with the kernels' kh = h % nk_h mapping.
15412fn tp2_gdn_head_map(d: usize, nk: usize, nv: usize) -> Vec<usize> {
15413    let nk_h = nk / 2;
15414    let nv_h = nv / 2;
15415    (0..nv_h)
15416        .map(|j| (j / nk_h) * nk + (j % nk_h) + d * nk_h)
15417        .collect()
15418}
15419
15420/// Gather whole rows (row-major [rows, in_f]) into a compact copy.
15421fn gather_rows_host(src: &[f32], in_f: usize, rows: &[usize]) -> Vec<f32> {
15422    let mut out = Vec::with_capacity(rows.len() * in_f);
15423    for &r in rows {
15424        out.extend_from_slice(&src[r * in_f..(r + 1) * in_f]);
15425    }
15426    out
15427}
15428
15429/// Gather column blocks per row (row-major [nrows, ncols]) into a compact copy.
15430fn gather_cols_host(
15431    src: &[f32],
15432    nrows: usize,
15433    ncols: usize,
15434    blocks: &[(usize, usize)],
15435) -> Vec<f32> {
15436    let width: usize = blocks.iter().map(|&(_, l)| l).sum();
15437    let mut out = Vec::with_capacity(nrows * width);
15438    for r in 0..nrows {
15439        for &(start, len) in blocks {
15440            out.extend_from_slice(&src[r * ncols + start..r * ncols + start + len]);
15441        }
15442    }
15443    out
15444}
15445
15446fn need_twin(e: &Engine, data: &[f32], in_f: usize, what: &str) -> Res<CudaSlice<u8>> {
15447    bf16_twin(e, data, in_f)?.ok_or_else(|| {
15448        format!("qwen4exp_gpu tp2: {what} has no exact bf16 twin (in_f {in_f})").into()
15449    })
15450}
15451
15452/// Launch `q4e_push_f32`: UVA store of `n` f32 into the PEER address `dst_raw` on `e`'s
15453/// stream (the direct-join push).
15454fn launch_push(e: &Engine, src: &CudaSlice<f32>, dst_raw: u64, n: usize) -> Res<()> {
15455    let f = e.func("q4e_push_f32");
15456    let cfg = LaunchConfig::for_num_elems(n as u32);
15457    let nl = n as i64;
15458    let stream = e.gpu.stream();
15459    let mut b = stream.launch_builder(&f);
15460    b.arg(src).arg(&dst_raw).arg(&nl);
15461    unsafe {
15462        b.launch(cfg)?;
15463    }
15464    Ok(())
15465}
15466
15467/// Enable bidirectional P2P + pool peer access between two engines (the
15468/// `configure_native_p2p` essentials for the qwen4_exp TP2 pair; pool access makes every
15469/// pooled allocation UVA-addressable from the peer, which is what `q4e_push_f32` needs).
15470pub fn tp2_enable_p2p(e0: &Engine, e1: &Engine) -> Res<()> {
15471    use cudarc::driver::sys;
15472    for (src, dst) in [(e0, e1), (e1, e0)] {
15473        let mut can = 0i32;
15474        unsafe {
15475            sys::cuDeviceCanAccessPeer(&mut can, src.ctx().cu_device(), dst.ctx().cu_device())
15476                .result()?;
15477        }
15478        if can == 0 {
15479            return Err(format!(
15480                "qwen4exp_gpu tp2: dev{} cannot access dev{} over P2P",
15481                src.ctx().ordinal(),
15482                dst.ctx().ordinal()
15483            )
15484            .into());
15485        }
15486        src.ctx().bind_to_thread()?;
15487        let rc = unsafe { sys::cuCtxEnablePeerAccess(dst.ctx().cu_ctx(), 0) };
15488        use cudarc::driver::sys::cudaError_enum as E;
15489        if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
15490            return Err(format!("qwen4exp_gpu tp2: cuCtxEnablePeerAccess failed: {rc:?}").into());
15491        }
15492    }
15493    for (owner, accessor) in [(e0, e1), (e1, e0)] {
15494        let device = cudarc::driver::result::device::get(owner.ctx().ordinal() as i32)?;
15495        let mut pool: sys::CUmemoryPool = std::ptr::null_mut();
15496        unsafe {
15497            sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
15498        }
15499        let desc = sys::CUmemAccessDesc {
15500            location: sys::CUmemLocation {
15501                type_: sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
15502                id: accessor.ctx().ordinal() as i32,
15503            },
15504            flags: sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
15505        };
15506        let rc = unsafe { sys::cuMemPoolSetAccess(pool, &desc, 1) };
15507        if rc != sys::cudaError_enum::CUDA_SUCCESS {
15508            return Err(format!("qwen4exp_gpu tp2: cuMemPoolSetAccess failed: {rc:?}").into());
15509        }
15510    }
15511    Ok(())
15512}
15513
15514/// Build the card-1 replica PLE weight set from the checkpoint's host weights (the
15515/// device parts of `PleW` with an EMPTY table — the 102 GB n-gram table stays host-
15516/// resident on the model and is passed to `ple_block` explicitly).
15517fn build_ple_replica(
15518    e: &Engine,
15519    weights: &ReferenceWeights,
15520    prefix: &str,
15521    ple_plan: &PleEmbeddingPlan,
15522    streams: usize,
15523    hidden: usize,
15524) -> Res<PleW> {
15525    let embed_dim = ple_plan.embed_dim as usize;
15526    let key_proj = expect(weights, &family_id(format!("{prefix}ple.key_proj.weight")))?;
15527    let conv_w = expect(weights, &family_id(format!("{prefix}ple.conv1d.weight")))?;
15528    let norm_slices = |name: &str| -> Res<Vec<CudaSlice<f32>>> {
15529        let t = expect(weights, &family_id(format!("{prefix}ple.{name}.weight")))?;
15530        split_rows(&t.data, streams, hidden, 1)
15531            .into_iter()
15532            .map(|v| e.htod(&v))
15533            .collect::<Result<_, _>>()
15534            .map_err(Into::into)
15535    };
15536    let ints = |name: &str| -> Res<Vec<i64>> {
15537        let t = expect(
15538            weights,
15539            &family_id(format!("{prefix}ple.ple_embedding.{name}")),
15540        )?;
15541        t.ints
15542            .clone()
15543            .ok_or_else(|| "qwen4exp_gpu: n-gram buffer must be I64".into())
15544    };
15545    Ok(PleW {
15546        plan: *ple_plan,
15547        key_proj: split_rows(&key_proj.data, streams, hidden, embed_dim)
15548            .into_iter()
15549            .map(|v| e.htod(&v))
15550            .collect::<Result<_, _>>()?,
15551        value_proj: upload(
15552            e,
15553            &expect(
15554                weights,
15555                &family_id(format!("{prefix}ple.value_proj.weight")),
15556            )?,
15557        )?,
15558        norm_key: norm_slices("norm_key")?,
15559        norm_query: norm_slices("norm_query")?,
15560        norm_conv: norm_slices("norm_conv")?,
15561        conv_w: split_rows(&conv_w.data, streams, hidden, ple_plan.conv_kernel as usize)
15562            .into_iter()
15563            .map(|v| e.htod(&v))
15564            .collect::<Result<_, _>>()?,
15565        multipliers: ints("layer_multipliers")?,
15566        sizes: ints("ngram_heads_vocab_sizes")?,
15567        offsets: ints("ngram_heads_offsets")?,
15568        table: NgramTable::F32(Vec::new()), // never gathered; the model's table is passed in
15569    })
15570}
15571
15572/// Build one card's compact GDN half from host weights.
15573#[allow(clippy::too_many_arguments)]
15574fn build_gdn_half(
15575    e: &Engine,
15576    weights: &ReferenceWeights,
15577    index: u32,
15578    gdn: &GatedDeltaNetPlan,
15579    hidden: usize,
15580    d: usize,
15581) -> Res<GdnHalfW> {
15582    let (nk, nv) = (gdn.key_heads as usize, gdn.value_heads as usize);
15583    let (hk, hv) = (gdn.key_head_dim as usize, gdn.value_head_dim as usize);
15584    if nk % 2 != 0 || nv % nk != 0 {
15585        return Err(format!(
15586            "qwen4exp_gpu tp2: GDN layer {index} nk {nk} / nv {nv} does not split by key-head halves"
15587        )
15588        .into());
15589    }
15590    let (nk_h, nv_h) = (nk / 2, nv / 2);
15591    let head_map = tp2_gdn_head_map(d, nk, nv);
15592    let qkv = expect(weights, &layer_id(index, LayerTensor::GdnQkv))?;
15593    let z = expect(weights, &layer_id(index, LayerTensor::GdnGate))?;
15594    let beta = expect(weights, &layer_id(index, LayerTensor::GdnBeta))?;
15595    let alpha = expect(weights, &layer_id(index, LayerTensor::GdnAlpha))?;
15596    let out = expect(weights, &layer_id(index, LayerTensor::GdnOutput))?;
15597    let conv_w = expect(weights, &layer_id(index, LayerTensor::GdnConv1d))?;
15598    let a = expect(weights, &layer_id(index, LayerTensor::GdnA))?;
15599    let dt = expect(weights, &layer_id(index, LayerTensor::GdnDtBias))?;
15600    let norm = expect(weights, &layer_id(index, LayerTensor::GdnNorm))?;
15601    let kernel = gdn.conv_kernel as usize;
15602    // Row lists for the fused qkv/conv (q block, k block, v per compact head).
15603    let mut qkv_rows: Vec<usize> = Vec::with_capacity(2 * nk_h * hk + nv_h * hv);
15604    qkv_rows.extend(d * nk_h * hk..(d + 1) * nk_h * hk);
15605    qkv_rows.extend(nk * hk + d * nk_h * hk..nk * hk + (d + 1) * nk_h * hk);
15606    for &hm in &head_map {
15607        qkv_rows.extend(2 * nk * hk + hm * hv..2 * nk * hk + (hm + 1) * hv);
15608    }
15609    let mut z_rows: Vec<usize> = Vec::with_capacity(nv_h * hv);
15610    for &hm in &head_map {
15611        z_rows.extend(hm * hv..(hm + 1) * hv);
15612    }
15613    let out_blocks: Vec<(usize, usize)> = head_map.iter().map(|&hm| (hm * hv, hv)).collect();
15614    let qkv_c = gather_rows_host(&qkv.data, hidden, &qkv_rows);
15615    let z_c = gather_rows_host(&z.data, hidden, &z_rows);
15616    let beta_c = gather_rows_host(&beta.data, hidden, &head_map);
15617    let alpha_c = gather_rows_host(&alpha.data, hidden, &head_map);
15618    let out_c = gather_cols_host(&out.data, hidden, nv * hv, &out_blocks);
15619    let conv_c = gather_rows_host(&conv_w.data, kernel, &qkv_rows);
15620    let a_c: Vec<f32> = head_map.iter().map(|&hm| a.data[hm]).collect();
15621    let dt_c: Vec<f32> = head_map.iter().map(|&hm| dt.data[hm]).collect();
15622    Ok(GdnHalfW {
15623        nk_h,
15624        nv_h,
15625        hk,
15626        hv,
15627        kernel,
15628        gate_activation: gdn.gate_activation,
15629        proj_b16: need_stack_twin(
15630            e,
15631            &[&qkv_c, &z_c, &beta_c, &alpha_c],
15632            hidden,
15633            "tp2 gdn proj half",
15634        )?,
15635        out_b16: need_twin(e, &out_c, nv_h * hv, "tp2 gdn out half")?,
15636        conv_w: e.htod(&conv_c)?,
15637        a: e.htod(&a_c)?,
15638        dt: e.htod(&dt_c)?,
15639        norm: e.htod(&norm.data)?,
15640    })
15641}
15642
15643/// Build one card's QSA half from host weights (query heads d*nh_h.., KV heads d*nkv_h..).
15644#[allow(clippy::too_many_arguments)]
15645fn build_qsa_half(
15646    e: &Engine,
15647    weights: &ReferenceWeights,
15648    index: u32,
15649    attn: &FullAttentionPlan,
15650    hidden: usize,
15651    d: usize,
15652) -> Res<QsaHalfW> {
15653    let nh = attn.query_heads as usize;
15654    let nkv = attn.kv_heads as usize;
15655    let hd = attn.key_head_dim as usize;
15656    if nh % 2 != 0 || nkv % 2 != 0 || nh % nkv != 0 {
15657        return Err(format!(
15658            "qwen4exp_gpu tp2: QSA layer {index} heads {nh}/{nkv} do not split in halves"
15659        )
15660        .into());
15661    }
15662    let (nh_h, nkv_h) = (nh / 2, nkv / 2);
15663    let wq = expect(weights, &layer_id(index, LayerTensor::Query))?;
15664    let wk = expect(weights, &layer_id(index, LayerTensor::Key))?;
15665    let wv = expect(weights, &layer_id(index, LayerTensor::Value))?;
15666    let wo = expect(weights, &layer_id(index, LayerTensor::AttentionOutput))?;
15667    // Fused [q|gate] per head: card d's heads are a contiguous row block.
15668    let q_rows: Vec<usize> = (d * nh_h * 2 * hd..(d + 1) * nh_h * 2 * hd).collect();
15669    let kv_rows: Vec<usize> = (d * nkv_h * hd..(d + 1) * nkv_h * hd).collect();
15670    let wq_c = gather_rows_host(&wq.data, hidden, &q_rows);
15671    let wk_c = gather_rows_host(&wk.data, hidden, &kv_rows);
15672    let wv_c = gather_rows_host(&wv.data, hidden, &kv_rows);
15673    let wo_c = gather_cols_host(&wo.data, hidden, nh * hd, &[(d * nh_h * hd, nh_h * hd)]);
15674    let opt_norm = |tensor: LayerTensor| -> Res<Option<CudaSlice<f32>>> {
15675        match weights.get(&layer_id(index, tensor)) {
15676            Some(t) => Ok(Some(e.htod(&t.data)?)),
15677            None => Ok(None),
15678        }
15679    };
15680    let scale = match attn.scale {
15681        memra_gguf::model_plan::AttentionScale::InverseSqrtKeyDim => 1.0 / (hd as f32).sqrt(),
15682        memra_gguf::model_plan::AttentionScale::Fixed(scale) => scale,
15683    };
15684    Ok(QsaHalfW {
15685        nh_h,
15686        nkv_h,
15687        hd,
15688        n_rot: attn.rope.dimensions as usize,
15689        rope_base: attn.rope.base,
15690        scale,
15691        proj_b16: need_stack_twin(e, &[&wq_c, &wk_c, &wv_c], hidden, "tp2 qsa proj half")?,
15692        wo_b16: need_twin(e, &wo_c, nh_h * hd, "tp2 qsa o half")?,
15693        q_norm: opt_norm(LayerTensor::QueryNorm)?,
15694        k_norm: opt_norm(LayerTensor::KeyNorm)?,
15695        // Device table on THIS half's card; the width check ran at single-card load.
15696        yarn: build_yarn(e, &attn.rope, None, index)?,
15697    })
15698}
15699
15700/// Build the TP2 shard from a loaded checkpoint (host data), before the single-card
15701/// model consumes it. Card 0 gets its compact split copies on `e0`; card 1 gets its
15702/// replicas + halves on `e1`.
15703pub fn build_tp2_shard(e0: &Engine, e1: &Engine, ckpt: &LoadedCheckpoint) -> Res<Tp2Shard> {
15704    let plan = &ckpt.plan;
15705    let weights = &ckpt.weights;
15706    let hidden = plan.hidden_size as usize;
15707    let vocab = plan.vocab_size as usize;
15708    if vocab % 2 != 0 {
15709        return Err("qwen4exp_gpu tp2: odd vocab".into());
15710    }
15711    let mixer_plan = plan
15712        .exit_mixer
15713        .ok_or("qwen4exp_gpu tp2: missing exit mixer")?;
15714    let streams = mixer_plan.streams as usize;
15715    let rank = mixer_plan.bottleneck_rank as usize;
15716    // Expert placement, read ONCE per shard build (MEMRA_Q4E_EP_MAP; unset = the even
15717    // split control arm). Refusals are load-time, before a single byte is uploaded.
15718    let plan_experts = plan
15719        .layers
15720        .iter()
15721        .find_map(|l| match &l.mlp {
15722            MlpPlan::Moe(m) => Some(m.expert_count as usize),
15723            _ => None,
15724        })
15725        .ok_or("qwen4exp_gpu tp2: no MoE layer in the plan")?;
15726    let placement = match Tp2Placement::from_env(plan_experts)? {
15727        Some(p) => p,
15728        None => Tp2Placement::even(plan_experts),
15729    };
15730    println!(
15731        "# tp2-placement\tstrategy={}\tentry_rank={}\texperts={plan_experts}\tsource={}",
15732        placement.strategy(),
15733        placement.entry_rank(),
15734        placement.source()
15735    );
15736    let mut layers = Vec::with_capacity(plan.layers.len());
15737    for layer in &plan.layers {
15738        let prefix = format!("trunk.layers.{}.", layer.index);
15739        let _g1 = e1.gpu.enter_main()?;
15740        let attn_gate1 = load_gate(
15741            e1,
15742            weights,
15743            &prefix,
15744            "attn_hyper_connection.",
15745            streams,
15746            hidden,
15747            rank,
15748            true,
15749        )?;
15750        let mlp_gate1 = load_gate(
15751            e1,
15752            weights,
15753            &prefix,
15754            "mlp_hyper_connection.",
15755            streams,
15756            hidden,
15757            rank,
15758            true,
15759        )?;
15760        let ple1 = match layer.ple.as_ref() {
15761            None => None,
15762            Some(ple_plan) => Some(build_ple_replica(
15763                e1, weights, &prefix, ple_plan, streams, hidden,
15764            )?),
15765        };
15766        drop(_g1);
15767        let (mixer0, mixer1) = match &layer.attention {
15768            AttentionPlan::GatedDeltaNet(gdn) => {
15769                let _g0 = e0.gpu.enter_main()?;
15770                let m0 = MixerHalfW::Gdn(build_gdn_half(e0, weights, layer.index, gdn, hidden, 0)?);
15771                drop(_g0);
15772                let _g1 = e1.gpu.enter_main()?;
15773                let m1 = MixerHalfW::Gdn(build_gdn_half(e1, weights, layer.index, gdn, hidden, 1)?);
15774                (m0, m1)
15775            }
15776            AttentionPlan::Full(attn) => {
15777                let _g0 = e0.gpu.enter_main()?;
15778                let m0 =
15779                    MixerHalfW::Qsa(build_qsa_half(e0, weights, layer.index, attn, hidden, 0)?);
15780                drop(_g0);
15781                let _g1 = e1.gpu.enter_main()?;
15782                let m1 =
15783                    MixerHalfW::Qsa(build_qsa_half(e1, weights, layer.index, attn, hidden, 1)?);
15784                (m0, m1)
15785            }
15786            other => {
15787                return Err(format!("qwen4exp_gpu tp2: unsupported mixer {other:?}").into());
15788            }
15789        };
15790        // MoE: card1 bank halves from the HOST bank sources; NVFP4 required.
15791        let MlpPlan::Moe(moe_plan) = &layer.mlp else {
15792            return Err("qwen4exp_gpu tp2: non-MoE layer".into());
15793        };
15794        let experts = moe_plan.expert_count as usize;
15795        let ff = moe_plan.expert_intermediate_size as usize;
15796        if experts % 2 != 0 {
15797            return Err("qwen4exp_gpu tp2: odd expert count".into());
15798        }
15799        let bank = ckpt
15800            .banks
15801            .get(&layer.index)
15802            .ok_or("qwen4exp_gpu tp2: missing bank source")?;
15803        // The layer's expert placement, resolved ONCE here and carried on the shard so
15804        // the route split at decode/prefill cannot disagree with what was uploaded.
15805        let place = placement.layer(layer.index, experts)?;
15806        // Card 1's bank is a GATHER of the placed expert rows in local-slot order, not a
15807        // contiguous suffix slice. For the even control arm `card1` is exactly
15808        // `e_half..experts` ascending, so the gather concatenates the same bytes the old
15809        // slice handed over, in the same order — bit-identical by construction, which is
15810        // what makes "even split = control arm" a statement about bytes and not a hope.
15811        let upper =
15812            |src: &BankTensorSrc, out_f: usize, in_f: usize, what: &str| -> Res<Nvfp4Half> {
15813                let BankTensorSrc::Nvfp4 {
15814                    codes,
15815                    scales,
15816                    macros,
15817                    ..
15818                } = src
15819                else {
15820                    return Err(format!("qwen4exp_gpu tp2: {what} bank is not NVFP4").into());
15821                };
15822                let wbytes = out_f * in_f / 2;
15823                let sbytes = out_f * in_f / 16;
15824                let need_codes = place.card1.len() * wbytes;
15825                let need_scales = place.card1.len() * sbytes;
15826                if codes.len() < experts * wbytes || scales.len() < experts * sbytes {
15827                    return Err(format!(
15828                        "qwen4exp_gpu tp2: {what} bank is {} code / {} scale bytes, too \
15829                         small for {experts} experts x ({wbytes}, {sbytes})",
15830                        codes.len(),
15831                        scales.len()
15832                    )
15833                    .into());
15834                }
15835                let mut gcodes = Vec::with_capacity(need_codes);
15836                let mut gscales = Vec::with_capacity(need_scales);
15837                let mut gmacros = Vec::with_capacity(place.card1.len());
15838                for &eid in &place.card1 {
15839                    let e = eid as usize;
15840                    gcodes.extend_from_slice(&codes[e * wbytes..(e + 1) * wbytes]);
15841                    gscales.extend_from_slice(&scales[e * sbytes..(e + 1) * sbytes]);
15842                    gmacros.push(macros[e]);
15843                }
15844                Ok(Nvfp4Half {
15845                    codes: e1.htod_bytes(&gcodes)?,
15846                    scales: e1.htod_bytes(&gscales)?,
15847                    macros_dev: e1.htod(&gmacros)?,
15848                })
15849            };
15850        let shared = moe_plan
15851            .shared
15852            .as_ref()
15853            .ok_or("qwen4exp_gpu tp2: missing shared expert")?;
15854        let sff = shared.intermediate_size as usize;
15855        if sff % 2 != 0 {
15856            return Err("qwen4exp_gpu tp2: odd shared ff".into());
15857        }
15858        let sffh = sff / 2;
15859        let sh_gate = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpGate))?;
15860        let sh_up = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpUp))?;
15861        let sh_down = expect(weights, &layer_id(layer.index, LayerTensor::SharedMlpDown))?;
15862        let sh_ig = if shared.gated {
15863            Some(expect(
15864                weights,
15865                &layer_id(layer.index, LayerTensor::SharedMlpInputGate),
15866            )?)
15867        } else {
15868            None
15869        };
15870        let moe = {
15871            let _g1 = e1.gpu.enter_main()?;
15872            let gate1 = upper(&bank.gate, ff, hidden, "gate")?;
15873            let up1 = upper(&bank.up, ff, hidden, "up")?;
15874            let down1 = upper(&bank.down, hidden, ff, "down")?;
15875            let shared_gu1_b16 = need_stack_twin(
15876                e1,
15877                &[&sh_gate.data[sffh * hidden..], &sh_up.data[sffh * hidden..]],
15878                hidden,
15879                "tp2 shared gate/up (card1)",
15880            )?;
15881            let down1_c = gather_cols_host(&sh_down.data, hidden, sff, &[(sffh, sffh)]);
15882            let shared_down1 = need_twin(e1, &down1_c, sffh, "tp2 shared down (card1)")?;
15883            let shared_input_gate1 = match sh_ig.as_ref() {
15884                Some(t) => Some(e1.htod(&t.data)?),
15885                None => None,
15886            };
15887            drop(_g1);
15888            let _g0 = e0.gpu.enter_main()?;
15889            let down0_c = gather_cols_host(&sh_down.data, hidden, sff, &[(0, sffh)]);
15890            let shared_down0 = need_twin(e0, &down0_c, sffh, "tp2 shared down (card0)")?;
15891            let shared_gu0_b16 = need_stack_twin(
15892                e0,
15893                &[&sh_gate.data[..sffh * hidden], &sh_up.data[..sffh * hidden]],
15894                hidden,
15895                "tp2 shared gate/up (card0)",
15896            )?;
15897            MoeHalfW {
15898                gate1,
15899                up1,
15900                down1,
15901                shared_down0,
15902                shared_down1,
15903                shared_input_gate1,
15904                shared_gu0_b16,
15905                shared_gu1_b16,
15906            }
15907        };
15908        layers.push(Tp2LayerW {
15909            attn_gate1,
15910            mlp_gate1,
15911            mixer0,
15912            mixer1,
15913            moe,
15914            ple1,
15915            place,
15916        });
15917    }
15918    let _g1 = e1.gpu.enter_main()?;
15919    let exit_gate1 = load_gate(
15920        e1,
15921        weights,
15922        "trunk.hyper_connection_mixer.",
15923        "",
15924        streams,
15925        hidden,
15926        rank,
15927        false,
15928    )?;
15929    let vsplit = vocab / 2;
15930    let head = match weights.get(&TensorId::OutputProjection) {
15931        Some(t) => &t.data,
15932        None => &expect(weights, &TensorId::TokenEmbedding)?.data.clone(),
15933    };
15934    let lm_head1 = need_twin(
15935        e1,
15936        &head[vsplit * hidden..],
15937        hidden,
15938        "tp2 lm_head upper half",
15939    )?;
15940    let stage1 = [e1.zeros(hidden)?, e1.zeros(hidden)?];
15941    let ev1 = [e1.ctx().new_event(None)?, e1.ctx().new_event(None)?];
15942    let stage1_raw = {
15943        let s = e1.gpu.stream();
15944        [
15945            stage1[0].device_ptr(&s).0 as u64,
15946            stage1[1].device_ptr(&s).0 as u64,
15947        ]
15948    };
15949    drop(_g1);
15950    let _g0 = e0.gpu.enter_main()?;
15951    let stage0 = [e0.zeros(hidden)?, e0.zeros(hidden)?];
15952    let ev0 = [e0.ctx().new_event(None)?, e0.ctx().new_event(None)?];
15953    let stage0_raw = {
15954        let s = e0.gpu.stream();
15955        [
15956            stage0[0].device_ptr(&s).0 as u64,
15957            stage0[1].device_ptr(&s).0 as u64,
15958        ]
15959    };
15960    Ok(Tp2Shard {
15961        layers,
15962        exit_gate1,
15963        lm_head1,
15964        vsplit,
15965        stage0,
15966        stage1,
15967        stage0_raw,
15968        stage1_raw,
15969        ev0,
15970        ev1,
15971    })
15972}
15973
15974impl Qwen4ExpGpu {
15975    /// Load a checkpoint dir for TP2: P2P is enabled, the shard is built from the host
15976    /// checkpoint data (before the single-card model consumes it), then the single-card
15977    /// model loads onto `e0` exactly as `load_from_dir_with`.
15978    pub fn load_from_dir_tp2(
15979        e0: &Engine,
15980        e1: &Engine,
15981        dir: &std::path::Path,
15982        opts: LoadOptions,
15983    ) -> Res<(Self, Tp2Shard)> {
15984        tp2_enable_p2p(e0, e1)?;
15985        let checkpoint = read_checkpoint_with(dir, opts)?;
15986        let shard = build_tp2_shard(e0, e1, &checkpoint)?;
15987        let model = Self::from_loaded_checkpoint(e0, checkpoint)?;
15988        Ok((model, shard))
15989    }
15990
15991    /// One-time single-card -> TP2 half-state migration (host bounce; the state is
15992    /// TP2-latched afterwards). Card 0 keeps the host-side indexer raw-key cache and
15993    /// the single-card PLE history (replicated path); mixer device state splits.
15994    fn tp2_migrate(
15995        &self,
15996        e0: &Engine,
15997        e1: &Engine,
15998        _shard: &Tp2Shard,
15999        state: &mut Qwen4ExpState,
16000    ) -> Res<()> {
16001        let cap = state.capacity;
16002        let pos = state.pos;
16003        let mut tlayers = Vec::with_capacity(self.layers.len());
16004        for (layer, lstate) in self.layers.iter().zip(state.layers.iter_mut()) {
16005            let (m0, m1) = match (&layer.mixer, &mut lstate.mixer) {
16006                (
16007                    MixerW::Gdn(gdn),
16008                    MixerState::Gdn {
16009                        conv,
16010                        state: gstate,
16011                    },
16012                ) => {
16013                    let p = &gdn.plan;
16014                    let (nk, nv) = (p.key_heads as usize, p.value_heads as usize);
16015                    let (hk, hv) = (p.key_head_dim as usize, p.value_head_dim as usize);
16016                    let (nk_h, nv_h) = (nk / 2, nv / 2);
16017                    let pad = p.conv_kernel as usize - 1;
16018                    let conv_dim = 2 * nk * hk + nv * hv;
16019                    let conv_dim_h = 2 * nk_h * hk + nv_h * hv;
16020                    let state_host = {
16021                        let _g = e0.gpu.enter_main()?;
16022                        e0.dtoh(gstate)?
16023                    };
16024                    let conv_host = {
16025                        let _g = e0.gpu.enter_main()?;
16026                        e0.dtoh(conv)?
16027                    };
16028                    let mut halves = Vec::with_capacity(2);
16029                    for d in 0..2 {
16030                        let head_map = tp2_gdn_head_map(d, nk, nv);
16031                        let state_c = gather_rows_host(&state_host, hv * hk, &head_map);
16032                        let mut blocks: Vec<(usize, usize)> = vec![
16033                            (d * nk_h * hk, nk_h * hk),
16034                            (nk * hk + d * nk_h * hk, nk_h * hk),
16035                        ];
16036                        blocks.extend(head_map.iter().map(|&hm| (2 * nk * hk + hm * hv, hv)));
16037                        let conv_c = gather_cols_host(&conv_host, pad, conv_dim, &blocks);
16038                        let e = if d == 0 { e0 } else { e1 };
16039                        let _g = e.gpu.enter_main()?;
16040                        let state_dev = e.htod(&state_c)?;
16041                        let conv_dev = e.htod(&conv_c)?;
16042                        debug_assert_eq!(conv_c.len(), pad * conv_dim_h);
16043                        halves.push(MixerHalfState::Gdn {
16044                            conv: conv_dev,
16045                            state: state_dev,
16046                        });
16047                    }
16048                    let m1 = halves.pop().expect("two halves");
16049                    let m0 = halves.pop().expect("two halves");
16050                    (m0, m1)
16051                }
16052                (MixerW::Qsa(qsa), MixerState::Qsa { kv, .. }) => {
16053                    let nkv = qsa.attn.kv_heads as usize;
16054                    let hd = qsa.attn.key_head_dim as usize;
16055                    let nkv_h = nkv / 2;
16056                    let mut halves = Vec::with_capacity(2);
16057                    match &*kv {
16058                        QsaKvStore::F32 { k, v } => {
16059                            let (k_host, v_host) = {
16060                                let _g = e0.gpu.enter_main()?;
16061                                (
16062                                    e0.dtoh_view(&k.slice(0..pos * nkv * hd))?,
16063                                    e0.dtoh_view(&v.slice(0..pos * nkv * hd))?,
16064                                )
16065                            };
16066                            for d in 0..2 {
16067                                let block = [(d * nkv_h * hd, nkv_h * hd)];
16068                                let k_c = gather_cols_host(&k_host, pos, nkv * hd, &block);
16069                                let v_c = gather_cols_host(&v_host, pos, nkv * hd, &block);
16070                                let e = if d == 0 { e0 } else { e1 };
16071                                let _g = e.gpu.enter_main()?;
16072                                let mut k_dev = e.zeros(cap * nkv_h * hd)?;
16073                                let mut v_dev = e.zeros(cap * nkv_h * hd)?;
16074                                if pos > 0 {
16075                                    let mut kv_view = k_dev.slice_mut(0..pos * nkv_h * hd);
16076                                    e.gpu.stream().memcpy_htod(&k_c, &mut kv_view)?;
16077                                    let mut vv_view = v_dev.slice_mut(0..pos * nkv_h * hd);
16078                                    e.gpu.stream().memcpy_htod(&v_c, &mut vv_view)?;
16079                                }
16080                                halves.push(MixerHalfState::Qsa {
16081                                    kv: QsaKvStore::F32 { k: k_dev, v: v_dev },
16082                                });
16083                            }
16084                        }
16085                        QsaKvStore::Q8Q5 { k, v } => {
16086                            // Quantized halves: each head's hd elems are whole q8/q5
16087                            // 32-blocks (hd % 32 == 0 on real geometry), so the half
16088                            // rows gather BYTES verbatim — no dequant, no requant, the
16089                            // half caches are bit-slices of the single-card cache.
16090                            if hd % 32 != 0 {
16091                                return Err("qwen4exp_gpu tp2: quantized halves need \
16092                                            hd % 32 == 0 (byte-aligned head blocks)"
16093                                    .into());
16094                            }
16095                            let (krb, vrb) = (q8_row_bytes(nkv * hd), q5_row_bytes(nkv * hd));
16096                            let (krb_h, vrb_h) =
16097                                (q8_row_bytes(nkv_h * hd), q5_row_bytes(nkv_h * hd));
16098                            let (k_host, v_host) = {
16099                                let _g = e0.gpu.enter_main()?;
16100                                (
16101                                    e0.dtoh_u8_view(&k.slice(0..pos * krb))?,
16102                                    e0.dtoh_u8_view(&v.slice(0..pos * vrb))?,
16103                                )
16104                            };
16105                            for d in 0..2 {
16106                                let mut k_c = Vec::with_capacity(pos * krb_h);
16107                                let mut v_c = Vec::with_capacity(pos * vrb_h);
16108                                for r in 0..pos {
16109                                    let ko = r * krb + d * krb_h;
16110                                    k_c.extend_from_slice(&k_host[ko..ko + krb_h]);
16111                                    let vo = r * vrb + d * vrb_h;
16112                                    v_c.extend_from_slice(&v_host[vo..vo + vrb_h]);
16113                                }
16114                                let e = if d == 0 { e0 } else { e1 };
16115                                let _g = e.gpu.enter_main()?;
16116                                let mut k_dev = e.alloc_u8(cap * krb_h)?;
16117                                let mut v_dev = e.alloc_u8(cap * vrb_h)?;
16118                                if pos > 0 {
16119                                    let mut kv_view = k_dev.slice_mut(0..pos * krb_h);
16120                                    e.gpu.stream().memcpy_htod(&k_c, &mut kv_view)?;
16121                                    let mut vv_view = v_dev.slice_mut(0..pos * vrb_h);
16122                                    e.gpu.stream().memcpy_htod(&v_c, &mut vv_view)?;
16123                                }
16124                                halves.push(MixerHalfState::Qsa {
16125                                    kv: QsaKvStore::Q8Q5 { k: k_dev, v: v_dev },
16126                                });
16127                            }
16128                        }
16129                    }
16130                    // The single-card cache is DEAD after migration (a TP2-touched
16131                    // state refuses single-card forwards), and at long-context
16132                    // capacities it is the largest allocation on card 0 — stub it.
16133                    {
16134                        let _g = e0.gpu.enter_main()?;
16135                        *kv = match &*kv {
16136                            QsaKvStore::F32 { .. } => QsaKvStore::F32 {
16137                                k: e0.zeros(1)?,
16138                                v: e0.zeros(1)?,
16139                            },
16140                            QsaKvStore::Q8Q5 { .. } => QsaKvStore::Q8Q5 {
16141                                k: e0.alloc_u8(34)?,
16142                                v: e0.alloc_u8(24)?,
16143                            },
16144                        };
16145                    }
16146                    let m1 = halves.pop().expect("two halves");
16147                    let m0 = halves.pop().expect("two halves");
16148                    (m0, m1)
16149                }
16150                _ => return Err("qwen4exp_gpu tp2: layer/state mixer mismatch".into()),
16151            };
16152            // Card-1 PLE history replica (replicated path): copy card0's normed-conv rows.
16153            let ple1 = match lstate.ple.as_ref() {
16154                None => None,
16155                Some(ps) => {
16156                    let mut conv_hist = Vec::with_capacity(ps.conv_hist.len());
16157                    for h in &ps.conv_hist {
16158                        let host = {
16159                            let _g = e0.gpu.enter_main()?;
16160                            e0.dtoh(h)?
16161                        };
16162                        let _g = e1.gpu.enter_main()?;
16163                        conv_hist.push(e1.htod(&host)?);
16164                    }
16165                    Some(PleState {
16166                        conv_hist,
16167                        ngram_ids: Vec::new(),
16168                        ngram_history: Vec::new(),
16169                        ngram_last_eos: -1,
16170                    })
16171                }
16172            };
16173            tlayers.push(Tp2LayerState { m0, m1, ple1 });
16174        }
16175        state.tp2 = Some(Tp2State {
16176            ws1: StepPool::default(),
16177            layers: tlayers,
16178            graphs: Tp2Graphs::default(),
16179            pf_stage0: None,
16180            pf_stage1: None,
16181            pf_stage0_raw: [0; 2],
16182            pf_stage1_raw: [0; 2],
16183            pf_rows: 0,
16184        });
16185        Ok(())
16186    }
16187
16188    /// Per-card GDN split half (t-generic — TP2 prefill runs chunk-sized t):
16189    /// projections, conv, scan, norm+gate, and the compact out-projection PARTIAL
16190    /// (joined by the driver). Mirrors `gdn_forward`.
16191    #[allow(clippy::too_many_arguments)]
16192    fn gdn_forward_half(
16193        &self,
16194        e: &Engine,
16195        ws: &mut StepPool,
16196        eps: f32,
16197        h: &GdnHalfW,
16198        mixed: &CudaSlice<f32>,
16199        hstate: &mut MixerHalfState,
16200        t: usize,
16201    ) -> Res<CudaSlice<f32>> {
16202        let MixerHalfState::Gdn { conv, state } = hstate else {
16203            return Err("qwen4exp_gpu tp2: GDN half bound to non-GDN state".into());
16204        };
16205        let hidden = self.hidden;
16206        let (nk, nv, hk, hv) = (h.nk_h, h.nv_h, h.hk, h.hv);
16207        let kernel = h.kernel;
16208        let pad = kernel - 1;
16209        let conv_dim = 2 * nk * hk + nv * hv;
16210        let mut qkv = ws.take_f32(e, "gdn.qkv", t * conv_dim, 0)?;
16211        let mut z = ws.take_f32(e, "gdn.z", t * nv * hv, 0)?;
16212        let mut beta_raw = ws.take_f32(e, "gdn.beta", t * nv, 0)?;
16213        let mut alpha = ws.take_f32(e, "gdn.alpha", t * nv, 0)?;
16214        // Proj stack (round 4): the 4 half projections in ONE launch (bit-identical
16215        // rows; OFF arm = row-offset views of the same required stack). t == 1 only
16216        // (decode form); chunks run the per-mat row-offset launches.
16217        if t == 1 && proj_stack_on() {
16218            launch_qmatvec_bf16w_multi4(
16219                e,
16220                &h.proj_b16,
16221                mixed,
16222                &[
16223                    (&qkv, conv_dim),
16224                    (&z, nv * hv),
16225                    (&beta_raw, nv),
16226                    (&alpha, nv),
16227                ],
16228                hidden,
16229            )?;
16230        } else {
16231            launch_qmatvec_bf16w_off(e, &h.proj_b16, 0, mixed, &mut qkv, hidden, conv_dim, t)?;
16232            launch_qmatvec_bf16w_off(e, &h.proj_b16, conv_dim, mixed, &mut z, hidden, nv * hv, t)?;
16233            launch_qmatvec_bf16w_off(
16234                e,
16235                &h.proj_b16,
16236                conv_dim + nv * hv,
16237                mixed,
16238                &mut beta_raw,
16239                hidden,
16240                nv,
16241                t,
16242            )?;
16243            launch_qmatvec_bf16w_off(
16244                e,
16245                &h.proj_b16,
16246                conv_dim + nv * hv + nv,
16247                mixed,
16248                &mut alpha,
16249                hidden,
16250                nv,
16251                t,
16252            )?;
16253        }
16254        let mut g_log = ws.take_f32(e, "gdn.glog", t * nv, 0)?;
16255        e.gdn_glog_v(&alpha.slice(0..t * nv), &h.dt, &h.a, &mut g_log, nv, t)?;
16256        ws.put_f32("gdn.alpha", alpha);
16257        let mut conv_out = ws.take_f32(e, "gdn.conv_out", t * conv_dim, 0)?;
16258        launch_dwconv(
16259            e,
16260            &qkv,
16261            conv,
16262            &h.conv_w,
16263            &mut conv_out,
16264            t,
16265            pad,
16266            conv_dim,
16267            kernel,
16268            1,
16269            1,
16270        )?;
16271        let mut o = ws.take_f32(e, "gdn.o", t * nv * hv, 0)?;
16272        let scale = 1.0 / (hk as f32).sqrt();
16273        if t == 1 && gdn_step_on() && hk % 32 == 0 && hk <= 1024 {
16274            launch_gdn_scan_step(
16275                e, &conv_out, &g_log, &beta_raw, state, &mut o, nk, nv, hk, hv, scale, eps,
16276            )?;
16277        } else {
16278            launch_gdn_scan(
16279                e, &conv_out, &g_log, &beta_raw, state, &mut o, nk, nv, hk, hv, t, scale, eps,
16280            )?;
16281        }
16282        ws.put_f32("gdn.conv_out", conv_out);
16283        // conv history <- last `pad` raw qkv rows (zeros keep their place when t < pad).
16284        if t >= pad {
16285            e.copy_range_into(conv, 0, &qkv, (t - pad) * conv_dim, pad * conv_dim)?;
16286        } else {
16287            let keep = pad - t;
16288            let mut tmp = ws.take_f32(e, "gdn.tmp", keep * conv_dim, 0)?;
16289            e.copy_range_into(&mut tmp, 0, conv, t * conv_dim, keep * conv_dim)?;
16290            e.copy_range_into(conv, 0, &tmp, 0, keep * conv_dim)?;
16291            e.copy_range_into(conv, keep * conv_dim, &qkv, 0, t * conv_dim)?;
16292            ws.put_f32("gdn.tmp", tmp);
16293        }
16294        ws.put_f32("gdn.qkv", qkv);
16295        ws.put_f32("gdn.beta", beta_raw);
16296        ws.put_f32("gdn.glog", g_log);
16297        let mut gated = ws.take_f32(e, "gdn.gated", t * nv * hv, 0)?;
16298        match h.gate_activation {
16299            GdnGateActivation::Sigmoid if gdn_fuse_on() => {
16300                launch_rms_sigmul(e, &o, &h.norm, &z, &mut gated, hv, t * nv, eps)?;
16301            }
16302            GdnGateActivation::Sigmoid => {
16303                let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
16304                e.rms_norm(&o, &h.norm, &mut normed, hv, t * nv, eps)?;
16305                let mut sg = ws.take_f32(e, "gdn.sg", t * nv * hv, 0)?;
16306                e.sigmoid(&z, &mut sg, t * nv * hv)?;
16307                e.mul(&normed, &sg, &mut gated, t * nv * hv)?;
16308                ws.put_f32("gdn.sg", sg);
16309                ws.put_f32("gdn.normed", normed);
16310            }
16311            GdnGateActivation::Silu => {
16312                let mut normed = ws.take_f32(e, "gdn.normed", t * nv * hv, 0)?;
16313                e.rms_norm(&o, &h.norm, &mut normed, hv, t * nv, eps)?;
16314                e.silu_mul(&z, &normed, &mut gated, t * nv * hv)?;
16315                ws.put_f32("gdn.normed", normed);
16316            }
16317        }
16318        let mut partial = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
16319        launch_qmatvec_bf16w(
16320            e,
16321            &h.out_b16,
16322            &gated,
16323            &mut partial,
16324            nv * hv,
16325            hidden,
16326            t,
16327            1,
16328            0,
16329            0,
16330            nv * hv,
16331            0,
16332        )?;
16333        ws.put_f32("gdn.gated", gated);
16334        ws.put_f32("gdn.z", z);
16335        ws.put_f32("gdn.o", o);
16336        Ok(partial)
16337    }
16338
16339    /// Per-card QSA split half UP TO the cache append (t-generic — TP2 prefill runs
16340    /// chunk-sized t); returns (q, gate) for the post-selection half
16341    /// (`qsa_half_attend`). The indexer selection is built once on card 0.
16342    #[allow(clippy::too_many_arguments)]
16343    fn qsa_half_proj(
16344        &self,
16345        e: &Engine,
16346        ws: &mut StepPool,
16347        eps: f32,
16348        h: &QsaHalfW,
16349        mixed: &CudaSlice<f32>,
16350        hstate: &mut MixerHalfState,
16351        base_pos: usize,
16352        t: usize,
16353    ) -> Res<(CudaSlice<f32>, CudaSlice<f32>)> {
16354        let MixerHalfState::Qsa { kv } = hstate else {
16355            return Err("qwen4exp_gpu tp2: QSA half bound to non-QSA state".into());
16356        };
16357        let hidden = self.hidden;
16358        let (nh, nkv, hd) = (h.nh_h, h.nkv_h, h.hd);
16359        let mut q_fused = ws.take_f32(e, "qsa.qf", t * 2 * nh * hd, 0)?;
16360        let mut k_new = ws.take_f32(e, "qsa.k", t * nkv * hd, 0)?;
16361        let mut v_new = ws.take_f32(e, "qsa.v", t * nkv * hd, 0)?;
16362        // Proj stack (round 4): wq/wk/wv halves in ONE launch (bit-identical rows; OFF
16363        // arm = row-offset views of the same required stack). t == 1 only (the multi4
16364        // kernel is a decode form); chunks run the per-mat row-offset launches.
16365        if t == 1 && proj_stack_on() {
16366            launch_qmatvec_bf16w_multi4(
16367                e,
16368                &h.proj_b16,
16369                mixed,
16370                &[
16371                    (&q_fused, 2 * nh * hd),
16372                    (&k_new, nkv * hd),
16373                    (&v_new, nkv * hd),
16374                ],
16375                hidden,
16376            )?;
16377        } else {
16378            launch_qmatvec_bf16w_off(
16379                e,
16380                &h.proj_b16,
16381                0,
16382                mixed,
16383                &mut q_fused,
16384                hidden,
16385                2 * nh * hd,
16386                t,
16387            )?;
16388            launch_qmatvec_bf16w_off(
16389                e,
16390                &h.proj_b16,
16391                2 * nh * hd,
16392                mixed,
16393                &mut k_new,
16394                hidden,
16395                nkv * hd,
16396                t,
16397            )?;
16398            launch_qmatvec_bf16w_off(
16399                e,
16400                &h.proj_b16,
16401                2 * nh * hd + nkv * hd,
16402                mixed,
16403                &mut v_new,
16404                hidden,
16405                nkv * hd,
16406                t,
16407            )?;
16408        }
16409        let mut q = ws.take_f32(e, "qsa.q", t * nh * hd, 0)?;
16410        let mut gate = ws.take_f32(e, "qsa.gate", t * nh * hd, 0)?;
16411        e.q_gate_split(&q_fused, &mut q, &mut gate, hd, nh, t)?;
16412        ws.put_f32("qsa.qf", q_fused);
16413        let mut q = if let Some(norm) = h.q_norm.as_ref() {
16414            let mut dst = ws.take_f32(e, "qsa.qn", t * nh * hd, 0)?;
16415            e.rms_norm(&q, norm, &mut dst, hd, t * nh, eps)?;
16416            ws.put_f32("qsa.q", q);
16417            dst
16418        } else {
16419            q
16420        };
16421        let mut k_new = if let Some(norm) = h.k_norm.as_ref() {
16422            let mut dst = ws.take_f32(e, "qsa.kn", t * nkv * hd, 0)?;
16423            e.rms_norm(&k_new, norm, &mut dst, hd, t * nkv, eps)?;
16424            ws.put_f32("qsa.k", k_new);
16425            dst
16426        } else {
16427            k_new
16428        };
16429        let positions: Vec<i32> = (0..t).map(|i| (base_pos + i) as i32).collect();
16430        let pos_dev = ws.take_i32(e, "qsa.pos", &positions, 0)?;
16431        if let Some(yarn) = h.yarn.as_ref() {
16432            e.rope_neox_ffm(
16433                &mut q,
16434                &pos_dev,
16435                hd,
16436                h.n_rot,
16437                nh,
16438                t,
16439                h.rope_base,
16440                1.0,
16441                &yarn.ff,
16442                yarn.mscale,
16443            )?;
16444            e.rope_neox_ffm(
16445                &mut k_new,
16446                &pos_dev,
16447                hd,
16448                h.n_rot,
16449                nkv,
16450                t,
16451                h.rope_base,
16452                1.0,
16453                &yarn.ff,
16454                yarn.mscale,
16455            )?;
16456        } else {
16457            e.rope_neox(&mut q, &pos_dev, hd, h.n_rot, nh, t, h.rope_base, 1.0)?;
16458            e.rope_neox(&mut k_new, &pos_dev, hd, h.n_rot, nkv, t, h.rope_base, 1.0)?;
16459        }
16460        ws.put_i32("qsa.pos", pos_dev);
16461        match kv {
16462            QsaKvStore::F32 { k, v } => {
16463                e.copy_range_into(k, base_pos * nkv * hd, &k_new, 0, t * nkv * hd)?;
16464                e.copy_range_into(v, base_pos * nkv * hd, &v_new, 0, t * nkv * hd)?;
16465            }
16466            QsaKvStore::Q8Q5 { k, v } => {
16467                launch_q4e_kv_append(e, &k_new, &v_new, k, v, base_pos, t, nkv * hd)?;
16468            }
16469        }
16470        ws.put_f32(
16471            if h.k_norm.is_some() {
16472                "qsa.kn"
16473            } else {
16474                "qsa.k"
16475            },
16476            k_new,
16477        );
16478        ws.put_f32("qsa.v", v_new);
16479        Ok((q, gate))
16480    }
16481
16482    /// Post-selection QSA half: BLOCK-LIST SDPA over this card's KV half (bit-identical
16483    /// to the historical masked form on the same selection — the fixture-longatt /
16484    /// arm-0f pedigree — and the only form the quantized halves have), sigmoid gate,
16485    /// and the compact out-projection PARTIAL. t-generic.
16486    #[allow(clippy::too_many_arguments)]
16487    fn qsa_half_attend(
16488        &self,
16489        e: &Engine,
16490        ws: &mut StepPool,
16491        h: &QsaHalfW,
16492        hstate: &MixerHalfState,
16493        q: CudaSlice<f32>,
16494        gate: CudaSlice<f32>,
16495        pos_dev: &CudaSlice<i32>,
16496        meta_dev: &CudaSlice<i32>,
16497        max_count: usize,
16498        t: usize,
16499        t_kv: usize,
16500    ) -> Res<CudaSlice<f32>> {
16501        let MixerHalfState::Qsa { kv } = hstate else {
16502            return Err("qwen4exp_gpu tp2: QSA half bound to non-QSA state".into());
16503        };
16504        let hidden = self.hidden;
16505        let (nh, nkv, hd) = (h.nh_h, h.nkv_h, h.hd);
16506        let mut attended = ws.take_f32(e, "qsa.att", t * nh * hd, 0)?;
16507        match kv {
16508            QsaKvStore::F32 { k, v } => {
16509                let k_view = k.slice(0..t_kv * nkv * hd);
16510                let v_view = v.slice(0..t_kv * nkv * hd);
16511                launch_sdpa_blocklist(
16512                    e,
16513                    &q,
16514                    &k_view,
16515                    &v_view,
16516                    &mut attended,
16517                    pos_dev,
16518                    meta_dev,
16519                    hd,
16520                    nh,
16521                    nkv,
16522                    t,
16523                    max_count,
16524                    h.scale,
16525                )?;
16526            }
16527            QsaKvStore::Q8Q5 { k, v } => {
16528                launch_q4e_sdpa_blocklist_q8q5(
16529                    e,
16530                    &q,
16531                    k,
16532                    v,
16533                    &mut attended,
16534                    pos_dev,
16535                    meta_dev,
16536                    hd,
16537                    nh,
16538                    nkv,
16539                    t,
16540                    max_count,
16541                    h.scale,
16542                )?;
16543            }
16544        }
16545        ws.put_f32(
16546            if h.q_norm.is_some() {
16547                "qsa.qn"
16548            } else {
16549                "qsa.q"
16550            },
16551            q,
16552        );
16553        let mut sg = ws.take_f32(e, "qsa.sg", t * nh * hd, 0)?;
16554        e.sigmoid(&gate, &mut sg, t * nh * hd)?;
16555        let mut gated = ws.take_f32(e, "qsa.gated", t * nh * hd, 0)?;
16556        e.mul(&attended, &sg, &mut gated, t * nh * hd)?;
16557        let mut partial = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
16558        launch_qmatvec_bf16w(
16559            e,
16560            &h.wo_b16,
16561            &gated,
16562            &mut partial,
16563            nh * hd,
16564            hidden,
16565            t,
16566            1,
16567            0,
16568            0,
16569            nh * hd,
16570            0,
16571        )?;
16572        ws.put_f32("qsa.sg", sg);
16573        ws.put_f32("qsa.gated", gated);
16574        ws.put_f32("qsa.att", attended);
16575        ws.put_f32("qsa.gate", gate);
16576        Ok(partial)
16577    }
16578
16579    /// The QSA indexer host twin factored for TP2 (runs on card 0's projection; the mask
16580    /// bytes feed BOTH cards' masked SDPA halves).
16581    #[allow(clippy::too_many_arguments)]
16582    fn qsa_indexer_mask(
16583        &self,
16584        e: &Engine,
16585        ws: &mut StepPool,
16586        qsa: &QsaW,
16587        eps: f32,
16588        mixed: &CudaSlice<f32>,
16589        raw_keys: &mut IdxRawCache,
16590        pooled_keys: &mut Vec<f32>,
16591        base_pos: usize,
16592    ) -> Res<Vec<u8>> {
16593        let overlay = &qsa.overlay;
16594        let idx_dim = overlay.head_dim as usize;
16595        let qk_width = (overlay.query_heads as usize + overlay.kv_heads as usize) * idx_dim;
16596        let hidden = self.hidden;
16597        let mut idx_proj = ws.take_f32(e, "qsa.idxp", qk_width, 0)?;
16598        e.linear_device_into(mixed, &qsa.idx_proj, &mut idx_proj, 1, hidden, qk_width)?;
16599        let rows = e.dtoh_view(&idx_proj.slice(0..qk_width))?;
16600        ws.put_f32("qsa.idxp", idx_proj);
16601        raw_keys.append_rows_f32(
16602            &rows[overlay.query_heads as usize * idx_dim..qk_width],
16603            1,
16604            idx_dim,
16605        );
16606        indexer_mask_rows(
16607            overlay,
16608            qsa.attn.rope.base,
16609            qsa.yarn.as_ref().map(|y| (y.ff_host.as_slice(), y.mscale)),
16610            eps,
16611            &qsa.idx_q_norm,
16612            &qsa.idx_k_norm,
16613            &rows,
16614            raw_keys,
16615            pooled_keys,
16616            base_pos,
16617            1,
16618            base_pos + 1,
16619            0,
16620        )
16621    }
16622
16623    /// Shared-expert half on one card: gate/up rows (card 0 = the resident full twins'
16624    /// row prefix; card 1 = its suffix copies), silu, compact down columns. Returns the
16625    /// down PARTIAL and the (replicated-deterministic) input-gate scalar buffer.
16626    #[allow(clippy::too_many_arguments)]
16627    fn tp2_shared_half(
16628        &self,
16629        e: &Engine,
16630        ws: &mut StepPool,
16631        gu_b16: &CudaSlice<u8>,
16632        down_b16: &CudaSlice<u8>,
16633        input_gate: Option<&CudaSlice<f32>>,
16634        mixed: &CudaSlice<f32>,
16635        sffh: usize,
16636        t: usize,
16637    ) -> Res<(CudaSlice<f32>, Option<CudaSlice<f32>>)> {
16638        let hidden = self.hidden;
16639        let mut sh_gate = ws.take_f32(e, "moe.sh_gate", t * sffh, 0)?;
16640        let mut sh_up = ws.take_f32(e, "moe.sh_up", t * sffh, 0)?;
16641        // Proj stack (round 4): shared gate/up halves in ONE launch (bit-identical rows;
16642        // OFF arm = row-offset views of the same required stack). t == 1 only.
16643        if t == 1 && proj_stack_on() {
16644            launch_qmatvec_bf16w_multi4(
16645                e,
16646                gu_b16,
16647                mixed,
16648                &[(&sh_gate, sffh), (&sh_up, sffh)],
16649                hidden,
16650            )?;
16651        } else {
16652            launch_qmatvec_bf16w_off(e, gu_b16, 0, mixed, &mut sh_gate, hidden, sffh, t)?;
16653            launch_qmatvec_bf16w_off(e, gu_b16, sffh, mixed, &mut sh_up, hidden, sffh, t)?;
16654        }
16655        let mut act = ws.take_f32(e, "moe.sh_act", t * sffh, 0)?;
16656        e.silu_mul(&sh_gate, &sh_up, &mut act, t * sffh)?;
16657        let mut shared = ws.take_f32(e, "moe.sh_down", t * hidden, 0)?;
16658        launch_qmatvec_bf16w(
16659            e,
16660            down_b16,
16661            &act,
16662            &mut shared,
16663            sffh,
16664            hidden,
16665            t,
16666            1,
16667            0,
16668            0,
16669            sffh,
16670            0,
16671        )?;
16672        let g = match input_gate {
16673            Some(w) => {
16674                let mut g = ws.take_f32(e, "moe.g", t, 0)?;
16675                e.sigmoid_dot_rows_into(mixed, w, &mut g, hidden, t)?;
16676                Some(g)
16677            }
16678            None => None,
16679        };
16680        ws.put_f32("moe.sh_gate", sh_gate);
16681        ws.put_f32("moe.sh_up", sh_up);
16682        ws.put_f32("moe.sh_act", act);
16683        Ok((shared, g))
16684    }
16685}
16686
16687impl Qwen4ExpGpu {
16688    /// One TP2 decode step (t == 1, eager issue — decode graphs stay off in TP2; the
16689    /// joins are the schedule). Prefill stays single-card; the first call migrates the
16690    /// state (one-way latch). Requires the bf16-trunk + fused-gate seams ON (replicated
16691    /// compute must be deterministic-kernel-only).
16692    pub fn decode_step_tp2(
16693        &self,
16694        e0: &Engine,
16695        e1: &Engine,
16696        shard: &Tp2Shard,
16697        token: u32,
16698        state: &mut Qwen4ExpState,
16699    ) -> Res<Vec<f32>> {
16700        if !trunk_bf16_on() || !hc_fused_gate_on() {
16701            return Err(
16702                "qwen4exp_gpu tp2: requires set_trunk_bf16(true) and set_hc_fused_gate(true) \
16703                 (replicated compute must run deterministic kernels)"
16704                    .into(),
16705            );
16706        }
16707        if state.pos + 1 > state.capacity {
16708            return Err("qwen4exp_gpu: state capacity exceeded".into());
16709        }
16710        if state.tp2.is_none() {
16711            self.tp2_migrate(e0, e1, shard, state)?;
16712            state.graphs = StepGraphs::default();
16713        }
16714        let hidden = self.hidden;
16715        let vocab = self.vocab;
16716        let vsplit = shard.vsplit;
16717        let base_pos = state.pos;
16718        let reserve = state.reserve;
16719        state.tokens.push(token);
16720        let Qwen4ExpState {
16721            ref tokens,
16722            ws: ref mut ws0,
16723            ref mut tp2,
16724            layers: ref mut lstates,
16725            ..
16726        } = *state;
16727        let Tp2State {
16728            ws1,
16729            layers: tlayers,
16730            graphs: tgraphs,
16731            ..
16732        } = tp2.as_mut().expect("migrated above");
16733        // Slot RESERVE unit: reserve-derived, NOT capacity — a long-context TP2 state
16734        // (1M rows) must not reserve capacity-sized plane slots (~10 GB each).
16735        let cap = reserve.max(1);
16736
16737        // Entry: one embed row, H2D to both cards' plane slots (replicated planes).
16738        let token_us = token as usize;
16739        if token_us >= vocab {
16740            return Err(format!("qwen4exp_gpu: token {token_us} out of range").into());
16741        }
16742        let embedded = &self.embed_host[token_us * hidden..(token_us + 1) * hidden];
16743        let mut planes1: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
16744        let ptrs1 = {
16745            let _g = e1.gpu.enter_main()?;
16746            let embedded_dev = ws1.take_f32_h2d(e1, "entry.embed", embedded, cap * hidden)?;
16747            for s in 0..self.streams {
16748                let mut plane = ws1.take_f32(e1, PLANE_SLOTS[s], hidden, cap * hidden)?;
16749                e1.copy_into(&mut plane, 0, &embedded_dev, hidden)?;
16750                planes1.push(plane);
16751            }
16752            ws1.put_f32("entry.embed", embedded_dev);
16753            let ptr_vals: Vec<u64> = {
16754                let stream = e1.gpu.stream();
16755                planes1.iter().map(|p| p.device_ptr(&stream).0).collect()
16756            };
16757            ws1.take_u64_h2d(e1, "hc.ptrs", &ptr_vals, 0)?
16758        };
16759        let mut planes0: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
16760        let ptrs0 = {
16761            let _g = e0.gpu.enter_main()?;
16762            let embedded_dev = ws0.take_f32_h2d(e0, "entry.embed", embedded, cap * hidden)?;
16763            for s in 0..self.streams {
16764                let mut plane = ws0.take_f32(e0, PLANE_SLOTS[s], hidden, cap * hidden)?;
16765                e0.copy_into(&mut plane, 0, &embedded_dev, hidden)?;
16766                planes0.push(plane);
16767            }
16768            ws0.put_f32("entry.embed", embedded_dev);
16769            let ptr_vals: Vec<u64> = {
16770                let stream = e0.gpu.stream();
16771                planes0.iter().map(|p| p.device_ptr(&stream).0).collect()
16772            };
16773            ws0.take_u64_h2d(e0, "hc.ptrs", &ptr_vals, 0)?
16774        };
16775
16776        // Segment-graph mode (the single-card StepGraphs pattern per rank): first TP2
16777        // step runs fully eager to park every slot; captures are lazy on the next step.
16778        let use_graphs = decode_graphs_on() && step_ws_on();
16779        let graphs_live = use_graphs && tgraphs.warm;
16780        if use_graphs && !tgraphs.warm {
16781            tgraphs.warm = true;
16782        }
16783        if graphs_live && tgraphs.a[0].len() != self.layers.len() {
16784            for d in 0..2 {
16785                tgraphs.a[d] = (0..self.layers.len()).map(|_| None).collect();
16786                tgraphs.b[d] = (0..self.layers.len()).map(|_| None).collect();
16787                tgraphs.c[d] = (0..self.layers.len()).map(|_| None).collect();
16788                tgraphs.d[d] = (0..self.layers.len()).map(|_| None).collect();
16789            }
16790        }
16791        for (li, layer) in self.layers.iter().enumerate() {
16792            let lstate = &mut lstates[li];
16793            let tw = &shard.layers[li];
16794            let ts = &mut tlayers[li];
16795            let eps_a = layer.eps_attn;
16796            let eps_m = layer.eps_mlp;
16797            let moe = &layer.moe;
16798            let ff = moe.plan.expert_intermediate_size as usize;
16799            let experts = moe.plan.expert_count as usize;
16800            let selected = moe.plan.experts_per_token as usize;
16801            let sff = moe
16802                .plan
16803                .shared
16804                .as_ref()
16805                .map(|s| s.intermediate_size as usize)
16806                .unwrap_or(0);
16807            let sffh = sff / 2;
16808
16809            // ---- phase 1: attn gate + mixer half + join push (parity 0), per card ----
16810            match (&layer.mixer, &tw.mixer0, &tw.mixer1) {
16811                (MixerW::Gdn(_), MixerHalfW::Gdn(h0), MixerHalfW::Gdn(h1)) => {
16812                    {
16813                        let _g = e1.gpu.enter_main()?;
16814                        if let (Some(ple1), Some(ps1)) = (tw.ple1.as_ref(), ts.ple1.as_mut()) {
16815                            let table = &layer.ple.as_ref().expect("ple plan").table;
16816                            self.ple_block(
16817                                e1,
16818                                layer,
16819                                ple1,
16820                                table,
16821                                ps1,
16822                                &mut planes1,
16823                                tokens,
16824                                1,
16825                                false,
16826                                None,
16827                            )?;
16828                        }
16829                        if graphs_live && layer.ple.is_none() {
16830                            if tgraphs.a[1][li].is_none() {
16831                                tgraphs.a[1][li] =
16832                                    Some(e1.capture_graph_retained_nowarm(|eng| {
16833                                        self.tp2_gdn_seg_a(
16834                                            eng,
16835                                            ws1,
16836                                            &ptrs1,
16837                                            &tw.attn_gate1,
16838                                            h1,
16839                                            &mut ts.m1,
16840                                            &planes1,
16841                                            eps_a,
16842                                            shard.stage0_raw[0],
16843                                        )
16844                                    })?);
16845                            }
16846                            tgraphs.a[1][li].as_ref().unwrap().0.launch()?;
16847                        } else {
16848                            self.tp2_gdn_seg_a(
16849                                e1,
16850                                ws1,
16851                                &ptrs1,
16852                                &tw.attn_gate1,
16853                                h1,
16854                                &mut ts.m1,
16855                                &planes1,
16856                                eps_a,
16857                                shard.stage0_raw[0],
16858                            )?;
16859                        }
16860                        shard.ev1[0].record(&e1.gpu.stream())?;
16861                    }
16862                    {
16863                        let _g = e0.gpu.enter_main()?;
16864                        if let (Some(ple), Some(ps)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
16865                            self.ple_block(
16866                                e0,
16867                                layer,
16868                                ple,
16869                                &ple.table,
16870                                ps,
16871                                &mut planes0,
16872                                tokens,
16873                                1,
16874                                false,
16875                                None,
16876                            )?;
16877                        }
16878                        if graphs_live && layer.ple.is_none() {
16879                            if tgraphs.a[0][li].is_none() {
16880                                tgraphs.a[0][li] =
16881                                    Some(e0.capture_graph_retained_nowarm(|eng| {
16882                                        self.tp2_gdn_seg_a(
16883                                            eng,
16884                                            ws0,
16885                                            &ptrs0,
16886                                            &layer.attn_gate,
16887                                            h0,
16888                                            &mut ts.m0,
16889                                            &planes0,
16890                                            eps_a,
16891                                            shard.stage1_raw[0],
16892                                        )
16893                                    })?);
16894                            }
16895                            tgraphs.a[0][li].as_ref().unwrap().0.launch()?;
16896                        } else {
16897                            self.tp2_gdn_seg_a(
16898                                e0,
16899                                ws0,
16900                                &ptrs0,
16901                                &layer.attn_gate,
16902                                h0,
16903                                &mut ts.m0,
16904                                &planes0,
16905                                eps_a,
16906                                shard.stage1_raw[0],
16907                            )?;
16908                        }
16909                        shard.ev0[0].record(&e0.gpu.stream())?;
16910                    }
16911                }
16912                (MixerW::Qsa(qsa), MixerHalfW::Qsa(h0), MixerHalfW::Qsa(h1)) => {
16913                    // QSA stays eager: the indexer selection and the per-step t_kv
16914                    // launch shape are not capturable (single-card precedent).
16915                    let (q1, g1, inj1) = {
16916                        let _g = e1.gpu.enter_main()?;
16917                        let (mixed1, inj1) = self.gate_read(
16918                            e1,
16919                            ws1,
16920                            &ptrs1,
16921                            &tw.attn_gate1,
16922                            &planes1,
16923                            1,
16924                            eps_a,
16925                            false,
16926                        )?;
16927                        let (q1, g1) = self
16928                            .qsa_half_proj(e1, ws1, eps_a, h1, &mixed1, &mut ts.m1, base_pos, 1)?;
16929                        ws1.put_f32("hc.mixed", mixed1);
16930                        (q1, g1, inj1)
16931                    };
16932                    // The selection runs ONCE on card 0 (the single-card machinery:
16933                    // idxcache device raw cache, device scorer, audit twin) and its
16934                    // position lists feed BOTH cards' block-list halves — bit-identical
16935                    // to the historical masked form on the same selection.
16936                    let (sels, q0, g0, inj0) = {
16937                        let _g = e0.gpu.enter_main()?;
16938                        let (mixed0, inj0) = self.gate_read(
16939                            e0,
16940                            ws0,
16941                            &ptrs0,
16942                            &layer.attn_gate,
16943                            &planes0,
16944                            1,
16945                            eps_a,
16946                            false,
16947                        )?;
16948                        let (q0, g0) = self
16949                            .qsa_half_proj(e0, ws0, eps_a, h0, &mixed0, &mut ts.m0, base_pos, 1)?;
16950                        let MixerState::Qsa {
16951                            raw_keys,
16952                            pooled_keys,
16953                            pooled_dev,
16954                            pooled_dev_rows,
16955                            raw_dev,
16956                            raw_dev_rows,
16957                            idx_audit,
16958                            ..
16959                        } = &mut lstate.mixer
16960                        else {
16961                            return Err("qwen4exp_gpu tp2: QSA layer without raw-key cache".into());
16962                        };
16963                        let sels = self.qsa_update_select(
16964                            e0,
16965                            ws0,
16966                            qsa,
16967                            eps_a,
16968                            &mixed0,
16969                            raw_keys,
16970                            pooled_keys,
16971                            pooled_dev,
16972                            pooled_dev_rows,
16973                            raw_dev,
16974                            raw_dev_rows,
16975                            idx_audit.as_mut(),
16976                            base_pos,
16977                            1,
16978                            0,
16979                            false,
16980                        )?;
16981                        ws0.put_f32("hc.mixed", mixed0);
16982                        (sels, q0, g0, inj0)
16983                    };
16984                    let t_kv = base_pos + 1;
16985                    let block_size = qsa.overlay.block_size as usize;
16986                    let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
16987                    {
16988                        let _g = e1.gpu.enter_main()?;
16989                        let pos_dev = ws1.take_i32(e1, "qsa.selpos", &pos_flat, 0)?;
16990                        let meta_dev = ws1.take_i32(e1, "qsa.selmeta", &meta, 0)?;
16991                        let p1 = self.qsa_half_attend(
16992                            e1, ws1, h1, &ts.m1, q1, g1, &pos_dev, &meta_dev, max_count, 1, t_kv,
16993                        )?;
16994                        ws1.put_i32("qsa.selpos", pos_dev);
16995                        ws1.put_i32("qsa.selmeta", meta_dev);
16996                        launch_push(e1, &p1, shard.stage0_raw[0], hidden)?;
16997                        ws1.put_f32("mixer.out", p1);
16998                        put_inject(ws1, inj1);
16999                        shard.ev1[0].record(&e1.gpu.stream())?;
17000                    }
17001                    {
17002                        let _g = e0.gpu.enter_main()?;
17003                        let pos_dev = ws0.take_i32(e0, "qsa.selpos", &pos_flat, 0)?;
17004                        let meta_dev = ws0.take_i32(e0, "qsa.selmeta", &meta, 0)?;
17005                        let p0 = self.qsa_half_attend(
17006                            e0, ws0, h0, &ts.m0, q0, g0, &pos_dev, &meta_dev, max_count, 1, t_kv,
17007                        )?;
17008                        ws0.put_i32("qsa.selpos", pos_dev);
17009                        ws0.put_i32("qsa.selmeta", meta_dev);
17010                        launch_push(e0, &p0, shard.stage1_raw[0], hidden)?;
17011                        ws0.put_f32("mixer.out", p0);
17012                        put_inject(ws0, inj0);
17013                        shard.ev0[0].record(&e0.gpu.stream())?;
17014                    }
17015                }
17016                _ => return Err("qwen4exp_gpu tp2: mixer/shard shape mismatch".into()),
17017            }
17018            {
17019                let _g = e0.gpu.enter_main()?;
17020                e0.gpu.stream().wait(&shard.ev1[0])?;
17021            }
17022            {
17023                let _g = e1.gpu.enter_main()?;
17024                e1.gpu.stream().wait(&shard.ev0[0])?;
17025            }
17026
17027            // ---- phase 2: join add + write + mlp gate (+ card1 shared prestage) ----
17028            {
17029                let _g = e1.gpu.enter_main()?;
17030                if graphs_live {
17031                    if tgraphs.b[1][li].is_none() {
17032                        tgraphs.b[1][li] = Some(e1.capture_graph_retained_nowarm(|eng| {
17033                            self.tp2_seg_b(
17034                                eng,
17035                                ws1,
17036                                &ptrs1,
17037                                &tw.mlp_gate1,
17038                                &mut planes1,
17039                                &shard.stage1[0],
17040                                false,
17041                                eps_m,
17042                                Some((
17043                                    &tw.moe.shared_gu1_b16,
17044                                    &tw.moe.shared_down1,
17045                                    tw.moe.shared_input_gate1.as_ref(),
17046                                    sffh,
17047                                )),
17048                            )
17049                        })?);
17050                    }
17051                    tgraphs.b[1][li].as_ref().unwrap().0.launch()?;
17052                } else {
17053                    self.tp2_seg_b(
17054                        e1,
17055                        ws1,
17056                        &ptrs1,
17057                        &tw.mlp_gate1,
17058                        &mut planes1,
17059                        &shard.stage1[0],
17060                        false,
17061                        eps_m,
17062                        Some((
17063                            &tw.moe.shared_gu1_b16,
17064                            &tw.moe.shared_down1,
17065                            tw.moe.shared_input_gate1.as_ref(),
17066                            sffh,
17067                        )),
17068                    )?;
17069                }
17070            }
17071            {
17072                let _g = e0.gpu.enter_main()?;
17073                if graphs_live {
17074                    if tgraphs.b[0][li].is_none() {
17075                        tgraphs.b[0][li] = Some(e0.capture_graph_retained_nowarm(|eng| {
17076                            self.tp2_seg_b(
17077                                eng,
17078                                ws0,
17079                                &ptrs0,
17080                                &layer.mlp_gate,
17081                                &mut planes0,
17082                                &shard.stage0[0],
17083                                true,
17084                                eps_m,
17085                                None,
17086                            )
17087                        })?);
17088                    }
17089                    tgraphs.b[0][li].as_ref().unwrap().0.launch()?;
17090                } else {
17091                    self.tp2_seg_b(
17092                        e0,
17093                        ws0,
17094                        &ptrs0,
17095                        &layer.mlp_gate,
17096                        &mut planes0,
17097                        &shard.stage0[0],
17098                        true,
17099                        eps_m,
17100                        None,
17101                    )?;
17102                }
17103            }
17104
17105            // ---- phase 3: router host boundary + count-gated MoE tail (graphable via the
17106            // pack blob: fixed launch shapes, live slot count on device) + join (parity 1) ----
17107            let route = {
17108                let _g = e0.gpu.enter_main()?;
17109                let mixed0 = ws0.take_f32(e0, "hc.mixed", hidden, 0)?;
17110                let mut router_out = ws0.take_f32(e0, "moe.router", experts, 0)?;
17111                let none: Option<CudaSlice<u8>> = None;
17112                let rb = if router_bf16_on() {
17113                    &moe.router_b16
17114                } else {
17115                    &none
17116                };
17117                linear_trunk_into(
17118                    e0,
17119                    &moe.router,
17120                    rb,
17121                    &mixed0,
17122                    &mut router_out,
17123                    1,
17124                    hidden,
17125                    experts,
17126                )?;
17127                let logits = e0.dtoh_view(&router_out.slice(0..experts))?;
17128                ws0.put_f32("moe.router", router_out);
17129                ws0.put_f32("hc.mixed", mixed0);
17130                host_route_softmax_topk(&logits, selected)
17131            };
17132            // Split by PLACEMENT (even split when no map is loaded — then rank() is
17133            // `expert >= experts/2` and local() is `expert - experts/2`, i.e. exactly the
17134            // arithmetic this site used before the seam existed).
17135            let place = &tw.place;
17136            let mut sel0: Vec<i32> = Vec::with_capacity(selected);
17137            let mut w0: Vec<f32> = Vec::with_capacity(selected);
17138            let mut sel1: Vec<i32> = Vec::with_capacity(selected);
17139            let mut w1: Vec<f32> = Vec::with_capacity(selected);
17140            for &(expert, weight) in &route {
17141                if place.rank(expert) == 0 {
17142                    sel0.push(place.local(expert) as i32);
17143                    w0.push(weight);
17144                } else {
17145                    sel1.push(place.local(expert) as i32);
17146                    w1.push(weight);
17147                }
17148            }
17149            {
17150                // Route trace + per-rank engagement, in the decode shape (t == 1). The
17151                // trace rides the readback the host router twin already did.
17152                let r0: Vec<Vec<(usize, f32)>> = vec![
17153                    sel0.iter()
17154                        .zip(&w0)
17155                        .map(|(&s, &w)| (s as usize, w))
17156                        .collect(),
17157                ];
17158                let r1: Vec<Vec<(usize, f32)>> = vec![
17159                    sel1.iter()
17160                        .zip(&w1)
17161                        .map(|(&s, &w)| (s as usize, w))
17162                        .collect(),
17163                ];
17164                tp2_count_split(&r0, &r1);
17165                trace_moe_routes(layer.index, 1, std::slice::from_ref(&route));
17166            }
17167            match tp2_gate_red()? {
17168                Tp2GateRed::None => {}
17169                // Drop the peer's routed contribution entirely.
17170                Tp2GateRed::SkipPeerMoe => {
17171                    sel1.clear();
17172                    w1.clear();
17173                }
17174                // Send peer-owned experts to card 0's bank at their peer LOCAL slot: the
17175                // plausible off-by-remap bug — right magnitudes, wrong experts.
17176                Tp2GateRed::PeerLocalIds => {
17177                    sel0.extend(sel1.drain(..));
17178                    w0.extend(w1.drain(..));
17179                }
17180                Tp2GateRed::ReverseePeerWeights => w1.reverse(),
17181            }
17182            let max_sel = selected;
17183            {
17184                let _g = e1.gpu.enter_main()?;
17185                ws1.upsert_u8(e1, "moe.pack", &tp2_pack_bytes(&sel1, &w1, max_sel), 0)?;
17186                if graphs_live {
17187                    if tgraphs.c[1][li].is_none() {
17188                        tgraphs.c[1][li] = Some(e1.capture_graph_retained_nowarm(|eng| {
17189                            self.tp2_seg_c(
17190                                eng,
17191                                ws1,
17192                                (
17193                                    &tw.moe.gate1.codes,
17194                                    &tw.moe.gate1.scales,
17195                                    &tw.moe.gate1.macros_dev,
17196                                ),
17197                                (
17198                                    &tw.moe.up1.codes,
17199                                    &tw.moe.up1.scales,
17200                                    &tw.moe.up1.macros_dev,
17201                                ),
17202                                (
17203                                    &tw.moe.down1.codes,
17204                                    &tw.moe.down1.scales,
17205                                    &tw.moe.down1.macros_dev,
17206                                ),
17207                                ff,
17208                                max_sel,
17209                                None,
17210                                tw.moe.shared_input_gate1.is_some(),
17211                                shard.stage0_raw[1],
17212                            )
17213                        })?);
17214                    }
17215                    tgraphs.c[1][li].as_ref().unwrap().0.launch()?;
17216                } else {
17217                    self.tp2_seg_c(
17218                        e1,
17219                        ws1,
17220                        (
17221                            &tw.moe.gate1.codes,
17222                            &tw.moe.gate1.scales,
17223                            &tw.moe.gate1.macros_dev,
17224                        ),
17225                        (
17226                            &tw.moe.up1.codes,
17227                            &tw.moe.up1.scales,
17228                            &tw.moe.up1.macros_dev,
17229                        ),
17230                        (
17231                            &tw.moe.down1.codes,
17232                            &tw.moe.down1.scales,
17233                            &tw.moe.down1.macros_dev,
17234                        ),
17235                        ff,
17236                        max_sel,
17237                        None,
17238                        tw.moe.shared_input_gate1.is_some(),
17239                        shard.stage0_raw[1],
17240                    )?;
17241                }
17242                shard.ev1[1].record(&e1.gpu.stream())?;
17243            }
17244            {
17245                let _g = e0.gpu.enter_main()?;
17246                let (
17247                    BankHalf::Nvfp4 {
17248                        codes: gc,
17249                        scales: gs,
17250                        macros_dev: gm,
17251                        ..
17252                    },
17253                    BankHalf::Nvfp4 {
17254                        codes: uc,
17255                        scales: us,
17256                        macros_dev: um,
17257                        ..
17258                    },
17259                    BankHalf::Nvfp4 {
17260                        codes: dc,
17261                        scales: ds,
17262                        macros_dev: dm,
17263                        ..
17264                    },
17265                ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
17266                else {
17267                    return Err("qwen4exp_gpu tp2: card0 bank is not NVFP4".into());
17268                };
17269                ws0.upsert_u8(e0, "moe.pack", &tp2_pack_bytes(&sel0, &w0, max_sel), 0)?;
17270                if graphs_live {
17271                    if tgraphs.c[0][li].is_none() {
17272                        tgraphs.c[0][li] = Some(e0.capture_graph_retained_nowarm(|eng| {
17273                            self.tp2_seg_c(
17274                                eng,
17275                                ws0,
17276                                (gc, gs, gm),
17277                                (uc, us, um),
17278                                (dc, ds, dm),
17279                                ff,
17280                                max_sel,
17281                                Some((
17282                                    &tw.moe.shared_gu0_b16,
17283                                    &tw.moe.shared_down0,
17284                                    moe.shared_input_gate.as_ref(),
17285                                    sffh,
17286                                )),
17287                                false,
17288                                shard.stage1_raw[1],
17289                            )
17290                        })?);
17291                    }
17292                    tgraphs.c[0][li].as_ref().unwrap().0.launch()?;
17293                } else {
17294                    self.tp2_seg_c(
17295                        e0,
17296                        ws0,
17297                        (gc, gs, gm),
17298                        (uc, us, um),
17299                        (dc, ds, dm),
17300                        ff,
17301                        max_sel,
17302                        Some((
17303                            &tw.moe.shared_gu0_b16,
17304                            &tw.moe.shared_down0,
17305                            moe.shared_input_gate.as_ref(),
17306                            sffh,
17307                        )),
17308                        false,
17309                        shard.stage1_raw[1],
17310                    )?;
17311                }
17312                shard.ev0[1].record(&e0.gpu.stream())?;
17313            }
17314            {
17315                let _g = e1.gpu.enter_main()?;
17316                e1.gpu.stream().wait(&shard.ev0[1])?;
17317                if graphs_live {
17318                    if tgraphs.d[1][li].is_none() {
17319                        tgraphs.d[1][li] = Some(e1.capture_graph_retained_nowarm(|eng| {
17320                            self.tp2_seg_d(eng, ws1, &ptrs1, &mut planes1, &shard.stage1[1], false)
17321                        })?);
17322                    }
17323                    tgraphs.d[1][li].as_ref().unwrap().0.launch()?;
17324                } else {
17325                    self.tp2_seg_d(e1, ws1, &ptrs1, &mut planes1, &shard.stage1[1], false)?;
17326                }
17327            }
17328            {
17329                let _g = e0.gpu.enter_main()?;
17330                e0.gpu.stream().wait(&shard.ev1[1])?;
17331                if graphs_live {
17332                    if tgraphs.d[0][li].is_none() {
17333                        tgraphs.d[0][li] = Some(e0.capture_graph_retained_nowarm(|eng| {
17334                            self.tp2_seg_d(eng, ws0, &ptrs0, &mut planes0, &shard.stage0[1], true)
17335                        })?);
17336                    }
17337                    tgraphs.d[0][li].as_ref().unwrap().0.launch()?;
17338                } else {
17339                    self.tp2_seg_d(e0, ws0, &ptrs0, &mut planes0, &shard.stage0[1], true)?;
17340                }
17341            }
17342        }
17343
17344        // Exit mixer (replicated) + vocab-split lm_head, per card (graphable).
17345        {
17346            let _g = e1.gpu.enter_main()?;
17347            if graphs_live {
17348                if tgraphs.exit[1].is_none() {
17349                    tgraphs.exit[1] = Some(e1.capture_graph_retained_nowarm(|eng| {
17350                        self.tp2_seg_exit(
17351                            eng,
17352                            ws1,
17353                            &ptrs1,
17354                            &shard.exit_gate1,
17355                            &planes1,
17356                            &shard.lm_head1,
17357                            vocab - vsplit,
17358                            1, // decode_step_tp2 is t == 1 by construction
17359                        )
17360                    })?);
17361                }
17362                tgraphs.exit[1].as_ref().unwrap().0.launch()?;
17363            } else {
17364                self.tp2_seg_exit(
17365                    e1,
17366                    ws1,
17367                    &ptrs1,
17368                    &shard.exit_gate1,
17369                    &planes1,
17370                    &shard.lm_head1,
17371                    vocab - vsplit,
17372                    1, // decode_step_tp2 is t == 1 by construction
17373                )?;
17374            }
17375        }
17376        {
17377            let _g = e0.gpu.enter_main()?;
17378            let head0 = self
17379                .output_b16
17380                .as_ref()
17381                .ok_or("qwen4exp_gpu tp2: lm_head has no bf16 twin")?;
17382            if graphs_live {
17383                if tgraphs.exit[0].is_none() {
17384                    tgraphs.exit[0] = Some(e0.capture_graph_retained_nowarm(|eng| {
17385                        self.tp2_seg_exit(
17386                            eng,
17387                            ws0,
17388                            &ptrs0,
17389                            &self.exit_mixer,
17390                            &planes0,
17391                            head0,
17392                            vsplit,
17393                            1, // decode_step_tp2 is t == 1 by construction
17394                        )
17395                    })?);
17396                }
17397                tgraphs.exit[0].as_ref().unwrap().0.launch()?;
17398            } else {
17399                self.tp2_seg_exit(
17400                    e0,
17401                    ws0,
17402                    &ptrs0,
17403                    &self.exit_mixer,
17404                    &planes0,
17405                    head0,
17406                    vsplit,
17407                    1, // decode_step_tp2 is t == 1 by construction
17408                )?;
17409            }
17410        }
17411        let mut out = vec![0.0f32; vocab];
17412        {
17413            let _g = e0.gpu.enter_main()?;
17414            let logits0 = ws0.peek_f32("logits")?;
17415            let host0 = e0.dtoh_view(&logits0.slice(0..vsplit))?;
17416            out[..vsplit].copy_from_slice(&host0);
17417        }
17418        {
17419            let _g = e1.gpu.enter_main()?;
17420            let logits1 = ws1.peek_f32("logits")?;
17421            let host1 = e1.dtoh_view(&logits1.slice(0..vocab - vsplit))?;
17422            out[vsplit..].copy_from_slice(&host1);
17423        }
17424        for (s, plane) in planes0.into_iter().enumerate() {
17425            ws0.put_f32(PLANE_SLOTS[s], plane);
17426        }
17427        for (s, plane) in planes1.into_iter().enumerate() {
17428            ws1.put_f32(PLANE_SLOTS[s], plane);
17429        }
17430        ws0.put_u64("hc.ptrs", ptrs0);
17431        ws1.put_u64("hc.ptrs", ptrs1);
17432        state.pos += 1;
17433        Ok(out)
17434    }
17435}
17436
17437impl Qwen4ExpGpu {
17438    /// TP2-NATIVE long-context state (tp2-prefill lane): the per-card halves allocate
17439    /// DIRECTLY at `capacity` and the single-card KV allocates as a stub — a 1M-token
17440    /// state never materializes the single-card cache at all (the yarn cell's card-0
17441    /// blocker). The state is TP2-latched from birth: single-card forwards refuse it
17442    /// (`state.tp2.is_some()`), and `decode_step_tp2` skips the migration.
17443    pub fn alloc_state_tp2(
17444        &self,
17445        e0: &Engine,
17446        e1: &Engine,
17447        shard: &Tp2Shard,
17448        capacity: usize,
17449        reserve: usize,
17450    ) -> Res<Qwen4ExpState> {
17451        // The single-card side: stub KV, live idx caches (the TP2 indexer runs on
17452        // card 0 through the same machinery), PLE/GDN states on card 0 unused by the
17453        // TP2 route but kept tiny.
17454        let mut state = {
17455            // Stub the single-card KV by allocating under a 1-token capacity, then
17456            // restore the real capacity for the mask/meta bookkeeping.
17457            // The stub's reserve is 1, not `reserve`: `reserve.min(1).max(1)` was written
17458            // here and is the constant 1 for every usize (clippy::min_max, deny-by-default,
17459            // which is how it surfaced). Behaviour-identical simplification — the real
17460            // `reserve` is restored two lines down.
17461            let mut st = self.alloc_state_reserve(e0, 1, 1, None)?;
17462            st.capacity = capacity;
17463            st.reserve = reserve;
17464            st
17465        };
17466        let mut tlayers = Vec::with_capacity(self.layers.len());
17467        for (layer, tw) in self.layers.iter().zip(shard.layers.iter()) {
17468            let mk_half = |e: &Engine, hw: &MixerHalfW| -> Res<MixerHalfState> {
17469                let _g = e.gpu.enter_main()?;
17470                match hw {
17471                    MixerHalfW::Gdn(h) => {
17472                        let conv_dim = 2 * h.nk_h * h.hk + h.nv_h * h.hv;
17473                        let pad = h.kernel - 1;
17474                        Ok(MixerHalfState::Gdn {
17475                            conv: e.zeros(pad * conv_dim)?,
17476                            state: e.zeros(h.nv_h * h.hv * h.hk)?,
17477                        })
17478                    }
17479                    MixerHalfW::Qsa(h) => {
17480                        let kv_dim = h.nkv_h * h.hd;
17481                        let kv = if kv_quant_on() {
17482                            QsaKvStore::Q8Q5 {
17483                                k: e.alloc_u8(capacity * q8_row_bytes(kv_dim))?,
17484                                v: e.alloc_u8(capacity * q5_row_bytes(kv_dim))?,
17485                            }
17486                        } else {
17487                            QsaKvStore::F32 {
17488                                k: e.zeros(capacity * kv_dim)?,
17489                                v: e.zeros(capacity * kv_dim)?,
17490                            }
17491                        };
17492                        Ok(MixerHalfState::Qsa { kv })
17493                    }
17494                }
17495            };
17496            let m0 = mk_half(e0, &tw.mixer0)?;
17497            let m1 = mk_half(e1, &tw.mixer1)?;
17498            let ple1 = match layer.ple.as_ref() {
17499                None => None,
17500                Some(ple) => {
17501                    let pad = (ple.plan.conv_kernel as usize - 1) * ple.plan.max_ngram as usize;
17502                    let _g = e1.gpu.enter_main()?;
17503                    let mut conv_hist = Vec::with_capacity(self.streams);
17504                    for _ in 0..self.streams {
17505                        conv_hist.push(e1.zeros(pad * self.hidden)?);
17506                    }
17507                    Some(PleState {
17508                        conv_hist,
17509                        ngram_ids: Vec::new(),
17510                        ngram_history: Vec::new(),
17511                        ngram_last_eos: -1,
17512                    })
17513                }
17514            };
17515            tlayers.push(Tp2LayerState { m0, m1, ple1 });
17516        }
17517        state.tp2 = Some(Tp2State {
17518            ws1: StepPool::default(),
17519            layers: tlayers,
17520            graphs: Tp2Graphs::default(),
17521            pf_stage0: None,
17522            pf_stage1: None,
17523            pf_stage0_raw: [0; 2],
17524            pf_stage1_raw: [0; 2],
17525            pf_rows: 0,
17526        });
17527        Ok(state)
17528    }
17529
17530    /// TP2 LONG-context chunked prefill: `prefill_extend`'s program on the TP2 route —
17531    /// KV/state fill happens SHARDED-LOCAL on each card (the yarn cell measured remote
17532    /// KV at 18x decode collapse; local halves are the 1M route). Returns the LAST
17533    /// row's logits [vocab].
17534    pub fn prefill_extend_tp2(
17535        &self,
17536        e0: &Engine,
17537        e1: &Engine,
17538        shard: &Tp2Shard,
17539        ids: &[u32],
17540        state: &mut Qwen4ExpState,
17541        chunk: usize,
17542    ) -> Res<Vec<f32>> {
17543        if ids.is_empty() || chunk == 0 {
17544            return Err("qwen4exp_gpu: prefill_extend_tp2 needs ids and a chunk size".into());
17545        }
17546        let mut last = Vec::new();
17547        for piece in ids.chunks(chunk) {
17548            let is_last =
17549                piece.as_ptr() as usize + piece.len() * 4 == ids.as_ptr() as usize + ids.len() * 4;
17550            let head = if is_last {
17551                HeadMode::LastRow
17552            } else {
17553                HeadMode::Skip
17554            };
17555            last = self.forward_tp2(e0, e1, shard, piece, state, head)?;
17556        }
17557        Ok(last)
17558    }
17559
17560    /// One TP2 forward over `t` rows (eager; the TP2-prefill program). Replicated
17561    /// planes + gate reads on both cards, mixer/MoE halves with LOCAL KV/state, join
17562    /// adds in fixed rank order (the decode joins' determinism argument), the indexer
17563    /// selection ONCE on card 0 feeding both cards' block-list halves, and the MoE
17564    /// route split by expert half from the card-0 host route.
17565    #[allow(clippy::too_many_arguments)]
17566    pub fn forward_tp2(
17567        &self,
17568        e0: &Engine,
17569        e1: &Engine,
17570        shard: &Tp2Shard,
17571        ids: &[u32],
17572        state: &mut Qwen4ExpState,
17573        head: HeadMode,
17574    ) -> Res<Vec<f32>> {
17575        if !trunk_bf16_on() || !hc_fused_gate_on() {
17576            return Err(
17577                "qwen4exp_gpu tp2: requires set_trunk_bf16(true) and set_hc_fused_gate(true)"
17578                    .into(),
17579            );
17580        }
17581        let t = ids.len();
17582        if t == 0 {
17583            return Err("qwen4exp_gpu tp2: empty chunk".into());
17584        }
17585        if state.pos + t > state.capacity {
17586            return Err("qwen4exp_gpu: state capacity exceeded".into());
17587        }
17588        if state.tp2.is_none() {
17589            self.tp2_migrate(e0, e1, shard, state)?;
17590            state.graphs = StepGraphs::default();
17591        }
17592        let hidden = self.hidden;
17593        let vocab = self.vocab;
17594        let vsplit = shard.vsplit;
17595        let base_pos = state.pos;
17596        let reserve = state.reserve;
17597        state.tokens.extend_from_slice(ids);
17598        let Qwen4ExpState {
17599            ref tokens,
17600            ws: ref mut ws0,
17601            ref mut tp2,
17602            layers: ref mut lstates,
17603            ..
17604        } = *state;
17605        let tp2s = tp2.as_mut().expect("alloc'd or migrated above");
17606        // Prefill join staging: [t*hidden] x 2 per direction, grown to the largest
17607        // chunk seen (the two-buffer parity proof is the decode staging's, verbatim).
17608        if tp2s.pf_rows < t {
17609            {
17610                let _g = e1.gpu.enter_main()?;
17611                let s1 = [e1.zeros(t * hidden)?, e1.zeros(t * hidden)?];
17612                let s = e1.gpu.stream();
17613                tp2s.pf_stage1_raw = [s1[0].device_ptr(&s).0 as u64, s1[1].device_ptr(&s).0 as u64];
17614                tp2s.pf_stage1 = Some(s1);
17615            }
17616            {
17617                let _g = e0.gpu.enter_main()?;
17618                let s0 = [e0.zeros(t * hidden)?, e0.zeros(t * hidden)?];
17619                let s = e0.gpu.stream();
17620                tp2s.pf_stage0_raw = [s0[0].device_ptr(&s).0 as u64, s0[1].device_ptr(&s).0 as u64];
17621                tp2s.pf_stage0 = Some(s0);
17622            }
17623            tp2s.pf_rows = t;
17624        }
17625        let Tp2State {
17626            ws1,
17627            layers: tlayers,
17628            pf_stage0,
17629            pf_stage1,
17630            pf_stage0_raw,
17631            pf_stage1_raw,
17632            ..
17633        } = tp2s;
17634        let pf_stage0 = pf_stage0.as_ref().expect("sized above");
17635        let pf_stage1 = pf_stage1.as_ref().expect("sized above");
17636        let resv = reserve.max(t);
17637
17638        // Entry: embed rows, H2D to BOTH cards' plane slots (replicated planes).
17639        let mut embedded = vec![0.0f32; t * hidden];
17640        for (row, &token) in ids.iter().enumerate() {
17641            let token = token as usize;
17642            if token >= vocab {
17643                return Err(format!("qwen4exp_gpu: token {token} out of range").into());
17644            }
17645            embedded[row * hidden..(row + 1) * hidden]
17646                .copy_from_slice(&self.embed_host[token * hidden..(token + 1) * hidden]);
17647        }
17648        let mut planes1: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
17649        let ptrs1 = {
17650            let _g = e1.gpu.enter_main()?;
17651            let embedded_dev = ws1.take_f32_h2d(e1, "entry.embed", &embedded, resv * hidden)?;
17652            for s in 0..self.streams {
17653                let mut plane = ws1.take_f32(e1, PLANE_SLOTS[s], t * hidden, resv * hidden)?;
17654                e1.copy_into(&mut plane, 0, &embedded_dev, t * hidden)?;
17655                planes1.push(plane);
17656            }
17657            ws1.put_f32("entry.embed", embedded_dev);
17658            let ptr_vals: Vec<u64> = {
17659                let stream = e1.gpu.stream();
17660                planes1.iter().map(|p| p.device_ptr(&stream).0).collect()
17661            };
17662            ws1.take_u64_h2d(e1, "hc.ptrs", &ptr_vals, 0)?
17663        };
17664        let mut planes0: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
17665        let ptrs0 = {
17666            let _g = e0.gpu.enter_main()?;
17667            let embedded_dev = ws0.take_f32_h2d(e0, "entry.embed", &embedded, resv * hidden)?;
17668            for s in 0..self.streams {
17669                let mut plane = ws0.take_f32(e0, PLANE_SLOTS[s], t * hidden, resv * hidden)?;
17670                e0.copy_into(&mut plane, 0, &embedded_dev, t * hidden)?;
17671                planes0.push(plane);
17672            }
17673            ws0.put_f32("entry.embed", embedded_dev);
17674            let ptr_vals: Vec<u64> = {
17675                let stream = e0.gpu.stream();
17676                planes0.iter().map(|p| p.device_ptr(&stream).0).collect()
17677            };
17678            ws0.take_u64_h2d(e0, "hc.ptrs", &ptr_vals, 0)?
17679        };
17680
17681        for (li, layer) in self.layers.iter().enumerate() {
17682            let lstate = &mut lstates[li];
17683            let tw = &shard.layers[li];
17684            let ts = &mut tlayers[li];
17685            let eps_a = layer.eps_attn;
17686            let eps_m = layer.eps_mlp;
17687            let moe = &layer.moe;
17688            let ff = moe.plan.expert_intermediate_size as usize;
17689            let experts = moe.plan.expert_count as usize;
17690            let selected = moe.plan.experts_per_token as usize;
17691            let sff = moe
17692                .plan
17693                .shared
17694                .as_ref()
17695                .map(|s| s.intermediate_size as usize)
17696                .unwrap_or(0);
17697            let sffh = sff / 2;
17698
17699            // ---- PLE (wide-stream add), replicated on both cards ----
17700            if let (Some(ple), Some(ps)) = (layer.ple.as_ref(), lstate.ple.as_mut()) {
17701                let _g = e0.gpu.enter_main()?;
17702                self.ple_block(
17703                    e0,
17704                    layer,
17705                    ple,
17706                    &ple.table,
17707                    ps,
17708                    &mut planes0,
17709                    tokens,
17710                    t,
17711                    false,
17712                    None,
17713                )?;
17714            }
17715            if let (Some(ple1), Some(ps1)) = (tw.ple1.as_ref(), ts.ple1.as_mut()) {
17716                let table = &layer.ple.as_ref().expect("ple plan").table;
17717                let _g = e1.gpu.enter_main()?;
17718                self.ple_block(
17719                    e1,
17720                    layer,
17721                    ple1,
17722                    table,
17723                    ps1,
17724                    &mut planes1,
17725                    tokens,
17726                    t,
17727                    false,
17728                    None,
17729                )?;
17730            }
17731
17732            // ---- phase 1: attn gate + mixer halves + join push (parity 0) ----
17733            match (&layer.mixer, &tw.mixer0, &tw.mixer1) {
17734                (MixerW::Gdn(_), MixerHalfW::Gdn(h0), MixerHalfW::Gdn(h1)) => {
17735                    {
17736                        let _g = e1.gpu.enter_main()?;
17737                        let (mixed1, inj1) = self.gate_read(
17738                            e1,
17739                            ws1,
17740                            &ptrs1,
17741                            &tw.attn_gate1,
17742                            &planes1,
17743                            t,
17744                            eps_a,
17745                            false,
17746                        )?;
17747                        let p1 =
17748                            self.gdn_forward_half(e1, ws1, eps_a, h1, &mixed1, &mut ts.m1, t)?;
17749                        ws1.put_f32("hc.mixed", mixed1);
17750                        launch_push(e1, &p1, pf_stage0_raw[0], t * hidden)?;
17751                        ws1.put_f32("mixer.out", p1);
17752                        put_inject(ws1, inj1);
17753                        shard.ev1[0].record(&e1.gpu.stream())?;
17754                    }
17755                    {
17756                        let _g = e0.gpu.enter_main()?;
17757                        let (mixed0, inj0) = self.gate_read(
17758                            e0,
17759                            ws0,
17760                            &ptrs0,
17761                            &layer.attn_gate,
17762                            &planes0,
17763                            t,
17764                            eps_a,
17765                            false,
17766                        )?;
17767                        let p0 =
17768                            self.gdn_forward_half(e0, ws0, eps_a, h0, &mixed0, &mut ts.m0, t)?;
17769                        ws0.put_f32("hc.mixed", mixed0);
17770                        launch_push(e0, &p0, pf_stage1_raw[0], t * hidden)?;
17771                        ws0.put_f32("mixer.out", p0);
17772                        put_inject(ws0, inj0);
17773                        shard.ev0[0].record(&e0.gpu.stream())?;
17774                    }
17775                }
17776                (MixerW::Qsa(qsa), MixerHalfW::Qsa(h0), MixerHalfW::Qsa(h1)) => {
17777                    let (q1, g1, inj1) = {
17778                        let _g = e1.gpu.enter_main()?;
17779                        let (mixed1, inj1) = self.gate_read(
17780                            e1,
17781                            ws1,
17782                            &ptrs1,
17783                            &tw.attn_gate1,
17784                            &planes1,
17785                            t,
17786                            eps_a,
17787                            false,
17788                        )?;
17789                        let (q1, g1) = self
17790                            .qsa_half_proj(e1, ws1, eps_a, h1, &mixed1, &mut ts.m1, base_pos, t)?;
17791                        ws1.put_f32("hc.mixed", mixed1);
17792                        (q1, g1, inj1)
17793                    };
17794                    let (sels, q0, g0, inj0) = {
17795                        let _g = e0.gpu.enter_main()?;
17796                        let (mixed0, inj0) = self.gate_read(
17797                            e0,
17798                            ws0,
17799                            &ptrs0,
17800                            &layer.attn_gate,
17801                            &planes0,
17802                            t,
17803                            eps_a,
17804                            false,
17805                        )?;
17806                        let (q0, g0) = self
17807                            .qsa_half_proj(e0, ws0, eps_a, h0, &mixed0, &mut ts.m0, base_pos, t)?;
17808                        let MixerState::Qsa {
17809                            raw_keys,
17810                            pooled_keys,
17811                            pooled_dev,
17812                            pooled_dev_rows,
17813                            raw_dev,
17814                            raw_dev_rows,
17815                            idx_audit,
17816                            ..
17817                        } = &mut lstate.mixer
17818                        else {
17819                            return Err("qwen4exp_gpu tp2: QSA layer without raw-key cache".into());
17820                        };
17821                        let sels = self.qsa_update_select(
17822                            e0,
17823                            ws0,
17824                            qsa,
17825                            eps_a,
17826                            &mixed0,
17827                            raw_keys,
17828                            pooled_keys,
17829                            pooled_dev,
17830                            pooled_dev_rows,
17831                            raw_dev,
17832                            raw_dev_rows,
17833                            idx_audit.as_mut(),
17834                            base_pos,
17835                            t,
17836                            0,
17837                            false,
17838                        )?;
17839                        ws0.put_f32("hc.mixed", mixed0);
17840                        (sels, q0, g0, inj0)
17841                    };
17842                    let t_kv = base_pos + t;
17843                    let block_size = qsa.overlay.block_size as usize;
17844                    let (pos_flat, meta, max_count) = rowsel_positions(&sels, block_size);
17845                    {
17846                        let _g = e1.gpu.enter_main()?;
17847                        let pos_dev = ws1.take_i32(e1, "qsa.selpos", &pos_flat, 0)?;
17848                        let meta_dev = ws1.take_i32(e1, "qsa.selmeta", &meta, 0)?;
17849                        let p1 = self.qsa_half_attend(
17850                            e1, ws1, h1, &ts.m1, q1, g1, &pos_dev, &meta_dev, max_count, t, t_kv,
17851                        )?;
17852                        ws1.put_i32("qsa.selpos", pos_dev);
17853                        ws1.put_i32("qsa.selmeta", meta_dev);
17854                        launch_push(e1, &p1, pf_stage0_raw[0], t * hidden)?;
17855                        ws1.put_f32("mixer.out", p1);
17856                        put_inject(ws1, inj1);
17857                        shard.ev1[0].record(&e1.gpu.stream())?;
17858                    }
17859                    {
17860                        let _g = e0.gpu.enter_main()?;
17861                        let pos_dev = ws0.take_i32(e0, "qsa.selpos", &pos_flat, 0)?;
17862                        let meta_dev = ws0.take_i32(e0, "qsa.selmeta", &meta, 0)?;
17863                        let p0 = self.qsa_half_attend(
17864                            e0, ws0, h0, &ts.m0, q0, g0, &pos_dev, &meta_dev, max_count, t, t_kv,
17865                        )?;
17866                        ws0.put_i32("qsa.selpos", pos_dev);
17867                        ws0.put_i32("qsa.selmeta", meta_dev);
17868                        launch_push(e0, &p0, pf_stage1_raw[0], t * hidden)?;
17869                        ws0.put_f32("mixer.out", p0);
17870                        put_inject(ws0, inj0);
17871                        shard.ev0[0].record(&e0.gpu.stream())?;
17872                    }
17873                }
17874                _ => return Err("qwen4exp_gpu tp2: mixer/shard shape mismatch".into()),
17875            }
17876            {
17877                let _g = e0.gpu.enter_main()?;
17878                e0.gpu.stream().wait(&shard.ev1[0])?;
17879            }
17880            {
17881                let _g = e1.gpu.enter_main()?;
17882                e1.gpu.stream().wait(&shard.ev0[0])?;
17883            }
17884
17885            // ---- phase 2: join add (fixed rank order) + gate_write + mlp gate_read ----
17886            let join_write = |e: &Engine,
17887                              ws: &mut StepPool,
17888                              ptrs: &CudaSlice<u64>,
17889                              planes: &mut [CudaSlice<f32>],
17890                              stage: &CudaSlice<f32>,
17891                              rank0: bool|
17892             -> Res<()> {
17893                let p = ws.take_f32(e, "mixer.out", t * hidden, 0)?;
17894                let mut out = ws.take_f32(e, "join.out", t * hidden, 0)?;
17895                if rank0 {
17896                    e.add(&p, stage, &mut out, t * hidden)?;
17897                } else {
17898                    e.add(stage, &p, &mut out, t * hidden)?;
17899                }
17900                let inj = take_inject(e, ws, self.streams, t)?;
17901                self.gate_write(e, planes, ptrs, &out, &inj, t)?;
17902                ws.put_f32("mixer.out", p);
17903                ws.put_f32("join.out", out);
17904                put_inject(ws, inj);
17905                Ok(())
17906            };
17907            {
17908                let _g = e1.gpu.enter_main()?;
17909                join_write(e1, ws1, &ptrs1, &mut planes1, &pf_stage1[0], false)?;
17910            }
17911            {
17912                let _g = e0.gpu.enter_main()?;
17913                join_write(e0, ws0, &ptrs0, &mut planes0, &pf_stage0[0], true)?;
17914            }
17915
17916            // ---- phase 3: mlp gate + MoE halves + shared halves + join (parity 1) ----
17917            let mixed1 = {
17918                let _g = e1.gpu.enter_main()?;
17919                let (mixed1, injm1) =
17920                    self.gate_read(e1, ws1, &ptrs1, &tw.mlp_gate1, &planes1, t, eps_m, false)?;
17921                put_inject(ws1, injm1);
17922                mixed1
17923            };
17924            let mixed0 = {
17925                let _g = e0.gpu.enter_main()?;
17926                let (mixed0, injm0) =
17927                    self.gate_read(e0, ws0, &ptrs0, &layer.mlp_gate, &planes0, t, eps_m, false)?;
17928                put_inject(ws0, injm0);
17929                mixed0
17930            };
17931            // Route on card 0 (host twin — TP2 keeps host expert ids by construction),
17932            // split by expert half.
17933            let routes: Vec<Vec<(usize, f32)>> = {
17934                let _g = e0.gpu.enter_main()?;
17935                let mut router_out = ws0.take_f32(e0, "moe.router", t * experts, 0)?;
17936                let none: Option<CudaSlice<u8>> = None;
17937                let rb = if router_bf16_on() {
17938                    &moe.router_b16
17939                } else {
17940                    &none
17941                };
17942                linear_trunk_into(
17943                    e0,
17944                    &moe.router,
17945                    rb,
17946                    &mixed0,
17947                    &mut router_out,
17948                    t,
17949                    hidden,
17950                    experts,
17951                )?;
17952                let logits = e0.dtoh_view(&router_out.slice(0..t * experts))?;
17953                ws0.put_f32("moe.router", router_out);
17954                let mut routes = Vec::with_capacity(t);
17955                for token in 0..t {
17956                    routes.push(host_route_softmax_topk(
17957                        &logits[token * experts..(token + 1) * experts],
17958                        selected,
17959                    ));
17960                }
17961                routes
17962            };
17963            // Split by PLACEMENT (see the decode site); with no map loaded this is the
17964            // even split and reproduces the previous `eid < e_half` / `eid - e_half`
17965            // arithmetic exactly.
17966            let place = &tw.place;
17967            let split_half = |home: bool| -> Vec<Vec<(usize, f32)>> {
17968                routes
17969                    .iter()
17970                    .map(|r| {
17971                        r.iter()
17972                            .filter(|&&(eid, _)| (place.rank(eid) == 0) == home)
17973                            .map(|&(eid, w)| (place.local(eid), w))
17974                            .collect()
17975                    })
17976                    .collect()
17977            };
17978            let mut routes0 = split_half(true);
17979            let mut routes1 = split_half(false);
17980            // Per-rank engagement + the shared-format route trace, in the PREFILL shape
17981            // (one line per (layer, forward) carrying this chunk's t rows of picks).
17982            tp2_count_split(&routes0, &routes1);
17983            trace_moe_routes(layer.index, t, &routes);
17984            match tp2_gate_red()? {
17985                Tp2GateRed::None => {}
17986                Tp2GateRed::SkipPeerMoe => routes1.iter_mut().for_each(|r| r.clear()),
17987                Tp2GateRed::PeerLocalIds => {
17988                    for (r0, r1) in routes0.iter_mut().zip(routes1.iter_mut()) {
17989                        r0.append(r1);
17990                    }
17991                }
17992                Tp2GateRed::ReverseePeerWeights => {
17993                    for r in routes1.iter_mut() {
17994                        let n = r.len();
17995                        for i in 0..n / 2 {
17996                            let (a, b) = (r[i].1, r[n - 1 - i].1);
17997                            r[i].1 = b;
17998                            r[n - 1 - i].1 = a;
17999                        }
18000                    }
18001                }
18002            }
18003            let (routes0, routes1) = (routes0, routes1);
18004            // Card 1: routed half over the bank half (local ids) + shared suffix half.
18005            {
18006                let _g = e1.gpu.enter_main()?;
18007                let mut out1 = self.tp2_moe_rows(
18008                    e1,
18009                    ws1,
18010                    (
18011                        &tw.moe.gate1.codes,
18012                        &tw.moe.gate1.scales,
18013                        &tw.moe.gate1.macros_dev,
18014                    ),
18015                    (
18016                        &tw.moe.up1.codes,
18017                        &tw.moe.up1.scales,
18018                        &tw.moe.up1.macros_dev,
18019                    ),
18020                    (
18021                        &tw.moe.down1.codes,
18022                        &tw.moe.down1.scales,
18023                        &tw.moe.down1.macros_dev,
18024                    ),
18025                    &routes1,
18026                    &mixed1,
18027                    t,
18028                    ff,
18029                )?;
18030                let (sh, g) = self.tp2_shared_half(
18031                    e1,
18032                    ws1,
18033                    &tw.moe.shared_gu1_b16,
18034                    &tw.moe.shared_down1,
18035                    tw.moe.shared_input_gate1.as_ref(),
18036                    &mixed1,
18037                    sffh,
18038                    t,
18039                )?;
18040                match g.as_ref() {
18041                    Some(g) => e1.add_scaled_rows(&sh, g, &mut out1, hidden, t)?,
18042                    None => {
18043                        let mut summed = ws1.take_f32(e1, "moe.sum", t * hidden, 0)?;
18044                        e1.add(&out1, &sh, &mut summed, t * hidden)?;
18045                        ws1.put_f32("moe.out", out1);
18046                        out1 = summed;
18047                    }
18048                }
18049                ws1.put_f32("moe.sh_down", sh);
18050                if let Some(g) = g {
18051                    ws1.put_f32("moe.g", g);
18052                }
18053                launch_push(e1, &out1, pf_stage0_raw[1], t * hidden)?;
18054                ws1.put_f32("moe.out", out1);
18055                ws1.put_f32("hc.mixed", mixed1);
18056                shard.ev1[1].record(&e1.gpu.stream())?;
18057            }
18058            // Card 0: routed half over the FULL resident bank (absolute ids < E/2) +
18059            // shared prefix half.
18060            {
18061                let _g = e0.gpu.enter_main()?;
18062                let (
18063                    BankHalf::Nvfp4 {
18064                        codes: gc,
18065                        scales: gs,
18066                        macros_dev: gm,
18067                        ..
18068                    },
18069                    BankHalf::Nvfp4 {
18070                        codes: uc,
18071                        scales: us,
18072                        macros_dev: um,
18073                        ..
18074                    },
18075                    BankHalf::Nvfp4 {
18076                        codes: dc,
18077                        scales: ds,
18078                        macros_dev: dm,
18079                        ..
18080                    },
18081                ) = (&moe.bank.gate, &moe.bank.up, &moe.bank.down)
18082                else {
18083                    return Err("qwen4exp_gpu tp2: card0 bank is not NVFP4".into());
18084                };
18085                let mut out0 = self.tp2_moe_rows(
18086                    e0,
18087                    ws0,
18088                    (gc, gs, gm),
18089                    (uc, us, um),
18090                    (dc, ds, dm),
18091                    &routes0,
18092                    &mixed0,
18093                    t,
18094                    ff,
18095                )?;
18096                let (sh, g) = self.tp2_shared_half(
18097                    e0,
18098                    ws0,
18099                    &tw.moe.shared_gu0_b16,
18100                    &tw.moe.shared_down0,
18101                    moe.shared_input_gate.as_ref(),
18102                    &mixed0,
18103                    sffh,
18104                    t,
18105                )?;
18106                match g.as_ref() {
18107                    Some(g) => e0.add_scaled_rows(&sh, g, &mut out0, hidden, t)?,
18108                    None => {
18109                        let mut summed = ws0.take_f32(e0, "moe.sum", t * hidden, 0)?;
18110                        e0.add(&out0, &sh, &mut summed, t * hidden)?;
18111                        ws0.put_f32("moe.out", out0);
18112                        out0 = summed;
18113                    }
18114                }
18115                ws0.put_f32("moe.sh_down", sh);
18116                if let Some(g) = g {
18117                    ws0.put_f32("moe.g", g);
18118                }
18119                launch_push(e0, &out0, pf_stage1_raw[1], t * hidden)?;
18120                ws0.put_f32("moe.out", out0);
18121                ws0.put_f32("hc.mixed", mixed0);
18122                shard.ev0[1].record(&e0.gpu.stream())?;
18123            }
18124            {
18125                let _g = e1.gpu.enter_main()?;
18126                e1.gpu.stream().wait(&shard.ev0[1])?;
18127                let p = ws1.take_f32(e1, "moe.out", t * hidden, 0)?;
18128                let mut out = ws1.take_f32(e1, "join.out", t * hidden, 0)?;
18129                e1.add(&pf_stage1[1], &p, &mut out, t * hidden)?;
18130                let inj = take_inject(e1, ws1, self.streams, t)?;
18131                self.gate_write(e1, &mut planes1, &ptrs1, &out, &inj, t)?;
18132                ws1.put_f32("moe.out", p);
18133                ws1.put_f32("join.out", out);
18134                put_inject(ws1, inj);
18135            }
18136            {
18137                let _g = e0.gpu.enter_main()?;
18138                e0.gpu.stream().wait(&shard.ev1[1])?;
18139                let p = ws0.take_f32(e0, "moe.out", t * hidden, 0)?;
18140                let mut out = ws0.take_f32(e0, "join.out", t * hidden, 0)?;
18141                e0.add(&p, &pf_stage0[1], &mut out, t * hidden)?;
18142                let inj = take_inject(e0, ws0, self.streams, t)?;
18143                self.gate_write(e0, &mut planes0, &ptrs0, &out, &inj, t)?;
18144                ws0.put_f32("moe.out", p);
18145                ws0.put_f32("join.out", out);
18146                put_inject(ws0, inj);
18147            }
18148        }
18149
18150        // Exit: Skip on interior chunks; LastRow copies each plane's final row into
18151        // t == 1 exit slots and runs the decode exit segment on them; All runs the exit
18152        // segment over ALL t rows straight off the planes.
18153        //
18154        // `All` used to fall through to the LastRow body, so a caller asking for every row
18155        // got exactly one and no error. That is the failure mode the loud-failure law is
18156        // about: the TP2 class gate's whole PRIME regime is "compare EVERY row of a full-head
18157        // forward", and it could not have done that — it only surfaced because the gate
18158        // length-checks single-card logits against TP2 logits before comparing
18159        // ("single-card produced 2483200 logits, TP2 248320"). Without that check the gate
18160        // would have compared one row and reported a t>=2 verdict.
18161        //
18162        // Cost note (why this stays an instrument, not a serving path): a [t, vocab] block is
18163        // t * 248320 * 4 bytes, so it is ~9.9 MB at the gate's 10-token probe and gigabytes at
18164        // a long-context chunk. Chunked prefill therefore still uses LastRow, exactly as the
18165        // single-card path does for the same reason.
18166        let head_rows = match head {
18167            HeadMode::All => t,
18168            _ => 1,
18169        };
18170        let mut out = vec![
18171            0.0f32;
18172            if head == HeadMode::Skip {
18173                0
18174            } else {
18175                head_rows * vocab
18176            }
18177        ];
18178        if head != HeadMode::Skip {
18179            {
18180                let _g = e1.gpu.enter_main()?;
18181                // All: the planes already hold every row, so the exit reads them directly
18182                // with the pointer array the trunk built. LastRow: copy each plane's final
18183                // row into the t == 1 exit slots (the decode-shaped exit).
18184                let mut exit_planes: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
18185                if head != HeadMode::All {
18186                    for (s, plane) in planes1.iter().enumerate() {
18187                        let mut row = ws1.take_f32(e1, EXIT_PLANE_SLOTS[s], hidden, hidden)?;
18188                        e1.copy_range_into(&mut row, 0, plane, (t - 1) * hidden, hidden)?;
18189                        exit_planes.push(row);
18190                    }
18191                }
18192                let use_planes: &[CudaSlice<f32>] = if head == HeadMode::All {
18193                    &planes1
18194                } else {
18195                    &exit_planes
18196                };
18197                let ptr_vals: Vec<u64> = {
18198                    let stream = e1.gpu.stream();
18199                    use_planes.iter().map(|p| p.device_ptr(&stream).0).collect()
18200                };
18201                let eptrs = ws1.take_u64_h2d(e1, "exit.ptrs", &ptr_vals, 0)?;
18202                self.tp2_seg_exit(
18203                    e1,
18204                    ws1,
18205                    &eptrs,
18206                    &shard.exit_gate1,
18207                    use_planes,
18208                    &shard.lm_head1,
18209                    vocab - vsplit,
18210                    head_rows,
18211                )?;
18212                ws1.put_u64("exit.ptrs", eptrs);
18213                for (s, p) in exit_planes.into_iter().enumerate() {
18214                    ws1.put_f32(EXIT_PLANE_SLOTS[s], p);
18215                }
18216                let logits1 = ws1.peek_f32("logits")?;
18217                let half1 = vocab - vsplit;
18218                let host1 = e1.dtoh_view(&logits1.slice(0..head_rows * half1))?;
18219                // This card owns the HIGH column half of every row, so a [rows, half1]
18220                // block scatters into [rows, vocab] one row at a time.
18221                for r in 0..head_rows {
18222                    out[r * vocab + vsplit..(r + 1) * vocab]
18223                        .copy_from_slice(&host1[r * half1..(r + 1) * half1]);
18224                }
18225            }
18226            {
18227                let _g = e0.gpu.enter_main()?;
18228                let head0 = self
18229                    .output_b16
18230                    .as_ref()
18231                    .ok_or("qwen4exp_gpu tp2: lm_head has no bf16 twin")?;
18232                let mut exit_planes: Vec<CudaSlice<f32>> = Vec::with_capacity(self.streams);
18233                if head != HeadMode::All {
18234                    for (s, plane) in planes0.iter().enumerate() {
18235                        let mut row = ws0.take_f32(e0, EXIT_PLANE_SLOTS[s], hidden, hidden)?;
18236                        e0.copy_range_into(&mut row, 0, plane, (t - 1) * hidden, hidden)?;
18237                        exit_planes.push(row);
18238                    }
18239                }
18240                let use_planes: &[CudaSlice<f32>] = if head == HeadMode::All {
18241                    &planes0
18242                } else {
18243                    &exit_planes
18244                };
18245                let ptr_vals: Vec<u64> = {
18246                    let stream = e0.gpu.stream();
18247                    use_planes.iter().map(|p| p.device_ptr(&stream).0).collect()
18248                };
18249                let eptrs = ws0.take_u64_h2d(e0, "exit.ptrs", &ptr_vals, 0)?;
18250                self.tp2_seg_exit(
18251                    e0,
18252                    ws0,
18253                    &eptrs,
18254                    &self.exit_mixer,
18255                    use_planes,
18256                    head0,
18257                    vsplit,
18258                    head_rows,
18259                )?;
18260                ws0.put_u64("exit.ptrs", eptrs);
18261                for (s, p) in exit_planes.into_iter().enumerate() {
18262                    ws0.put_f32(EXIT_PLANE_SLOTS[s], p);
18263                }
18264                let logits0 = ws0.peek_f32("logits")?;
18265                let host0 = e0.dtoh_view(&logits0.slice(0..head_rows * vsplit))?;
18266                // This card owns the LOW column half of every row.
18267                for r in 0..head_rows {
18268                    out[r * vocab..r * vocab + vsplit]
18269                        .copy_from_slice(&host0[r * vsplit..(r + 1) * vsplit]);
18270                }
18271            }
18272        } else {
18273            // Establish a host boundary per chunk so the chunk loop cannot run the
18274            // host arbitrarily far ahead of both devices.
18275            {
18276                let _g = e0.gpu.enter_main()?;
18277                e0.gpu.stream().synchronize()?;
18278            }
18279            {
18280                let _g = e1.gpu.enter_main()?;
18281                e1.gpu.stream().synchronize()?;
18282            }
18283        }
18284        for (s, plane) in planes0.into_iter().enumerate() {
18285            ws0.put_f32(PLANE_SLOTS[s], plane);
18286        }
18287        for (s, plane) in planes1.into_iter().enumerate() {
18288            ws1.put_f32(PLANE_SLOTS[s], plane);
18289        }
18290        ws0.put_u64("hc.ptrs", ptrs0);
18291        ws1.put_u64("hc.ptrs", ptrs1);
18292        state.pos += t;
18293        Ok(out)
18294    }
18295
18296    /// Grouped routed-experts half at t rows (TP2 prefill): the single-card grouped
18297    /// prefill program (SLOT_CAP sub-batching, absolute-token maps, per-token
18298    /// slot-ordered combines) over THIS CARD's bank (card 0 = the full resident bank
18299    /// with absolute ids < E/2; card 1 = the half bank with local ids). Tokens with no
18300    /// experts on this card keep their zero rows (the join sums the halves).
18301    #[allow(clippy::too_many_arguments)]
18302    fn tp2_moe_rows(
18303        &self,
18304        e: &Engine,
18305        ws: &mut StepPool,
18306        gate: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
18307        up: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
18308        down: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
18309        routes: &[Vec<(usize, f32)>],
18310        mixed: &CudaSlice<f32>,
18311        t: usize,
18312        ff: usize,
18313    ) -> Res<CudaSlice<f32>> {
18314        let hidden = self.hidden;
18315        if !(sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0) {
18316            return Err(
18317                "qwen4exp_gpu tp2: prefill MoE needs the gufuse geometry (hidden%32, ff%4)".into(),
18318            );
18319        }
18320        let mut out = ws.take_f32(e, "moe.out", t * hidden, 0)?;
18321        {
18322            let mut view = out.slice_mut(0..t * hidden);
18323            e.memset_zeros_view(&mut view)?;
18324        }
18325        const SLOT_CAP: usize = 8192;
18326        let mut tok0 = 0usize;
18327        while tok0 < t {
18328            // Advance until the slot budget fills (routes are variable-length halves).
18329            let mut tok_n = 0usize;
18330            let mut slots = 0usize;
18331            while tok0 + tok_n < t {
18332                let n = routes[tok0 + tok_n].len();
18333                if tok_n > 0 && slots + n > SLOT_CAP {
18334                    break;
18335                }
18336                slots += n;
18337                tok_n += 1;
18338            }
18339            let batch = &routes[tok0..tok0 + tok_n];
18340            let mut sel_all: Vec<i32> = Vec::with_capacity(slots);
18341            let mut w_all: Vec<f32> = Vec::with_capacity(slots);
18342            let mut tok_all: Vec<i32> = Vec::with_capacity(slots);
18343            let mut ranges: Vec<(usize, usize)> = Vec::with_capacity(tok_n);
18344            for (i, route) in batch.iter().enumerate() {
18345                ranges.push((sel_all.len(), route.len()));
18346                for &(eid, wgt) in route {
18347                    sel_all.push(eid as i32);
18348                    w_all.push(wgt);
18349                    tok_all.push((tok0 + i) as i32);
18350                }
18351            }
18352            let s_total = sel_all.len();
18353            if s_total > 0 {
18354                let sel = ws.take_i32(e, "moe.sel", &sel_all, 0)?;
18355                let w_dev = ws.take_f32_h2d(e, "moe.w", &w_all, 0)?;
18356                let tokm = ws.take_i32(e, "moe.tok", &tok_all, 0)?;
18357                let mut act = ws.take_f32(e, "moe.act", s_total * ff, 0)?;
18358                launch_nvfp4_sel_gu_silu(
18359                    e,
18360                    gate,
18361                    up,
18362                    Some(&sel),
18363                    0,
18364                    s_total,
18365                    mixed,
18366                    &mut act,
18367                    hidden,
18368                    ff,
18369                    Some((&tokm, hidden)),
18370                )?;
18371                let mut partial = ws.take_f32(e, "moe.partial", s_total * hidden, 0)?;
18372                launch_nvfp4_sel_matvec(
18373                    e,
18374                    down.0,
18375                    down.1,
18376                    down.2,
18377                    &sel,
18378                    &act,
18379                    &mut partial,
18380                    s_total,
18381                    ff,
18382                    hidden,
18383                    ff,
18384                )?;
18385                for (i, &(start, len)) in ranges.iter().enumerate() {
18386                    if len > 0 {
18387                        launch_axpy_rows_seq_at(
18388                            e,
18389                            &partial,
18390                            start,
18391                            &w_dev,
18392                            start,
18393                            &mut out,
18394                            tok0 + i,
18395                            hidden,
18396                            len,
18397                        )?;
18398                    }
18399                }
18400                ws.put_i32("moe.sel", sel);
18401                ws.put_i32("moe.tok", tokm);
18402                ws.put_f32("moe.w", w_dev);
18403                ws.put_f32("moe.act", act);
18404                ws.put_f32("moe.partial", partial);
18405            }
18406            tok0 += tok_n;
18407        }
18408        Ok(out)
18409    }
18410
18411    /// TP2 segment A (GDN layers, graphable): attn gate_read + GDN half + join push;
18412    /// parks the partial in "mixer.out" and the inject scalars in their slots.
18413    #[allow(clippy::too_many_arguments)]
18414    fn tp2_gdn_seg_a(
18415        &self,
18416        e: &Engine,
18417        ws: &mut StepPool,
18418        ptrs: &CudaSlice<u64>,
18419        attn_gate: &GateW,
18420        h: &GdnHalfW,
18421        hstate: &mut MixerHalfState,
18422        planes: &[CudaSlice<f32>],
18423        eps: f32,
18424        push_raw: u64,
18425    ) -> Res<()> {
18426        let (mixed, inj) = self.gate_read(e, ws, ptrs, attn_gate, planes, 1, eps, false)?;
18427        let p = self.gdn_forward_half(e, ws, eps, h, &mixed, hstate, 1)?;
18428        ws.put_f32("hc.mixed", mixed);
18429        launch_push(e, &p, push_raw, self.hidden)?;
18430        ws.put_f32("mixer.out", p);
18431        put_inject(ws, inj);
18432        Ok(())
18433    }
18434
18435    /// TP2 segment B (all layers, graphable): mixer join add (SAME rank order on both
18436    /// cards) + gate_write + mlp gate_read (+ optional card-1 shared-half prestage,
18437    /// parked in "tp2.sh"/"tp2.shg"); parks the mlp mixed in "hc.mixed" and the mlp
18438    /// inject in its slots.
18439    #[allow(clippy::too_many_arguments)]
18440    fn tp2_seg_b(
18441        &self,
18442        e: &Engine,
18443        ws: &mut StepPool,
18444        ptrs: &CudaSlice<u64>,
18445        mlp_gate: &GateW,
18446        planes: &mut [CudaSlice<f32>],
18447        stage_recv: &CudaSlice<f32>,
18448        rank0: bool,
18449        eps_m: f32,
18450        shared: Option<(
18451            &CudaSlice<u8>,
18452            &CudaSlice<u8>,
18453            Option<&CudaSlice<f32>>,
18454            usize,
18455        )>,
18456    ) -> Res<()> {
18457        let hidden = self.hidden;
18458        let p = ws.take_f32(e, "mixer.out", hidden, 0)?;
18459        let mut out = ws.take_f32(e, "join.out", hidden, 0)?;
18460        if rank0 {
18461            e.add(&p, stage_recv, &mut out, hidden)?;
18462        } else {
18463            e.add(stage_recv, &p, &mut out, hidden)?;
18464        }
18465        let inj = take_inject(e, ws, self.streams, 1)?;
18466        self.gate_write(e, planes, ptrs, &out, &inj, 1)?;
18467        ws.put_f32("mixer.out", p);
18468        ws.put_f32("join.out", out);
18469        put_inject(ws, inj);
18470        let (mixed, injm) = self.gate_read(e, ws, ptrs, mlp_gate, planes, 1, eps_m, false)?;
18471        if let Some((gu_b16, d_b16, ig, sffh)) = shared {
18472            let (sh, gg) = self.tp2_shared_half(e, ws, gu_b16, d_b16, ig, &mixed, sffh, 1)?;
18473            // Slot-cycle invariant: park under the SAME names tp2_shared_half takes
18474            // from ("moe.sh_down"/"moe.g"), or the next capture of this segment would
18475            // allocate inside the capture region (graph mem node).
18476            ws.put_f32("moe.sh_down", sh);
18477            if let Some(gg) = gg {
18478                ws.put_f32("moe.g", gg);
18479            }
18480        }
18481        ws.put_f32("hc.mixed", mixed);
18482        put_inject(ws, injm);
18483        Ok(())
18484    }
18485
18486    /// TP2 exit segment (graphable): exit mixer read + this card's lm_head half into the
18487    /// parked "logits" slot.
18488    #[allow(clippy::too_many_arguments)]
18489    /// TP2 exit segment (mixer + this card's lm_head column half) over `rows` rows.
18490    ///
18491    /// `rows` used to be hardcoded to 1, which made `HeadMode::All` silently identical to
18492    /// `HeadMode::LastRow` in the TP2 forward — see the caller for why that was a defect
18493    /// and not merely a limitation. Both `gate_read_inner` and `launch_qmatvec_bf16w`
18494    /// already take a row count (the kernel's grid y-dim IS `t`, striding `x` by
18495    /// `x_tstride`), so this is a parameter that was never threaded, not new math: at
18496    /// `rows == 1` the launch arguments are byte-for-byte the ones this function used
18497    /// before, which is what makes the decode path a control rather than a hope.
18498    fn tp2_seg_exit(
18499        &self,
18500        e: &Engine,
18501        ws: &mut StepPool,
18502        ptrs: &CudaSlice<u64>,
18503        gate: &GateW,
18504        planes: &[CudaSlice<f32>],
18505        head_b16: &CudaSlice<u8>,
18506        out_f: usize,
18507        rows: usize,
18508    ) -> Res<()> {
18509        let x = self
18510            .gate_read_inner(e, ws, ptrs, gate, planes, rows, self.exit_eps, false, false)?
18511            .0;
18512        let mut logits = ws.take_f32(e, "logits", rows * out_f, rows * out_f)?;
18513        launch_qmatvec_bf16w(
18514            e,
18515            head_b16,
18516            &x,
18517            &mut logits,
18518            self.hidden,
18519            out_f,
18520            rows,
18521            1,
18522            0,
18523            0,
18524            self.hidden,
18525            0,
18526        )?;
18527        ws.put_f32("hc.mixed", x);
18528        ws.put_f32("logits", logits);
18529        Ok(())
18530    }
18531}
18532
18533/// Launch the count-gated grouped sel matvec (`_v3c`, fixed grid over `max_sel` slots,
18534/// live count from the pack blob). TP2 graph segments only; geometry must admit the
18535/// 4-row kernel (the artifact does).
18536#[allow(clippy::too_many_arguments)]
18537fn launch_nvfp4_sel_matvec_pack(
18538    e: &Engine,
18539    codes: &CudaSlice<u8>,
18540    scales: &CudaSlice<u8>,
18541    macros_dev: &CudaSlice<f32>,
18542    pack_raw: u64,
18543    max_sel: usize,
18544    x: &CudaSlice<f32>,
18545    y: &mut CudaSlice<f32>,
18546    in_f: usize,
18547    out_f: usize,
18548    x_stride: usize,
18549) -> Res<()> {
18550    if in_f % 32 != 0 || out_f % 4 != 0 {
18551        return Err(
18552            "qmatvec_nvfp4_modelopt_sel_f32_v3c: geometry needs in_f%32==0 && out_f%4==0".into(),
18553        );
18554    }
18555    let f = e.func("qmatvec_nvfp4_modelopt_sel_f32_v3c");
18556    let cfg = LaunchConfig {
18557        grid_dim: ((out_f / 4) as u32, max_sel as u32, 1),
18558        block_dim: (32, 1, 1),
18559        shared_mem_bytes: 0,
18560    };
18561    let (inf, outf, ms) = (in_f as i32, out_f as i32, max_sel as i32);
18562    let xs = x_stride as i64;
18563    let stream = e.gpu.stream();
18564    let mut b = stream.launch_builder(&f);
18565    b.arg(codes)
18566        .arg(scales)
18567        .arg(macros_dev)
18568        .arg(&pack_raw)
18569        .arg(&ms)
18570        .arg(x)
18571        .arg(y)
18572        .arg(&inf)
18573        .arg(&outf)
18574        .arg(&xs);
18575    unsafe {
18576        b.launch(cfg)?;
18577    }
18578    Ok(())
18579}
18580
18581fn launch_axpy_rows_seq_pack(
18582    e: &Engine,
18583    x: &CudaSlice<f32>,
18584    pack_raw: u64,
18585    max_sel: usize,
18586    y: &mut CudaSlice<f32>,
18587    width: usize,
18588) -> Res<()> {
18589    let f = e.func("axpy_rows_seq_pack_f32");
18590    let cfg = LaunchConfig::for_num_elems(width as u32);
18591    let (ms, wi) = (max_sel as i32, width as i32);
18592    let stream = e.gpu.stream();
18593    let mut b = stream.launch_builder(&f);
18594    b.arg(x).arg(&pack_raw).arg(&ms).arg(y).arg(&wi);
18595    unsafe {
18596        b.launch(cfg)?;
18597    }
18598    Ok(())
18599}
18600
18601/// Build the pack blob: [max_sel i32 sel padded][max_sel f32 w padded][i32 count].
18602fn tp2_pack_bytes(sel: &[i32], w: &[f32], max_sel: usize) -> Vec<u8> {
18603    let mut out = Vec::with_capacity((2 * max_sel + 1) * 4);
18604    for i in 0..max_sel {
18605        out.extend_from_slice(&sel.get(i).copied().unwrap_or(0).to_le_bytes());
18606    }
18607    for i in 0..max_sel {
18608        out.extend_from_slice(&w.get(i).copied().unwrap_or(0.0).to_le_bytes());
18609    }
18610    out.extend_from_slice(&(sel.len() as i32).to_le_bytes());
18611    out
18612}
18613
18614impl Qwen4ExpGpu {
18615    /// TP2 segment C (graphable): count-gated routed half over the pack blob + shared
18616    /// add + join push. Card 1 takes its prestaged shared parts ("moe.sh_down"/"moe.g",
18617    /// parked by seg B); card 0 computes its shared half here. Parks the MoE partial in
18618    /// "moe.out".
18619    #[allow(clippy::too_many_arguments)]
18620    fn tp2_seg_c(
18621        &self,
18622        e: &Engine,
18623        ws: &mut StepPool,
18624        gate: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
18625        up: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
18626        down: (&CudaSlice<u8>, &CudaSlice<u8>, &CudaSlice<f32>),
18627        ff: usize,
18628        max_sel: usize,
18629        shared_compute: Option<(
18630            &CudaSlice<u8>,
18631            &CudaSlice<u8>,
18632            Option<&CudaSlice<f32>>,
18633            usize,
18634        )>,
18635        shared_gated: bool,
18636        push_raw: u64,
18637    ) -> Res<()> {
18638        let hidden = self.hidden;
18639        let pack_raw = {
18640            let pack = ws.peek_u8("moe.pack")?;
18641            let stream = e.gpu.stream();
18642            pack.device_ptr(&stream).0
18643        };
18644        let mixed = ws.take_f32(e, "hc.mixed", hidden, 0)?;
18645        let mut act = ws.take_f32(e, "moe.act", max_sel * ff, 0)?;
18646        // Fused gate+up+silu (round 4, count-gated pack mode): the capture bakes the
18647        // live arm; dead slots (>= live count) retire at the first instruction and the
18648        // count-gated down/axpy never read them. Bit-identical to the chain per slot.
18649        if sel_gufuse_on() && hidden % 32 == 0 && ff % 4 == 0 {
18650            launch_nvfp4_sel_gu_silu(
18651                e, gate, up, None, pack_raw, max_sel, &mixed, &mut act, hidden, ff, None,
18652            )?;
18653        } else {
18654            let mut yg = ws.take_f32(e, "moe.yg", max_sel * ff, 0)?;
18655            let mut yu = ws.take_f32(e, "moe.yu", max_sel * ff, 0)?;
18656            launch_nvfp4_sel_matvec_pack(
18657                e, gate.0, gate.1, gate.2, pack_raw, max_sel, &mixed, &mut yg, hidden, ff, 0,
18658            )?;
18659            launch_nvfp4_sel_matvec_pack(
18660                e, up.0, up.1, up.2, pack_raw, max_sel, &mixed, &mut yu, hidden, ff, 0,
18661            )?;
18662            e.silu_mul(&yg, &yu, &mut act, max_sel * ff)?;
18663            ws.put_f32("moe.yg", yg);
18664            ws.put_f32("moe.yu", yu);
18665        }
18666        let mut partial = ws.take_f32(e, "moe.partial", max_sel * hidden, 0)?;
18667        launch_nvfp4_sel_matvec_pack(
18668            e,
18669            down.0,
18670            down.1,
18671            down.2,
18672            pack_raw,
18673            max_sel,
18674            &act,
18675            &mut partial,
18676            ff,
18677            hidden,
18678            ff,
18679        )?;
18680        let mut r = ws.take_f32(e, "moe.out", hidden, 0)?;
18681        launch_axpy_rows_seq_pack(e, &partial, pack_raw, max_sel, &mut r, hidden)?;
18682        ws.put_f32("moe.act", act);
18683        ws.put_f32("moe.partial", partial);
18684        let (sh, g) = match shared_compute {
18685            Some((gu_b16, d_b16, ig, sffh)) => {
18686                self.tp2_shared_half(e, ws, gu_b16, d_b16, ig, &mixed, sffh, 1)?
18687            }
18688            None => {
18689                let sh = ws.take_f32(e, "moe.sh_down", hidden, 0)?;
18690                let g = if shared_gated {
18691                    Some(ws.take_f32(e, "moe.g", 1, 0)?)
18692                } else {
18693                    None
18694                };
18695                (sh, g)
18696            }
18697        };
18698        match g.as_ref() {
18699            Some(g) => e.add_scaled_rows(&sh, g, &mut r, hidden, 1)?,
18700            None => {
18701                let mut view = r.slice_mut(0..hidden);
18702                e.axpy_into(&sh, 1.0, &mut view, hidden)?;
18703            }
18704        }
18705        ws.put_f32("moe.sh_down", sh);
18706        if let Some(g) = g {
18707            ws.put_f32("moe.g", g);
18708        }
18709        launch_push(e, &r, push_raw, hidden)?;
18710        ws.put_f32("moe.out", r);
18711        ws.put_f32("hc.mixed", mixed);
18712        Ok(())
18713    }
18714
18715    /// TP2 segment D (graphable): MoE join add (SAME rank order both cards) + gate_write.
18716    #[allow(clippy::too_many_arguments)]
18717    fn tp2_seg_d(
18718        &self,
18719        e: &Engine,
18720        ws: &mut StepPool,
18721        ptrs: &CudaSlice<u64>,
18722        planes: &mut [CudaSlice<f32>],
18723        stage_recv: &CudaSlice<f32>,
18724        rank0: bool,
18725    ) -> Res<()> {
18726        let hidden = self.hidden;
18727        let mp = ws.take_f32(e, "moe.out", hidden, 0)?;
18728        let mut mo = ws.take_f32(e, "join.out", hidden, 0)?;
18729        if rank0 {
18730            e.add(&mp, stage_recv, &mut mo, hidden)?;
18731        } else {
18732            e.add(stage_recv, &mp, &mut mo, hidden)?;
18733        }
18734        let injm = take_inject(e, ws, self.streams, 1)?;
18735        self.gate_write(e, planes, ptrs, &mo, &injm, 1)?;
18736        ws.put_f32("moe.out", mp);
18737        ws.put_f32("join.out", mo);
18738        put_inject(ws, injm);
18739        Ok(())
18740    }
18741}