spark_model/weight_loader/
qwen35_dense.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2
3use anyhow::Result;
4use atlas_core::config::{LayerType, ModelConfig};
5use spark_runtime::gpu::GpuBackend;
6use spark_runtime::kv_cache::KvCacheDtype;
7use spark_runtime::weights::{WeightDtype, WeightStore};
8
9use super::{ModelWeightLoader, WeightFormat};
10use crate::layer::TransformerLayer;
11use crate::layers::{DenseFfnLayer, FfnComponent, Qwen3AttentionLayer, Qwen3SsmLayer};
12use crate::tp_shard::{
13    TpGdnDims, TpShardKind, load_qkvo_tp, shard_dense_bf16, shard_gdn_ba_rows, shard_gdn_conv_rows,
14    shard_gdn_out_proj_row_parallel, shard_gdn_qkvz_rows, shard_gdn_value_vector,
15    shard_quantized_nvfp4,
16};
17use crate::weight_map::{
18    AttentionWeights, DenseWeight, Fp8Weight, MtpWeights, Nvfp4Variant, PackedQ2Weight, SsmWeights,
19    dense, dense_auto, dense_f32_safe, dense_keep_f32, dequant_nvfp4_to_bf16, detect_nvfp4_variant,
20    gpu_concat_rows, interleave_ba, load_dense_ffn, load_fp8_block_scaled_as_fp8weight,
21    load_kv_scales, load_mtp, quantize_to_nvfp4, quantized_auto,
22};
23
24/// True when `{prefix}.weight` is FP8 E4M3 on disk with a 2D block scale
25/// (`weight_scale_inv` or 2D `weight_scale`) — i.e. a native FP8 checkpoint
26/// projection that should load as `Fp8Weight` rather than be requantized to
27/// NVFP4. Mirrors `qwen35::load_layers::proj_is_native_fp8`.
28/// The Q2_0 group size if `{prefix}.weight` is a keep-packed ternary tensor
29/// (`WeightDtype::PackedQ2_0`, produced by the GGUF loader under
30/// `ATLAS_GGUF_NATIVE_Q2=1`), else `None`. When `None` for every projection the
31/// FFN takes the unchanged BF16→NVFP4 path, so the default (flag-off) behavior
32/// is byte-identical.
33fn proj_q2_group(store: &WeightStore, prefix: &str) -> Option<u16> {
34    store
35        .get(&format!("{prefix}.weight"))
36        .ok()
37        .and_then(|w| w.q2_group())
38}
39
40/// Build a [`PackedQ2Weight`] borrowing the store's packed `block_q2_0` buffer.
41/// The buffer is owned by the `WeightStore` (freed with it), so this only wraps
42/// the pointer + `[n, k]` + group; no dequant, no allocation.
43fn packed_q2_from_store(store: &WeightStore, prefix: &str) -> Result<PackedQ2Weight> {
44    let w = store.get(&format!("{prefix}.weight"))?;
45    let group = w
46        .q2_group()
47        .ok_or_else(|| anyhow::anyhow!("{prefix}.weight is not keep-packed Q2_0"))?;
48    anyhow::ensure!(
49        w.shape.len() == 2,
50        "packed Q2_0 {prefix}.weight must be 2D, got {:?}",
51        w.shape
52    );
53    Ok(PackedQ2Weight {
54        weight: w.ptr,
55        n: w.shape[0] as u32,
56        k: w.shape[1] as u32,
57        group,
58    })
59}
60
61fn proj_is_native_fp8(store: &WeightStore, prefix: &str) -> bool {
62    let is_fp8_weight = store
63        .get(&format!("{prefix}.weight"))
64        .map(|w| w.dtype == WeightDtype::FP8E4M3)
65        .unwrap_or(false);
66    let has_block_scale = store.contains(&format!("{prefix}.weight_scale_inv"))
67        || store
68            .get(&format!("{prefix}.weight_scale"))
69            .map(|s| s.shape.len() == 2)
70            .unwrap_or(false);
71    is_fp8_weight && has_block_scale
72}
73
74/// True when `{prefix}.weight` is on-disk FP8 with a scale the native-FP8
75/// `w8a16` path can actually consume — i.e. one that is (or broadcasts to) the
76/// `[ceil(N/128), ceil(K/128)]` FP32 block grid the kernel indexes as
77/// `block_scale[n/128, k/128]`:
78///
79///   * `weight_scale_inv` / 2-D `weight_scale` shaped as that block grid
80///     (DeepSeek-V3 / Qwen-native convention), or
81///   * a per-tensor SCALAR `weight_scale` (ModelOpt; e.g. the nvidia
82///     Qwen3.6-27B-NVFP4 GDN projections) — `load_fp8_block_scaled_as_fp8weight`
83///     broadcasts it into a uniform grid, which is exact.
84///
85/// A **per-row** `weight_scale` (`[N,1]`, e.g. unsloth's re-quantized
86/// Qwen3.6-*-NVFP4, 2026-07-10) is deliberately REJECTED. It is not a block
87/// grid: the kernel would read row `n`'s multiplier from grid cell `n/128`, so
88/// 127 of every 128 rows get some other row's scale. That is in-bounds — the
89/// widened `[N]` buffer is *larger* than the `[N/128, K/128]` grid — so it does
90/// not fault; it silently produces garbage logits. Returning false here drops
91/// the projection to the default `dequant_fp8_blockscaled_to_bf16` →
92/// `quantize_to_nvfp4` path, which reads a `[N,1]` scale correctly
93/// (`block_n = N/N = 1`, i.e. one multiplier per row).
94fn proj_is_fp8_any_scale(store: &WeightStore, prefix: &str) -> bool {
95    let Ok(w) = store.get(&format!("{prefix}.weight")) else {
96        return false;
97    };
98    if w.dtype != WeightDtype::FP8E4M3 || w.shape.len() != 2 {
99        return false;
100    }
101    let (n, k) = (w.shape[0], w.shape[1]);
102
103    for key in [
104        format!("{prefix}.weight_scale_inv"),
105        format!("{prefix}.weight_scale"),
106    ] {
107        let Ok(s) = store.get(&key) else { continue };
108        // Per-tensor scalar → broadcast to a uniform grid: exact.
109        if s.num_elements() == 1 {
110            return true;
111        }
112        // 2-D scale: only a genuine 128×128 block grid is consumable.
113        if s.shape.len() == 2 && s.shape[0] == n.div_ceil(128) && s.shape[1] == k.div_ceil(128) {
114            return true;
115        }
116    }
117    false
118}
119
120/// Concatenate two block-scaled FP8 weights along rows (dim 0):
121/// `[n_a, k] ++ [n_b, k] -> [n_a+n_b, k]`. FP8 bytes (1 B/elem) and the
122/// `[n/128, k/128]` FP32 block-scale grids are contiguous row-major, so each is
123/// a straight device-to-device append. Requires `n_a % 128 == 0` so the
124/// scale-grid rows meet at a block boundary (GDN qkv rows are a multiple of
125/// 128). Produces the `[Q|K|V|Z]` sequential order the SSM layer expects.
126fn concat_fp8_block_scaled(
127    a: &Fp8Weight,
128    b: &Fp8Weight,
129    k: usize,
130    gpu: &dyn GpuBackend,
131) -> Result<Fp8Weight> {
132    let kb = k.div_ceil(128);
133    let a_w = a.n as usize * k;
134    let b_w = b.n as usize * k;
135    let weight = gpu.alloc(a_w + b_w)?;
136    gpu.copy_d2d(a.weight, weight, a_w)?;
137    gpu.copy_d2d(b.weight, weight.offset(a_w), b_w)?;
138    let a_s = (a.n as usize).div_ceil(128) * kb * 4;
139    let b_s = (b.n as usize).div_ceil(128) * kb * 4;
140    let row_scale = gpu.alloc(a_s + b_s)?;
141    gpu.copy_d2d(a.row_scale, row_scale, a_s)?;
142    gpu.copy_d2d(b.row_scale, row_scale.offset(a_s), b_s)?;
143    Ok(Fp8Weight {
144        weight,
145        row_scale,
146        n: a.n + b.n,
147        k: k as u32,
148        scale_format: crate::weight_map::WeightQuantFormat::Fp8BlockScaled,
149    })
150}
151
152/// Opt-in gate for native dense-FP8 attention + FFN dispatch (Qwythos / dense
153/// Ornith-FP8). Default OFF.
154///
155/// VERIFIED 2026-06-29 on Qwythos-9B-FP8 (gb10/ornith-1.0-9b): with the flag
156/// on, the FP8 arms fire for all 32 FFN + 8 full-attn layers and text is
157/// correct (coherence/fib/tools 3/3). BUT it is NOT a perf win — ~30 tok/s vs
158/// ~40 for the NVFP4 fallback — because this target's NVFP4 W4A16 kernels
159/// (fused dual-GEMV decode, transposed m128 prefill) are more optimized than
160/// its FP8 W8A16 kernels (unfused per-projection GEMV, non-transposed
161/// `w8a16_gemm` prefill; the attention FP8 prefill transpose also does not
162/// engage). Vision prefill additionally hits a CUDA-700. Making FP8 pay off
163/// here needs dedicated dense-FP8 kernels (fused FP8 dual-GEMV + fast
164/// transposed FP8 prefill GEMM), not loader wiring. Until then NVFP4 autoquant
165/// is the better dense runtime. `ATLAS_DENSE_FP8=1` opts in for that kernel work.
166fn dense_fp8_enabled() -> bool {
167    std::env::var("ATLAS_DENSE_FP8").as_deref() == Ok("1")
168}
169
170/// Whether the native block-scaled FP8 GDN arm runs for this SSM layer.
171///
172/// ONE predicate, called by `load_layers` and by `prune_after_load`: the
173/// second frees the store tensors the first copied into the fused `[QKV|Z]`
174/// weight, and a drift between the two is a use-after-free with no
175/// diagnostic. The keep-packed Q2 arm `continue`s ahead of this one, so it is
176/// part of the condition (#915).
177fn gdn_fp8_arm_selected(store: &WeightStore, la: &str, tp_size: usize) -> bool {
178    let q2 = tp_size.max(1) == 1
179        && std::env::var_os("ATLAS_NO_Q2_GDN").is_none()
180        && proj_q2_group(store, &format!("{la}.in_proj_qkv")).is_some()
181        && proj_q2_group(store, &format!("{la}.in_proj_z")).is_some();
182    !q2 && std::env::var_os("ATLAS_NO_GDN_FP8").is_none()
183        && proj_is_fp8_any_scale(store, &format!("{la}.in_proj_qkv"))
184        && proj_is_fp8_any_scale(store, &format!("{la}.in_proj_z"))
185        && proj_is_fp8_any_scale(store, &format!("{la}.out_proj"))
186}
187
188/// The dense-FFN width. `moe_intermediate_size` is the PER-EXPERT width and is
189/// unset (=0) on dense Qwen3.6/3.8-*-FP8, so reading it first would size a
190/// 0-byte allocation; `intermediate_size` is unset on the older MoE-style
191/// configs. Same fallback order as `weight_map/fp8_lut.rs::load_dense_ffn`.
192fn ffn_inter(config: &ModelConfig) -> usize {
193    if config.intermediate_size > 0 {
194        config.intermediate_size
195    } else {
196        config.moe_intermediate_size
197    }
198}
199
200/// Whether the native-FP8 dense-FFN overlay runs for THIS layer.
201///
202/// The condition `load_layers` applied inline before `prune_after_load` needed
203/// the same answer. Pure — a function of the store, the config and the
204/// detected variant — so the two sites cannot drift, which is the failure a
205/// prune predicate must not have: freeing a store tensor a layer still aliases
206/// is a use-after-free with no diagnostic.
207fn ffn_fp8_arm_selected(
208    store: &WeightStore,
209    config: &ModelConfig,
210    variant: Nvfp4Variant,
211    lp: &str,
212) -> bool {
213    dense_fp8_enabled()
214        && config.tp_world_size.max(1) == 1
215        && matches!(variant, Nvfp4Variant::Fp8Dequanted)
216        && proj_is_native_fp8(store, &format!("{lp}.mlp.gate_proj"))
217}
218
219/// Whether THIS layer's gate and up are fused into one `[2*inter, hidden]`
220/// block-scaled FP8 weight (#927).
221///
222/// Beyond the FP8 overlay itself: the target must arm the arm (`[defaults]
223/// ffn_gateup_fused`), the model must be DENSE (a MoE config has no
224/// `ffn_gate_up_fused` arena buffer and never reaches the dense-FFN path), and
225/// both extents must be whole 128-blocks — `concat_fp8_block_scaled` appends
226/// the `[N/128, K/128]` scale grids, which is only the fused grid when the
227/// seam falls on a block boundary (`ceil` of a sum is not the sum of `ceil`s).
228///
229/// The SECOND caller is `prune_after_load`, which releases exactly the store
230/// tensors this returned true for. Rule and the receipt:
231/// `layers/dense_ffn_gateup_fused.rs`.
232fn ffn_gateup_fused_selected(
233    store: &WeightStore,
234    config: &ModelConfig,
235    variant: Nvfp4Variant,
236    lp: &str,
237) -> bool {
238    let inter = ffn_inter(config);
239    let hidden = config.hidden_size;
240    // The CONFIG's widths are what the ledger terms, the prediction and the
241    // view offsets are all computed from, so a checkpoint whose tensors
242    // disagree with them must DECLINE rather than be concatenated at the wrong
243    // stride. Checked here and not at the call site because `prune_after_load`
244    // asks this same question and frees on the answer: a predicate the loader
245    // narrows locally is a store tensor freed out from under a live view.
246    let on_disk = |name: &str| {
247        store
248            .get(&format!("{lp}.mlp.{name}.weight"))
249            .is_ok_and(|w| w.shape == [inter, hidden])
250    };
251    ffn_fp8_arm_selected(store, config, variant, lp)
252        && crate::layers::dense_ffn::gateup_fused::ffn_gateup_fused()
253        && config.num_experts == 0
254        && inter > 0
255        && inter.is_multiple_of(128)
256        && hidden.is_multiple_of(128)
257        && on_disk("gate_proj")
258        && on_disk("up_proj")
259}
260
261// `pub` (re-exported from `weight_loader/mod.rs`): the pre-load residency
262// PREDICTION in `predicted_residency` is read by spark-server's preflight,
263// and it prices its terms with this module's shape helpers so the prediction
264// and the loader's own tally cannot be two different arithmetics (#915).
265pub mod fp8_residency;
266mod loaders_b;
267pub mod predicted_residency;
268mod rowwise_fp8;
269
270use crate::layers::qwen3_attention::Fp8TwinSet;
271use fp8_residency::{DerivedResidency, RouteEnv};
272
273pub struct Qwen35DenseWeightLoader;
274
275impl ModelWeightLoader for Qwen35DenseWeightLoader {
276    fn supports_tp(&self) -> bool {
277        // FullAttention layers are TP-sharded (NVFP4-from-disk and BF16
278        // → NVFP4 paths). LinearAttention (GDN SSM) layers run
279        // full-replica per rank — see qwen35.rs for the rationale.
280        true
281    }
282
283    fn load_layers(
284        &self,
285        store: &WeightStore,
286        config: &ModelConfig,
287        gpu: &dyn GpuBackend,
288        layer_kv_dtypes: &[KvCacheDtype],
289    ) -> Result<Vec<Box<dyn TransformerLayer>>> {
290        let layer_types = if config.layer_types.is_empty() {
291            (0..config.num_hidden_layers)
292                .map(|i| config.layer_type(i))
293                .collect::<Vec<_>>()
294        } else {
295            config.layer_types.clone()
296        };
297
298        let mut layers: Vec<Box<dyn TransformerLayer>> =
299            Vec::with_capacity(config.num_hidden_layers);
300        let mut attn_idx = 0usize;
301
302        let absmax_k = gpu.kernel("quantize_nvfp4", "nvfp4_global_absmax")?;
303        let quantize_k = gpu.kernel("quantize_nvfp4", "quantize_bf16_to_nvfp4")?;
304        let stream = gpu.default_stream();
305        let h = config.hidden_size;
306
307        let variant = detect_nvfp4_variant(store, config);
308        let weight_format = WeightFormat::detect(store, config);
309        tracing::info!(
310            "Weight format: {:?}, NVFP4 variant: {:?}",
311            weight_format,
312            variant
313        );
314
315        // Native FP8 SSM prefill GEMM (Qwen3.6-27B-FP8 root-cause fix,
316        // commit 3ebc08a). Atlas's prior SSM in_proj_qkv path was
317        // FP8 → BF16 → NVFP4 → BF16 (in `w4a16_gemm` dequant) → MMA — a
318        // double-quant chain whose NVFP4 hop's ~4-bit per-group precision
319        // is dominated by signal at q/v but attenuated into a k-direction
320        // error (HF conv-k ‖6.3‖ vs conv-v ‖117.2‖, ~18× smaller). For
321        // every FP8-on-disk checkpoint we install a single-scale FP8 copy
322        // of the stacked `[QKV|Z]` and `out_proj` weights for prefill,
323        // bypassing the NVFP4 intermediate. Prefill dispatches via the
324        // existing `fp8_gemm_n128` (BF16 act × FP8 weight) — same path
325        // the MoE shared-expert FP8 prefill uses. Decode/GEMV unchanged.
326        // Originally env-gated `ATLAS_FP8_SSM_PREFILL=1`; promoted to
327        // unconditional 2026-05-20 after live verification (commit
328        // dfb4e8a era, tokens_to_first_degeneration 1,196 → 16,968).
329        // 2026-07-03 precision policy: GDN projections stay ≥FP8 — the
330        // NVFP4 requant of qkvz/out_proj flattens tensors that both
331        // checkpoint toolchains deliberately keep high-precision (modelopt
332        // sensitivity analysis ships them FP8; unsloth ships BF16). Applies
333        // to ALL NVFP4 variants now, not just Fp8Dequanted. Kill-switch
334        // ATLAS_NO_GDN_FP8_PREFILL restores the pre-policy behavior for A/B.
335        let fp8_ssm_prefill = std::env::var_os("ATLAS_NO_GDN_FP8_PREFILL").is_none();
336        let bf16_to_fp8_k = if fp8_ssm_prefill {
337            tracing::info!(
338                // The old wording — "NVFP4 kept as structural fallback for
339                // decode batch paths" — was DISPROVEN by nsys at C=8
340                // (2026-08-17): the batched verify QKVZ was taking this FP8
341                // copy at every M>8, 26.3% of the step. It is true again only
342                // because that arm now reads NVFP4; say the actual rule so the
343                // log cannot re-drift from the dispatch.
344                "SSM in_proj_qkv + out_proj via native FP8 prefill GEMM \
345                 (BF16 act × FP8 weight via fp8_gemm_n128). PREFILL ONLY: \
346                 decode + batched verify read the NVFP4 copy — weight-streaming \
347                 GEMV at M<=8, tile GEMM above it (trait_decode_batched.rs). \
348                 The FP8 copy reaches decode only at M<=8 on a build whose \
349                 batched NVFP4 GEMVs are absent"
350            );
351            Some(gpu.kernel("w4a16", "bf16_to_fp8")?)
352        } else {
353            None
354        };
355
356        // ATLAS_MEM_PROFILE: per-phase GPU-free trace to pin the strix/APU
357        // load-time footprint (FP8-source persistence vs NVFP4 steady-state vs
358        // BF16 requant transients). Gated env so it's a no-op in production.
359        let mem_profile = std::env::var("ATLAS_MEM_PROFILE").is_ok();
360        let log_free = |tag: &str| {
361            if mem_profile && let Ok(free) = gpu.free_memory() {
362                tracing::info!("MEM_PROFILE[{tag}]: {:.2} GB GPU-free", free as f64 / 1e9);
363            }
364        };
365        log_free("dense-load-start");
366
367        // #915: resolved ONCE, from the same resolvers the forward pass uses —
368        // the loader runs before `ForwardContext` exists. Contract and WHY:
369        // `fp8_residency.rs`.
370        let route_env = RouteEnv::from_env();
371        let mut residency = DerivedResidency::default();
372
373        for (i, lt) in layer_types.iter().enumerate() {
374            if i % 8 == 0 {
375                log_free(&format!("layer-{i}"));
376            }
377            let lp = config.layer_prefix(i);
378            let input_norm = dense(store, &format!("{lp}.input_layernorm.weight"))?;
379            let post_attn_norm = dense(store, &format!("{lp}.post_attention_layernorm.weight"))?;
380
381            // Dense FFN instead of MoE. Native FP8 checkpoints (single-GPU)
382            // load gate/up/down directly as block-scaled `Fp8Weight` and
383            // dispatch w8a16 — no NVFP4 requant. TP>1 still uses the NVFP4
384            // path (FP8 FFN sharding is a follow-up).
385            let ffn_fp8 = ffn_fp8_arm_selected(store, config, variant, &lp);
386            // 2026-09-11 (#915), replacing "always load the NVFP4 weights so
387            // every dispatch path has a valid weight to fall back to": there is
388            // no such path any more. `forward_k2`/`k3`/`km` redirect to
389            // `forward_prefill` whenever an FP8 overlay is installed
390            // (`native_small_batch_uses_prefill`), and both `forward` and
391            // `forward_prefill_inner` return from inside their `fp8_weights`
392            // arm. Building the fallback cost 18.4 GiB on Qwen3.8-27B-FP8 that
393            // nothing could read. The CUDA-700-at-concurrency hazard the old
394            // rule guarded is real and is why this is decided by
395            // `fp8_residency.rs` rather than inline: a NULL NVFP4 weight is
396            // only sound when the plan proves no w4a16 dispatch is reachable.
397            // Native-BF16 dense-FFN prefill (Holo/Ornith Bf16Raw): the fast
398            // tensor-core `dense_gemm_tc` path (dense_ffn::forward_prefill) needs
399            // LIVE BF16 gate/up/down. `load_dense_ffn`'s Bf16Raw arm runtime-
400            // quantizes each proj via `quantized_any`, whose Bf16Raw branch
401            // FREES the store's cached BF16 buffer (`gpu.free(w.ptr)` in
402            // nvfp4_detect.rs:288-309, the Bf16Raw arm). `dense_auto` returns that
403            // SAME (now-freed) store ptr for a BF16 tensor — quant_helpers.rs:290
404            // hands back `w.ptr` uncopied — so overlaying it AFTER load_dense_ffn hands
405            // `set_bf16_weights` freed GPU memory -> dense_gemm_tc CUDA-700 at
406            // grid=[div_ceil(intermediate_size,64),..] on the first prefill.
407            // Snapshot fresh D2D copies BEFORE the free (the clone is an
408            // independent allocation the layer owns for its lifetime).
409            // Native keep-packed ternary Q2_0 (ATLAS_GGUF_NATIVE_Q2=1): when the
410            // GGUF loader tagged gate/up/down as `PackedQ2_0`, DON'T requant to
411            // NVFP4 — install the raw 2-bit blocks and dispatch `q2_0_gemv` at
412            // decode. Requires tp_size=1 (packed-block sharding is unimplemented).
413            // Flag off → tensors are BF16, `ffn_q2` is false, path unchanged.
414            let ffn_q2 = config.tp_world_size.max(1) == 1
415                && proj_q2_group(store, &format!("{lp}.mlp.gate_proj")).is_some()
416                && proj_q2_group(store, &format!("{lp}.mlp.up_proj")).is_some()
417                && proj_q2_group(store, &format!("{lp}.mlp.down_proj")).is_some();
418            // Keep-packed projections are 2-bit blocks, not BF16 — there is
419            // nothing to snapshot (dense_auto has no PackedQ2_0 arm and would
420            // abort the load), and the ffn_q2 arm below owns their compute.
421            let ffn_bf16_snapshot = if !ffn_q2 && matches!(variant, Nvfp4Variant::Bf16Raw) {
422                let inter = if config.intermediate_size > 0 {
423                    config.intermediate_size
424                } else {
425                    config.moe_intermediate_size
426                };
427                let clone_bf16 = |name: &str, rows: usize, cols: usize| -> Result<DenseWeight> {
428                    let src = dense_auto(store, &format!("{lp}.mlp.{name}.weight"), gpu)?;
429                    let bytes = rows * cols * 2; // BF16 = 2 bytes/elem
430                    let dst = gpu.alloc(bytes)?;
431                    // The whole point of this snapshot is an allocation
432                    // INDEPENDENT of the store's cached ptr (which load_dense_ffn
433                    // frees below); an aliased dst would silently re-create the
434                    // freed-memory CUDA-700 this helper exists to prevent.
435                    debug_assert_ne!(
436                        dst, src.weight,
437                        "ffn_bf16_snapshot must be a fresh allocation, not an alias of the store ptr"
438                    );
439                    gpu.copy_d2d(src.weight, dst, bytes)?;
440                    Ok(DenseWeight { weight: dst })
441                };
442                Some((
443                    clone_bf16("gate_proj", inter, h)?,
444                    clone_bf16("up_proj", inter, h)?,
445                    clone_bf16("down_proj", h, inter)?,
446                ))
447            } else {
448                None
449            };
450
451            // #915: the NVFP4 gate/up/down fallback and its transposed twins
452            // are 18.4 GiB on Qwen3.8-27B-FP8 that NO native-FP8 dispatch can
453            // reach — every `DenseFfnLayer` entry point returns from inside its
454            // `self.fp8_weights` arm and `w8_gemm!` binds the transposed
455            // operand to a literal `None`. The comment above ("always load the
456            // NVFP4 weights ... the rare batched paths fall back to real
457            // NVFP4") described the pre-#927 dispatch; `forward_k2`/`k3`/`km`
458            // have redirected to `forward_prefill` since
459            // `native_small_batch_uses_prefill` landed. Decision table and the
460            // loader-runs-before-dispatch contract: `fp8_residency.rs`.
461            let plan = route_env.plan(ffn_fp8, false, false);
462            let ffn_nvfp4 = !ffn_q2 && plan.ffn_nvfp4;
463            let ffn_weights = if ffn_nvfp4 {
464                load_dense_ffn(
465                    store, &lp, gpu, variant, absmax_k, quantize_k, stream, config,
466                )?
467            } else {
468                // NULL NVFP4 fallback. Packed-Q2 (Tier-1c): decode uses the
469                // packed weights; prefill / batched paths bail (Tier-2).
470                // Native FP8: every arm reads the E4M3 bytes installed by
471                // `set_fp8_weights` below. No NVFP4 allocation → memory win.
472                if ffn_fp8 {
473                    residency.skip(fp8_residency::dense_ffn_nvfp4_bytes(h, ffn_inter(config)));
474                }
475                use crate::weight_map::QuantizedWeight;
476                crate::layers::dense_ffn::DenseFfnWeights {
477                    gate_proj: QuantizedWeight::null(),
478                    up_proj: QuantizedWeight::null(),
479                    down_proj: QuantizedWeight::null(),
480                    gate_proj_t: None,
481                    up_proj_t: None,
482                    down_proj_t: None,
483                }
484            };
485            residency.twins.ffn_nvfp4 |= ffn_nvfp4;
486            let mut dffn = DenseFfnLayer::new(ffn_weights, gpu)?;
487            if ffn_q2 {
488                dffn.set_q2_weights(
489                    packed_q2_from_store(store, &format!("{lp}.mlp.gate_proj"))?,
490                    packed_q2_from_store(store, &format!("{lp}.mlp.up_proj"))?,
491                    packed_q2_from_store(store, &format!("{lp}.mlp.down_proj"))?,
492                    gpu,
493                );
494            }
495            if ffn_fp8 {
496                // The FP8 `.weight` bytes are store-owned (zero-copy from the
497                // checkpoint); only the widened FP32 block-scale grid is a
498                // fresh allocation (`loaders_fp8.rs:109`). Adopt it — #736
499                // lists the loader sites that allocate without an owner.
500                let load_ffn_fp8 = |name: &str| -> Result<Fp8Weight> {
501                    let w = load_fp8_block_scaled_as_fp8weight(
502                        store,
503                        &format!("{lp}.mlp.{name}"),
504                        gpu,
505                    )?;
506                    let bytes = (w.n as usize).div_ceil(128) * (w.k as usize).div_ceil(128) * 4;
507                    store
508                        .derived()
509                        .adopt("ffn fp8 block scale (widened)", w.row_scale, bytes);
510                    Ok(w)
511                };
512                let mut gate = load_ffn_fp8("gate_proj")?;
513                let mut up = load_ffn_fp8("up_proj")?;
514                let down = load_ffn_fp8("down_proj")?;
515                // FUSED gate+up (#927). ONE `[2*inter, hidden]` E4M3 buffer
516                // and ONE `[2*inter/128, hidden/128]` FP32 scale grid, with
517                // `gate` and `up` re-pointed at VIEWS inside them — so the
518                // fused decode GEMM and every un-fused rung of `w8_gemm!` read
519                // the SAME bytes and neither needs a second copy.
520                //
521                // RESIDENCY IS NET ZERO, and that is the whole design
522                // constraint: a second copy is 178.3 MB x 64 layers = 11.4 GB,
523                // straight out of the bs32 KV budget. `prune_after_load`
524                // releases the two source store tensors this copied
525                // (`{lp}.mlp.{gate,up}_proj.weight` + their scale tensors),
526                // exactly as the SSM `[QKV|Z]` concat above has done since
527                // #915, and `predicted_residency` prices the pair at zero for
528                // the preflight ring fit.
529                let inter = ffn_inter(config);
530                let fused = if ffn_gateup_fused_selected(store, config, variant, &lp) {
531                    let fused = concat_fp8_block_scaled(&gate, &up, h, gpu)?;
532                    let (w_bytes, s_bytes) = fp8_residency::ffn_gateup_fused_parts(h, inter);
533                    // The concat COPIED both widened grids, so the two
534                    // per-projection allocations are dead. They were adopted a
535                    // few lines up; disown before freeing, or teardown frees
536                    // them a second time.
537                    let d = store.derived();
538                    let grid = inter.div_ceil(128) * h.div_ceil(128) * 4;
539                    for ptr in [gate.row_scale, up.row_scale] {
540                        d.disown(ptr);
541                        gpu.free(ptr)?;
542                    }
543                    residency.free(2 * grid);
544                    // The views. `gate` is the fused buffer's head and `up`
545                    // starts one `[inter, hidden]` block in; the scale grids
546                    // meet at the same boundary because `inter % 128 == 0` is
547                    // a clause of the selector above.
548                    gate.weight = fused.weight;
549                    gate.row_scale = fused.row_scale;
550                    up.weight = fused.weight.offset(inter * h);
551                    up.row_scale = fused.row_scale.offset(grid);
552                    d.adopt("ffn gate+up fp8 concat", fused.weight, w_bytes);
553                    d.adopt("ffn gate+up fp8 block scale", fused.row_scale, s_bytes);
554                    residency.keep(w_bytes + s_bytes);
555                    residency.twins.ffn_gateup_fused = true;
556                    Some(fused)
557                } else {
558                    None
559                };
560                dffn.set_fp8_weights(gate, up, down);
561                if let Some(fused) = fused {
562                    dffn.set_fp8_gate_up_fused(fused);
563                }
564            }
565            // ATLAS_FFN_MMQ: eagerly materialize Q4_K + free the dead `_t` copies at load,
566            // BEFORE KV cache sizing, so net FFN footprint == NVFP4 baseline (no decode OOM-throttle).
567            dffn.finalize_q4k_load(gpu, h as u32, config.intermediate_size as u32, stream)?;
568            // ATLAS_FFN_NVFP4_MMQ: same discipline for the W4A4 FP4-MMQ arm — repack
569            // gate/up to block_nvfp4 + free their `_t` copies (net ~0 footprint).
570            //
571            // SKIPPED when a LoRA adapter is pending. The forward-time FP4-MMQ
572            // arm is disabled while an adapter is installed (it leaves gate/up
573            // UNSCALED and folds weight_scale_2 inside the SiLU-mul, which
574            // would silently scale a true-valued delta). But this finalize
575            // FREES the transposed `_t` copies on the assumption that the MMQ
576            // arm will serve prefill — so running it and then disabling the arm
577            // left prefill on the slowest non-transposed GEMM with nothing to
578            // fall back to: 176 tok/s against 841 on a 2K prompt, and it had
579            // NOTHING to do with the cost of applying the deltas (measured with
580            // the deltas skipped entirely).
581            //
582            // `adapter_max_rank` is the load-time signal that `--lora-adapter`
583            // was given; the adapter itself is installed later (build step 8),
584            // so this is the only point where the decision can be made before
585            // the twins are freed.
586            if config.adapter_max_rank == 0 {
587                dffn.finalize_nvfp4_mmq_load(
588                    gpu,
589                    h as u32,
590                    config.intermediate_size as u32,
591                    stream,
592                )?;
593            }
594            // Native-BF16 dense-FFN overlay (Bf16Raw, no-metadata Holo dense): install the
595            // live BF16 gate/up/down snapshot so forward/forward_prefill's bf16 branch
596            // (preferred over the NVFP4 fallback) reads valid memory. The NVFP4 weights built
597            // by load_dense_ffn stay as the spec-decode/batched fallback (never null -> no
598            // CUDA-700 at concurrency). Snapshot was taken before load_dense_ffn freed the
599            // store's BF16 buffer (see ffn_bf16_snapshot above).
600            if let Some((g, u, d)) = ffn_bf16_snapshot {
601                dffn.set_bf16_weights(g, u, d);
602            }
603            let ffn = FfnComponent::Dense(dffn);
604
605            match lt {
606                LayerType::FullAttention => {
607                    let p = format!("{lp}.self_attn");
608                    let tp_rank = config.tp_rank;
609                    let tp_size = config.tp_world_size.max(1);
610                    // Bf16Raw installs a BF16 dense O-proj after the layer is
611                    // built; other variants leave this None (NVFP4/FP8 dispatch).
612                    let mut o_dense_bf16: Option<DenseWeight> = None;
613
614                    // Native keep-packed ternary Q2_0 (Tier-1c): when the GGUF
615                    // loader tagged q/k/v/o as `PackedQ2_0` (transform-free
616                    // full-attention projections), install the raw 2-bit blocks
617                    // and dispatch `q2_0_gemv_vec` at decode / transient-dequant
618                    // at prefill — no NVFP4 requant, no `_t` copies. Requires
619                    // tp_size=1 (packed-block sharding is unimplemented). Bonsai
620                    // has no kill-switch here; the whole path is gated upstream
621                    // by ATLAS_GGUF_NATIVE_Q2 (else these tensors are BF16 and
622                    // `attn_q2` is false). ATLAS_NO_Q2_ATTN forces the BF16 path
623                    // for A/B bisection.
624                    let attn_q2 = tp_size == 1
625                        && std::env::var_os("ATLAS_NO_Q2_ATTN").is_none()
626                        && proj_q2_group(store, &format!("{p}.q_proj")).is_some()
627                        && proj_q2_group(store, &format!("{p}.k_proj")).is_some()
628                        && proj_q2_group(store, &format!("{p}.v_proj")).is_some()
629                        && proj_q2_group(store, &format!("{p}.o_proj")).is_some();
630                    if attn_q2 {
631                        let (k_scale, v_scale) = load_kv_scales(store, &p, gpu);
632                        let attn = AttentionWeights {
633                            q_proj: DenseWeight {
634                                weight: spark_runtime::gpu::DevicePtr::NULL,
635                            },
636                            k_proj: DenseWeight {
637                                weight: spark_runtime::gpu::DevicePtr::NULL,
638                            },
639                            v_proj: DenseWeight {
640                                weight: spark_runtime::gpu::DevicePtr::NULL,
641                            },
642                            o_proj: crate::weight_map::QuantizedWeight::null(),
643                            q_norm: dense(store, &format!("{p}.q_norm.weight"))?,
644                            k_norm: dense(store, &format!("{p}.k_norm.weight"))?,
645                            q_norm_full: None,
646                            k_norm_full: None,
647                            k_scale,
648                            v_scale,
649                        };
650                        let mut attn_layer = Qwen3AttentionLayer::new(
651                            input_norm,
652                            attn,
653                            post_attn_norm,
654                            ffn,
655                            attn_idx,
656                            None,
657                            None,
658                            None,
659                            gpu,
660                            layer_kv_dtypes[attn_idx],
661                            config.fp8_kv_calibration_tokens,
662                            config,
663                        )?;
664                        attn_layer.set_packed_q2_weights(
665                            packed_q2_from_store(store, &format!("{p}.q_proj"))?,
666                            packed_q2_from_store(store, &format!("{p}.k_proj"))?,
667                            packed_q2_from_store(store, &format!("{p}.v_proj"))?,
668                            packed_q2_from_store(store, &format!("{p}.o_proj"))?,
669                            gpu,
670                        );
671                        tracing::info!(
672                            "ATTN[{lp}] native keep-packed Q2_0: q/k/v/o 2-bit \
673                             (q2_0_gemv_vec decode; transient-dequant prefill)"
674                        );
675                        layers.push(Box::new(attn_layer));
676                        attn_idx += 1;
677                        if (i + 1) % 10 == 0 {
678                            tracing::info!("Loaded layers 0..{}", i + 1);
679                        }
680                        continue;
681                    }
682                    // #915: does the native FP8 attention overlay replace
683                    // these weights below? Hoisted out of the overlay block so
684                    // the NVFP4 build can be skipped rather than built and
685                    // immediately orphaned — `set_fp8_weights` OVERWRITES
686                    // `q/k/v/o_weight`, so on this route the NVFP4 q/k/v/o were
687                    // unreachable the moment they were installed.
688                    let attn_fp8 = dense_fp8_enabled()
689                        && config.tp_world_size.max(1) == 1
690                        && matches!(variant, Nvfp4Variant::Fp8Dequanted)
691                        && proj_is_native_fp8(store, &format!("{p}.q_proj"));
692                    let attn_nvfp4 = route_env.attn_nvfp4(attn_fp8);
693                    let (attn, q_nvfp4, k_nvfp4, v_nvfp4) = match variant {
694                        Nvfp4Variant::CompressedTensors => {
695                            // NVFP4-from-disk path: column-parallel Q/K/V, row-parallel O.
696                            let group_size = 16usize;
697                            let load_nvfp4 = |name: &str,
698                                              full_n: usize,
699                                              full_k: usize,
700                                              kind: TpShardKind|
701                             -> Result<crate::weight_map::QuantizedWeight> {
702                                let prefix = format!("{p}.{name}");
703                                // Mixed-precision compressed-tensors checkpoints
704                                // (unsloth Qwen3.6-*-NVFP4, re-quantized 2026-07-10)
705                                // NVFP4-pack most of the net but keep attention
706                                // q/k/v/o as FP8 (`.weight` FP8E4M3 + a per-row
707                                // `.weight_scale`, no `.weight_packed`). Without the
708                                // pack metadata, dequant and runtime-quantize to NVFP4
709                                // instead of failing on the absent
710                                // `weight_global_scale`. Mirrors the MoE loader's
711                                // attention arm (weight_loader/qwen35/load_layers/
712                                // attention_arms.rs).
713                                let src = if store.contains(&format!("{prefix}.weight_packed")) {
714                                    quantized_auto(store, &prefix, gpu, variant)?
715                                } else {
716                                    let dense_bf16 =
717                                        dense_auto(store, &format!("{prefix}.weight"), gpu)?;
718                                    quantize_to_nvfp4(
719                                        &dense_bf16,
720                                        full_n,
721                                        full_k,
722                                        gpu,
723                                        absmax_k,
724                                        quantize_k,
725                                        stream,
726                                    )?
727                                };
728                                if tp_size == 1 {
729                                    return Ok(src);
730                                }
731                                let sharded = shard_quantized_nvfp4(
732                                    &src, full_n, full_k, kind, tp_rank, tp_size, group_size, gpu,
733                                )?;
734                                gpu.free(src.weight)?;
735                                gpu.free(src.weight_scale)?;
736                                Ok(sharded)
737                            };
738                            let [q, k, v, o] = load_qkvo_tp(config, load_nvfp4)?;
739                            let dummy = DenseWeight {
740                                weight: spark_runtime::gpu::DevicePtr::NULL,
741                            };
742                            let (k_scale, v_scale) = load_kv_scales(store, &p, gpu);
743                            let attn = AttentionWeights {
744                                q_proj: dummy,
745                                k_proj: dummy,
746                                v_proj: dummy,
747                                o_proj: o,
748                                q_norm: dense(store, &format!("{p}.q_norm.weight"))?,
749                                k_norm: dense(store, &format!("{p}.k_norm.weight"))?,
750                                q_norm_full: None,
751                                k_norm_full: None,
752                                k_scale,
753                                v_scale,
754                            };
755                            (attn, Some(q), Some(k), Some(v))
756                        }
757                        Nvfp4Variant::Standard | Nvfp4Variant::Fp8Dequanted if !attn_nvfp4 => {
758                            // #915: the FP8 overlay below replaces q/k/v/o, and
759                            // nothing reads the NVFP4 copies afterwards — the
760                            // transposed twins only under `ATLAS_CUTLASS_NVFP4_*`
761                            // and the base `o_proj` only under `ATLAS_ATTN_W4A4`,
762                            // both of which `RouteEnv::attn_nvfp4` accounts for.
763                            // Skipping the build also skips the BF16 dequant of
764                            // every FP8 projection that fed `quantize_to_nvfp4`.
765                            // Same NULL-o_proj shape the Bf16Raw arm below uses.
766                            let (k_scale, v_scale) = load_kv_scales(store, &p, gpu);
767                            let (nh, hd) = (config.num_attention_heads, config.head_dim);
768                            let (nkv, hh) = (config.num_key_value_heads, config.hidden_size);
769                            let q_n = nh * hd * if config.attn_gated { 2 } else { 1 };
770                            residency.skip(fp8_residency::attn_nvfp4_bytes(
771                                q_n,
772                                nkv * hd,
773                                nh * hd,
774                                hh,
775                            ));
776                            let null = || DenseWeight {
777                                weight: spark_runtime::gpu::DevicePtr::NULL,
778                            };
779                            let attn = AttentionWeights {
780                                q_proj: null(),
781                                k_proj: null(),
782                                v_proj: null(),
783                                o_proj: crate::weight_map::QuantizedWeight::null(),
784                                q_norm: dense(store, &format!("{p}.q_norm.weight"))?,
785                                k_norm: dense(store, &format!("{p}.k_norm.weight"))?,
786                                q_norm_full: None,
787                                k_norm_full: None,
788                                k_scale,
789                                v_scale,
790                            };
791                            // The NULL o_proj is only sound while the FP8
792                            // overlay is installed below — a null NVFP4 weight
793                            // reached by a w4a16 dispatch is the
794                            // CUDA-700-at-concurrency failure mode.
795                            debug_assert!(
796                                attn_fp8,
797                                "attn_nvfp4=false must imply a native FP8 overlay"
798                            );
799                            (attn, None, None, None)
800                        }
801                        Nvfp4Variant::Standard | Nvfp4Variant::Fp8Dequanted => {
802                            // BF16 → NVFP4 path: shard BF16 then quantize per-rank.
803                            let load_bf16_then_nvfp4 = |name: &str,
804                                                        full_n: usize,
805                                                        full_k: usize,
806                                                        kind: TpShardKind|
807                             -> Result<(
808                                DenseWeight,
809                                crate::weight_map::QuantizedWeight,
810                            )> {
811                                // Pre-quantized Standard NVFP4 (e.g. sakamakismile): weight is U8
812                                // on disk. Load directly as QuantizedWeight without BF16 roundtrip.
813                                // TP sharding of pre-quantized NVFP4 is not yet supported: enforce
814                                // tp_size=1 explicitly, or every rank silently loads the full
815                                // unsharded weight (duplicated, not sharded — wrong results with
816                                // no error).
817                                let weight_key = format!("{p}.{name}.weight");
818                                if matches!(
819                                    store.get(&weight_key).map(|w| w.dtype),
820                                    Ok(WeightDtype::UInt8)
821                                ) {
822                                    anyhow::ensure!(
823                                        tp_size == 1,
824                                        "pre-quantized NVFP4 weight '{weight_key}' (U8 on disk) \
825                                         cannot be loaded under tensor parallelism (tp_size={tp_size}): \
826                                         TP sharding of pre-quantized NVFP4 checkpoints is not yet \
827                                         implemented. Use tp_size=1, or dequantize this checkpoint to \
828                                         BF16 first so it goes through the shard-then-requantize path."
829                                    );
830                                    let null_dense = DenseWeight {
831                                        weight: spark_runtime::gpu::DevicePtr::NULL,
832                                    };
833                                    let qw = quantized_auto(
834                                        store,
835                                        &format!("{p}.{name}"),
836                                        gpu,
837                                        Nvfp4Variant::Standard,
838                                    )?;
839                                    return Ok((null_dense, qw));
840                                }
841                                let src = dense_auto(store, &weight_key, gpu)?;
842                                let (sharded_ptr, local_n, local_k) = shard_dense_bf16(
843                                    src.weight, full_n, full_k, kind, tp_rank, tp_size, gpu,
844                                )?;
845                                let sharded = DenseWeight {
846                                    weight: sharded_ptr,
847                                };
848                                let q = quantize_to_nvfp4(
849                                    &sharded, local_n, local_k, gpu, absmax_k, quantize_k, stream,
850                                )?;
851                                if sharded_ptr != src.weight {
852                                    gpu.free(sharded_ptr)?;
853                                }
854                                Ok((src, q))
855                            };
856                            let [
857                                (q_dense, q_nvfp4),
858                                (k_dense, k_nvfp4),
859                                (v_dense, v_nvfp4),
860                                (o_dense, o_nvfp4),
861                            ] = load_qkvo_tp(config, load_bf16_then_nvfp4)?;
862
863                            let (k_scale, v_scale) = load_kv_scales(store, &p, gpu);
864
865                            // The BF16 q/k/v/o dense tensors are only the intermediate
866                            // fed to the GPU quantize_to_nvfp4 above. Prefill AND decode
867                            // always dispatch the NVFP4 weights, so the BF16 copies are
868                            // dead once quantized. Free them instead of retaining a full
869                            // second copy of every projection (Atlas issue #A1).
870                            gpu.free(q_dense.weight)?;
871                            gpu.free(k_dense.weight)?;
872                            gpu.free(v_dense.weight)?;
873                            gpu.free(o_dense.weight)?;
874
875                            let attn = AttentionWeights {
876                                q_proj: DenseWeight {
877                                    weight: spark_runtime::gpu::DevicePtr::NULL,
878                                },
879                                k_proj: DenseWeight {
880                                    weight: spark_runtime::gpu::DevicePtr::NULL,
881                                },
882                                v_proj: DenseWeight {
883                                    weight: spark_runtime::gpu::DevicePtr::NULL,
884                                },
885                                o_proj: o_nvfp4,
886                                q_norm: dense(store, &format!("{p}.q_norm.weight"))?,
887                                k_norm: dense(store, &format!("{p}.k_norm.weight"))?,
888                                q_norm_full: None,
889                                k_norm_full: None,
890                                k_scale,
891                                v_scale,
892                            };
893                            (attn, Some(q_nvfp4), Some(k_nvfp4), Some(v_nvfp4))
894                        }
895                        Nvfp4Variant::Bf16Raw => {
896                            // Native BF16 dense attention: keep Q/K/V/O in BF16
897                            // and dispatch the dense_gemv/dense_gemm kernels that
898                            // ship in the nvfp4 bundle (common/ dense_*_bf16). No
899                            // runtime BF16 -> NVFP4 quant — that lossily quantized
900                            // these no-metadata Holo dense checkpoints. Mirrors
901                            // qwen35/load_layers.rs:552 (BF16-dequant attention)
902                            // and gemma4/loader_a.rs:300/418.
903                            let load_bf16_dense =
904                                |name: &str,
905                                 full_n: usize,
906                                 full_k: usize,
907                                 kind: TpShardKind|
908                                 -> Result<DenseWeight> {
909                                    let src =
910                                        dense_auto(store, &format!("{p}.{name}.weight"), gpu)?;
911                                    if tp_size == 1 {
912                                        return Ok(src);
913                                    }
914                                    let (sharded_ptr, _local_n, _local_k) = shard_dense_bf16(
915                                        src.weight, full_n, full_k, kind, tp_rank, tp_size, gpu,
916                                    )?;
917                                    if sharded_ptr != src.weight {
918                                        gpu.free(src.weight)?;
919                                    }
920                                    Ok(DenseWeight {
921                                        weight: sharded_ptr,
922                                    })
923                                };
924                            let [q_dense, k_dense, v_dense, o_dense] =
925                                load_qkvo_tp(config, load_bf16_dense)?;
926
927                            let (k_scale, v_scale) = load_kv_scales(store, &p, gpu);
928
929                            // Keep q/k/v BF16 dense ALIVE (do NOT free): the dense
930                            // forward reads them directly. o_proj stays NULL — the
931                            // set_o_dense_bf16(o_dense) call after layer build
932                            // installs the BF16 O-proj that decode/prefill prefer.
933                            let attn = AttentionWeights {
934                                q_proj: q_dense,
935                                k_proj: k_dense,
936                                v_proj: v_dense,
937                                o_proj: crate::weight_map::QuantizedWeight::null(),
938                                q_norm: dense(store, &format!("{p}.q_norm.weight"))?,
939                                k_norm: dense(store, &format!("{p}.k_norm.weight"))?,
940                                q_norm_full: None,
941                                k_norm_full: None,
942                                k_scale,
943                                v_scale,
944                            };
945                            o_dense_bf16 = Some(o_dense);
946                            // The NULL o_proj above is only sound while the BF16
947                            // dense O-proj is installed after layer build — a null
948                            // NVFP4 weight reached by a w4a16 dispatch is the
949                            // CUDA-700-at-concurrency failure mode.
950                            debug_assert!(
951                                o_dense_bf16.is_some(),
952                                "Bf16Raw attention must install a dense O-proj to cover the null o_proj"
953                            );
954                            // BF16 native: no NVFP4 q/k/v weights → dense fallback.
955                            (attn, None, None, None)
956                        }
957                    };
958
959                    let mut attn_layer = Qwen3AttentionLayer::new(
960                        input_norm,
961                        attn,
962                        post_attn_norm,
963                        ffn,
964                        attn_idx,
965                        q_nvfp4,
966                        k_nvfp4,
967                        v_nvfp4,
968                        gpu,
969                        layer_kv_dtypes[attn_idx],
970                        config.fp8_kv_calibration_tokens,
971                        config,
972                    )?;
973                    // Fast-prefill: transposed NVFP4 copies route the 16 full-attn
974                    // layers' q/k/v/o prefill GEMMs onto w4a16_gemm_t_m128 (28.8%
975                    // of prefill GPU time on the base w4a16_gemm path; ~1.3x e2e).
976                    // predequant_for_prefill() is deliberately NOT called: the FP8
977                    // predequant route is slower for these bandwidth-bound GEMMs.
978                    if let (Some(qw), Some(kw), Some(vw)) = (q_nvfp4, k_nvfp4, v_nvfp4) {
979                        let (nh, hd) = (config.num_attention_heads, config.head_dim);
980                        let (nkv, hh) = (config.num_key_value_heads, config.hidden_size);
981                        let q_n = nh * hd * if config.attn_gated { 2 } else { 1 };
982                        let qt = qw.transpose_for_gemm(gpu, q_n, hh)?;
983                        let kt = kw.transpose_for_gemm(gpu, nkv * hd, hh)?;
984                        let vt = vw.transpose_for_gemm(gpu, nkv * hd, hh)?;
985                        let op = &attn_layer.attn.o_proj;
986                        let ot = op.transpose_for_gemm(gpu, hh, nh * hd)?;
987                        attn_layer.set_prefill_weights(Some(qt), Some(kt), Some(vt), Some(ot));
988                        // Fused [q|k|v] twin: k/v are N=1024, which against the
989                        // 128-wide N tile is 8 CTAs on 48 SMs (40 idle, 23.6 GB/s,
990                        // 9.75x off floor). Concatenated N=14336 runs 112 CTAs in
991                        // ONE launch. Bit-identical ONLY when the three share a
992                        // single `weight_scale_2` — the GEMM applies one scale2 per
993                        // launch — so verify the device values rather than assume.
994                        // Bit-exact float comparison, not an epsilon: the GEMM
995                        // applies ONE scale2, so anything but exact equality
996                        // changes results.
997                        let scales_equal = qw.weight_scale_2.to_bits()
998                            == kw.weight_scale_2.to_bits()
999                            && kw.weight_scale_2.to_bits() == vw.weight_scale_2.to_bits();
1000                        if scales_equal {
1001                            let fused =
1002                                crate::weight_map::QuantizedWeight::transpose_concat_for_gemm(
1003                                    gpu,
1004                                    &[(&qw, q_n), (&kw, nkv * hd), (&vw, nkv * hd)],
1005                                    hh,
1006                                )?;
1007                            attn_layer.set_fused_qkv_prefill_weight(Some(fused));
1008                        } else if attn_idx == 0 {
1009                            tracing::warn!(
1010                                "attention q/k/v have differing weight_scale_2 — fused QKV GEMM disabled (3 separate launches per layer)"
1011                            );
1012                        }
1013                    }
1014                    // Native-BF16 (Bf16Raw): install the dense O-proj so decode +
1015                    // prefill prefer it over the (NULL) NVFP4 o_proj. Mutually
1016                    // exclusive with the transposed-NVFP4 block above (q_nvfp4 is
1017                    // None on the Bf16Raw path).
1018                    if let Some(o_dense) = o_dense_bf16 {
1019                        attn_layer.set_o_dense_bf16(o_dense);
1020                    }
1021                    // Install native FP8 q/k/v/o (single-GPU FP8 checkpoint).
1022                    // `set_fp8_weights` REPLACES `q/k/v/o_weight`, so on this
1023                    // route the NVFP4 weights above are not a fallback — they
1024                    // are unreachable, which is why `attn_nvfp4` skipped
1025                    // building them (#915). The paths that could still read
1026                    // NVFP4 (`ATLAS_CUTLASS_NVFP4_*`, `ATLAS_ATTN_W4A4`) are
1027                    // exactly what `RouteEnv::attn_nvfp4` checks.
1028                    if attn_fp8 {
1029                        let load_fp8_proj = |name: &str,
1030                                             _n: usize,
1031                                             _k: usize,
1032                                             _kind: TpShardKind|
1033                         -> Result<Fp8Weight> {
1034                            // Only `row_scale` is allocated here; the E4M3
1035                            // bytes are store-owned. Adopt it (#736).
1036                            let w = load_fp8_block_scaled_as_fp8weight(
1037                                store,
1038                                &format!("{p}.{name}"),
1039                                gpu,
1040                            )?;
1041                            let bytes =
1042                                (w.n as usize).div_ceil(128) * (w.k as usize).div_ceil(128) * 4;
1043                            store.derived().adopt(
1044                                "attn fp8 block scale (widened)",
1045                                w.row_scale,
1046                                bytes,
1047                            );
1048                            Ok(w)
1049                        };
1050                        let [q_fp8, k_fp8, v_fp8, o_fp8] = load_qkvo_tp(config, load_fp8_proj)?;
1051                        attn_layer.set_fp8_weights(
1052                            Some(q_fp8),
1053                            Some(k_fp8),
1054                            Some(v_fp8),
1055                            Some(o_fp8),
1056                        );
1057                        // #915: build only the twins a selected kernel reads,
1058                        // and hand each to the store so teardown RELEASES it.
1059                        // K/V are NOT optional — `prefill/cache_skip_qkv.rs` has
1060                        // no W8A8 arm and is the first-chunk path of every
1061                        // request. Table: `Fp8TwinSet` + `fp8_residency.rs`.
1062                        let want =
1063                            route_env.attn_fp8_twins(true, attn_layer.has_w8a8_prefill_kernels());
1064                        let (nh, hd) = (config.num_attention_heads, config.head_dim);
1065                        let (nkv, hh) = (config.num_key_value_heads, config.hidden_size);
1066                        let q_n = nh * hd * if config.attn_gated { 2 } else { 1 };
1067                        let twin_bytes = |set| {
1068                            fp8_residency::attn_fp8_twin_bytes(set, q_n, nkv * hd, nh * hd, hh)
1069                        };
1070                        residency.twins.attn_fp8 |= want.any();
1071                        residency.skip(twin_bytes(Fp8TwinSet::ALL) - twin_bytes(want));
1072                        residency.keep(twin_bytes(want));
1073                        if let Err(e) = attn_layer.transpose_fp8_for_prefill_selected(
1074                            gpu,
1075                            stream,
1076                            want,
1077                            Some(store.derived()),
1078                        ) {
1079                            tracing::warn!("Layer {i}: dense FP8 transpose failed: {e}");
1080                        }
1081                    }
1082                    layers.push(Box::new(attn_layer));
1083                    attn_idx += 1;
1084                }
1085                LayerType::LinearAttention => {
1086                    let nv = config.linear_num_value_heads;
1087                    let nk = config.linear_num_key_heads;
1088                    // GDN HeadParallel: config holds per-rank-LOCAL linear head counts
1089                    // (topology.rs divided them by tp_size). TpGdnDims rebuilds the FULL
1090                    // pre-shard sizes so load/concat/interleave run at FULL, then the
1091                    // shard_gdn_* slicers cut this rank's contiguous head range. value_dim
1092                    // stays LOCAL (sizes the downstream quantize of the sharded buffers).
1093                    let tp_size = config.tp_world_size.max(1);
1094                    let dims = TpGdnDims::from_config(config);
1095                    let qkv_rows = dims.full_conv_dim();
1096                    let z_rows = dims.full_value_dim();
1097                    let value_dim = nv * config.linear_value_head_dim;
1098                    let la = format!("{lp}.linear_attn");
1099
1100                    // Native keep-packed ternary Q2_0 GDN (Tier-1c): the GGUF
1101                    // loader kept `in_proj_qkv` (V-region row-permuted) and
1102                    // `in_proj_z` (row-permuted) 2-bit. Byte-concat them into the
1103                    // fused [Q|K|V|Z] `qkvz` and dispatch `q2_0_gemv_vec` at decode
1104                    // / transient-dequant at prefill. `out_proj` (a within-row
1105                    // COLUMN reorder) is NOT packed here — it stays NVFP4. a/b/
1106                    // conv1d/norm/A_log stay BF16/F32. Requires tp_size=1.
1107                    // ATLAS_NO_Q2_GDN forces the BF16/NVFP4 path for A/B bisection.
1108                    let gdn_q2 = config.tp_world_size.max(1) == 1
1109                        && std::env::var_os("ATLAS_NO_Q2_GDN").is_none()
1110                        && proj_q2_group(store, &format!("{la}.in_proj_qkv")).is_some()
1111                        && proj_q2_group(store, &format!("{la}.in_proj_z")).is_some();
1112                    if gdn_q2 {
1113                        let qkv_q2 = packed_q2_from_store(store, &format!("{la}.in_proj_qkv"))?;
1114                        let z_q2 = packed_q2_from_store(store, &format!("{la}.in_proj_z"))?;
1115                        anyhow::ensure!(
1116                            qkv_q2.group == z_q2.group && qkv_q2.k == z_q2.k,
1117                            "GDN packed qkv/z group|k mismatch ({},{} vs {},{})",
1118                            qkv_q2.group,
1119                            qkv_q2.k,
1120                            z_q2.group,
1121                            z_q2.k
1122                        );
1123                        // Byte-concat packed rows: [Q|K|V] ++ [Z]. Each row is
1124                        // (k/group)*block_bytes; whole-row copy never splits a block.
1125                        let group = qkv_q2.group as usize;
1126                        let block_bytes = 2 + group / 4;
1127                        let row_bytes = (qkv_q2.k as usize / group) * block_bytes;
1128                        let qkv_bytes = qkv_q2.n as usize * row_bytes;
1129                        let z_bytes = z_q2.n as usize * row_bytes;
1130                        let qkvz_buf = gpu.alloc(qkv_bytes + z_bytes)?;
1131                        gpu.copy_d2d(qkv_q2.weight, qkvz_buf, qkv_bytes)?;
1132                        gpu.copy_d2d(z_q2.weight, qkvz_buf.offset(qkv_bytes), z_bytes)?;
1133                        let qkvz_q2 = PackedQ2Weight {
1134                            weight: qkvz_buf,
1135                            n: qkv_q2.n + z_q2.n,
1136                            k: qkv_q2.k,
1137                            group: qkv_q2.group,
1138                        };
1139                        // out_proj + a/b/conv1d/norm are BF16/F32 in the store
1140                        // (sidecar dequanted the reorder tensors). out_proj → NVFP4.
1141                        let in_proj_a = dense_auto(store, &format!("{la}.in_proj_a.weight"), gpu)?;
1142                        let in_proj_b = dense_auto(store, &format!("{la}.in_proj_b.weight"), gpu)?;
1143                        let conv1d = dense(store, &format!("{la}.conv1d.weight"))?;
1144                        let a_log = dense_keep_f32(store, &format!("{la}.A_log"), gpu)?;
1145                        let dt_bias = dense_keep_f32(store, &format!("{la}.dt_bias"), gpu)?;
1146                        let norm = dense_f32_safe(store, &format!("{la}.norm.weight"), gpu)?;
1147                        let ba_dense = interleave_ba(&in_proj_a, &in_proj_b, nv, nk, h, gpu)?;
1148                        let out_proj_dense =
1149                            dense_auto(store, &format!("{la}.out_proj.weight"), gpu)?;
1150                        let out_proj_nvfp4 = quantize_to_nvfp4(
1151                            &out_proj_dense,
1152                            h,
1153                            value_dim,
1154                            gpu,
1155                            absmax_k,
1156                            quantize_k,
1157                            stream,
1158                        )?;
1159                        let out_proj_nvfp4_t =
1160                            out_proj_nvfp4.transpose_for_gemm(gpu, h, value_dim)?;
1161                        gpu.free(out_proj_dense.weight)?;
1162                        let ssm = SsmWeights {
1163                            in_proj_qkvz: DenseWeight {
1164                                weight: spark_runtime::gpu::DevicePtr::NULL,
1165                            },
1166                            in_proj_ba: ba_dense,
1167                            conv1d,
1168                            a_log,
1169                            dt_bias,
1170                            norm,
1171                            out_proj: out_proj_nvfp4,
1172                        };
1173                        let mut layer = Qwen3SsmLayer::new_sequential(
1174                            input_norm,
1175                            ssm,
1176                            post_attn_norm,
1177                            ffn,
1178                            None,
1179                            None,
1180                            Some(out_proj_nvfp4_t),
1181                            config,
1182                            gpu,
1183                        )?;
1184                        layer.set_packed_q2_qkvz(qkvz_q2, gpu);
1185                        layer.predequant_for_prefill(gpu, config, stream)?;
1186                        tracing::info!(
1187                            "SSM[{lp}] native keep-packed Q2_0 GDN: qkvz 2-bit \
1188                             (concat qkv+z row-permuted), out_proj NVFP4"
1189                        );
1190                        layers.push(Box::new(layer));
1191                        continue;
1192                    }
1193
1194                    // SSM projections are loaded per-projection by on-disk dtype:
1195                    // each of in_proj_qkv / in_proj_z / out_proj may independently
1196                    // be NVFP4-packed (`weight_packed`) or plain (`weight`, routed
1197                    // by `dense_auto` → BF16/FP32/FP8). The unsloth NVFP4 re-quant
1198                    // of Qwen3.6-27B quantizes ONLY out_proj while keeping the
1199                    // in_proj_* in BF16; the old all-or-nothing gate (keyed on
1200                    // in_proj_qkv.weight_packed) then looked for a non-existent
1201                    // out_proj.weight and failed to build. `dense_auto` is dequant-
1202                    // to-BF16 for the concat pipeline regardless of source dtype.
1203                    let load_ssm_proj =
1204                        |name: &str, rows: usize, cols: usize| -> Result<DenseWeight> {
1205                            if store.contains(&format!("{name}.weight_packed")) {
1206                                dequant_nvfp4_to_bf16(store, name, rows, cols, gpu)
1207                            } else if matches!(
1208                                store.get(&format!("{name}.weight")).map(|w| w.dtype),
1209                                Ok(WeightDtype::UInt8)
1210                            ) {
1211                                // Standard-convention NVFP4 (packed bytes at
1212                                // `.weight`, not `.weight_packed`) — same dequant,
1213                                // different on-disk key.
1214                                dequant_nvfp4_to_bf16(store, name, rows, cols, gpu)
1215                            } else {
1216                                dense_auto(store, &format!("{name}.weight"), gpu)
1217                            }
1218                        };
1219                    // Native FP8 GDN (nvidia mixed-precision checkpoint): the
1220                    // in_proj_qkv / in_proj_z / out_proj projections ship as
1221                    // F8_E4M3 + per-tensor scale — modelopt's sensitivity
1222                    // analysis keeps the SSM projections high-precision. The
1223                    // default path (`load_ssm_proj` → `dense_auto`) dequants to
1224                    // BF16 then RE-quantizes to NVFP4 (4-bit), a lossy
1225                    // double-quant of these 48/64 layers that regressed BFCL-ST
1226                    // ~7pt (non_live 85.4→76.6). Load the on-disk FP8 directly
1227                    // (concat qkv+z on-device into [Q|K|V|Z] order) and route
1228                    // BOTH prefill (w8a16_gemm_pipelined) and decode
1229                    // (w8a16_gemv) through the fp8w fields — no requant, decode
1230                    // stays fast (FP8 = half BF16's weight bytes). MUST run
1231                    // BEFORE `load_ssm_proj` consumes the store tensors.
1232                    // Internal opt-out for the FP8-vs-NVFP4 GDN A/B + KL-drift
1233                    // gate (not a user choice; mirrors the `ATLAS_NO_*` debug
1234                    // levers). Default engages native FP8.
1235                    if gdn_fp8_arm_selected(store, &la, config.tp_world_size) {
1236                        let in_proj_a = dense(store, &format!("{la}.in_proj_a.weight"))?;
1237                        let in_proj_b = dense(store, &format!("{la}.in_proj_b.weight"))?;
1238                        let conv1d = dense(store, &format!("{la}.conv1d.weight"))?;
1239                        let a_log = dense_keep_f32(store, &format!("{la}.A_log"), gpu)?;
1240                        let dt_bias = dense_keep_f32(store, &format!("{la}.dt_bias"), gpu)?;
1241                        let norm = dense_f32_safe(store, &format!("{la}.norm.weight"), gpu)?;
1242                        let ba_dense = interleave_ba(&in_proj_a, &in_proj_b, nv, nk, h, gpu)?;
1243                        let qkv_f = load_fp8_block_scaled_as_fp8weight(
1244                            store,
1245                            &format!("{la}.in_proj_qkv"),
1246                            gpu,
1247                        )?;
1248                        let z_f = load_fp8_block_scaled_as_fp8weight(
1249                            store,
1250                            &format!("{la}.in_proj_z"),
1251                            gpu,
1252                        )?;
1253                        let out_f = load_fp8_block_scaled_as_fp8weight(
1254                            store,
1255                            &format!("{la}.out_proj"),
1256                            gpu,
1257                        )?;
1258                        let qkvz_f = concat_fp8_block_scaled(&qkv_f, &z_f, h, gpu)?;
1259                        // The concat copied both grids; free the per-projection
1260                        // scale allocs (weight bytes are store-owned, not freed).
1261                        let scale_bytes =
1262                            |n: usize, k: usize| n.div_ceil(128) * k.div_ceil(128) * 4;
1263                        gpu.free(qkv_f.row_scale)?;
1264                        gpu.free(z_f.row_scale)?;
1265                        residency.free(
1266                            scale_bytes(qkv_f.n as usize, h) + scale_bytes(z_f.n as usize, h),
1267                        );
1268                        // #736/#915: the fused `[QKV|Z]` weight is the SSM's
1269                        // hottest tensor and there is no un-fused dispatch to
1270                        // fall back to, so it STAYS — but it is a derived copy
1271                        // that no `ModelResource` owned, which is the
1272                        // 3,840 MB x48 row of the H100 teardown sweep. Adopt it.
1273                        let qkvz_bytes = (qkvz_f.n as usize) * h;
1274                        let qkvz_scale_bytes =
1275                            scale_bytes(qkv_f.n as usize, h) + scale_bytes(z_f.n as usize, h);
1276                        let ba_bytes = nv * 2 * h * 2; // [2*nv, h] BF16
1277                        let out_scale_bytes = scale_bytes(out_f.n as usize, out_f.k as usize);
1278                        let d = store.derived();
1279                        d.adopt("ssm qkvz fp8 concat", qkvz_f.weight, qkvz_bytes);
1280                        d.adopt(
1281                            "ssm qkvz fp8 block scale",
1282                            qkvz_f.row_scale,
1283                            qkvz_scale_bytes,
1284                        );
1285                        d.adopt(
1286                            "ssm out_proj fp8 block scale",
1287                            out_f.row_scale,
1288                            out_scale_bytes,
1289                        );
1290                        d.adopt("ssm in_proj_ba interleaved", ba_dense.weight, ba_bytes);
1291                        residency.keep(qkvz_bytes + qkvz_scale_bytes + out_scale_bytes + ba_bytes);
1292                        residency.twins.ssm_fp8_concat = true;
1293                        let ssm = SsmWeights {
1294                            in_proj_qkvz: DenseWeight {
1295                                weight: spark_runtime::gpu::DevicePtr::NULL,
1296                            },
1297                            in_proj_ba: ba_dense,
1298                            conv1d,
1299                            a_log,
1300                            dt_bias,
1301                            norm,
1302                            out_proj: crate::weight_map::QuantizedWeight::null(),
1303                        };
1304                        let mut layer = Qwen3SsmLayer::new_sequential(
1305                            input_norm,
1306                            ssm,
1307                            post_attn_norm,
1308                            ffn,
1309                            None,
1310                            None,
1311                            None,
1312                            config,
1313                            gpu,
1314                        )?;
1315                        layer.set_fp8_decode_weights(Some(qkvz_f), Some(out_f));
1316                        tracing::info!(
1317                            "SSM[{lp}] native FP8 GDN: qkvz+out_proj block-scaled FP8 \
1318                             (no NVFP4 requant; prefill+decode via w8a16)"
1319                        );
1320                        layers.push(Box::new(layer));
1321                        continue;
1322                    }
1323
1324                    // A, B, conv1d, A_log, dt_bias, norm are independent of the
1325                    // qkv/z/out_proj on-disk format below — load them once up
1326                    // front so both the native-NVFP4 fast path and the legacy
1327                    // dequant/requant path can share them.
1328                    //
1329                    // A_log and dt_bias MUST be FP32 — consumer kernels in
1330                    // `ssm_preprocess.cu` and `mamba2_ssm_decode.cu` declare
1331                    // them `const float*`. Loading via `dense()` kept BF16
1332                    // storage, reinterpreting 48-elt BF16 (96B) as 48-elt
1333                    // FP32 → per-head scrambled decay gates and exponential
1334                    // error amplification through GDR recurrence at long
1335                    // context. The MoE sister loader (`ssm_qwen35.rs`)
1336                    // already promotes these; dense was missing the mirror.
1337                    //
1338                    // in_proj_a/b: route through `load_ssm_proj` (not the raw
1339                    // `dense()` byte-reinterpret) so a Standard-NVFP4 A/B
1340                    // (U8-packed) checkpoint dequants correctly instead of
1341                    // being read as BF16 garbage.
1342                    let in_proj_a = load_ssm_proj(&format!("{la}.in_proj_a"), nv, h)?;
1343                    let in_proj_b = load_ssm_proj(&format!("{la}.in_proj_b"), nv, h)?;
1344                    let conv1d = dense(store, &format!("{la}.conv1d.weight"))?;
1345                    let a_log = dense_keep_f32(store, &format!("{la}.A_log"), gpu)?;
1346                    let dt_bias = dense_keep_f32(store, &format!("{la}.dt_bias"), gpu)?;
1347                    // norm.weight: use `dense_f32_safe` (FP32-aware: detects
1348                    // a fp32 checkpoint and truncates to BF16 with logging;
1349                    // bf16 passes through). Mirrors `weight_map/ssm_qwen35.rs`
1350                    // MoE sister loader (backported here 2026-05-20).
1351                    let norm = dense_f32_safe(store, &format!("{la}.norm.weight"), gpu)?;
1352                    let ba_dense = interleave_ba(&in_proj_a, &in_proj_b, nv, nk, h, gpu)?;
1353                    let qkvz_size = config.ssm_qkvz_size();
1354
1355                    // Native Standard-NVFP4 GDN (pre-quantized checkpoint, e.g.
1356                    // sakamakismile): in_proj_qkv / in_proj_z / out_proj ship
1357                    // U8-packed NVFP4 directly on disk (`.weight` dtype UInt8,
1358                    // not `.weight_packed` — that's the compressed-tensors
1359                    // convention `load_ssm_proj` already dequants above). Load
1360                    // them straight into `QuantizedWeight` and concat on GPU,
1361                    // skipping the BF16-dequant→re-quantize roundtrip entirely
1362                    // (that roundtrip is what the FP8/BF16-opt-in paths above
1363                    // exist to avoid for FP8-native and BF16-preferring
1364                    // checkpoints; here there's no lossy step to avoid in the
1365                    // first place — the data is already NVFP4). Requires all
1366                    // three projections to be U8; a partial-U8 checkpoint
1367                    // falls through to the legacy path below, where the
1368                    // `load_ssm_proj` UInt8 branch added above still dequants
1369                    // each U8 tensor correctly on its own.
1370                    let native_nvfp4 = matches!(
1371                        store
1372                            .get(&format!("{la}.in_proj_qkv.weight"))
1373                            .map(|w| w.dtype),
1374                        Ok(WeightDtype::UInt8)
1375                    ) && matches!(
1376                        store
1377                            .get(&format!("{la}.in_proj_z.weight"))
1378                            .map(|w| w.dtype),
1379                        Ok(WeightDtype::UInt8)
1380                    ) && matches!(
1381                        store.get(&format!("{la}.out_proj.weight")).map(|w| w.dtype),
1382                        Ok(WeightDtype::UInt8)
1383                    );
1384                    if native_nvfp4 {
1385                        let qkv_qw = quantized_auto(
1386                            store,
1387                            &format!("{la}.in_proj_qkv"),
1388                            gpu,
1389                            Nvfp4Variant::Standard,
1390                        )?;
1391                        let z_qw = quantized_auto(
1392                            store,
1393                            &format!("{la}.in_proj_z"),
1394                            gpu,
1395                            Nvfp4Variant::Standard,
1396                        )?;
1397                        let qkvz_nvfp4 = qkv_qw.concat_rows(&z_qw, qkv_rows, z_rows, h, gpu)?;
1398                        let qkvz_nvfp4_t = qkvz_nvfp4.transpose_for_gemm(gpu, qkvz_size, h)?;
1399
1400                        let out_proj_nvfp4 = quantized_auto(
1401                            store,
1402                            &format!("{la}.out_proj"),
1403                            gpu,
1404                            Nvfp4Variant::Standard,
1405                        )?;
1406                        let out_proj_nvfp4_t =
1407                            out_proj_nvfp4.transpose_for_gemm(gpu, h, value_dim)?;
1408
1409                        let ssm = SsmWeights {
1410                            in_proj_qkvz: DenseWeight {
1411                                weight: spark_runtime::gpu::DevicePtr::NULL,
1412                            },
1413                            in_proj_ba: ba_dense,
1414                            conv1d,
1415                            a_log,
1416                            dt_bias,
1417                            norm,
1418                            out_proj: out_proj_nvfp4,
1419                        };
1420                        let mut layer = Qwen3SsmLayer::new_sequential(
1421                            input_norm,
1422                            ssm,
1423                            post_attn_norm,
1424                            ffn,
1425                            Some(qkvz_nvfp4),
1426                            Some(qkvz_nvfp4_t),
1427                            Some(out_proj_nvfp4_t),
1428                            config,
1429                            gpu,
1430                        )?;
1431                        layer.predequant_for_prefill(gpu, config, stream)?;
1432                        tracing::info!(
1433                            "SSM[{lp}] native NVFP4 GDN: qkvz+out_proj loaded pre-quantized \
1434                             (U8-packed on disk; no BF16 dequant/requant roundtrip)"
1435                        );
1436                        layers.push(Box::new(layer));
1437                        continue;
1438                    }
1439
1440                    // PER-ROW FP8 for the row-wise cuBLASLt PREFILL arm
1441                    // (`ATLAS_FP8_ROWWISE=1`). Read from the store BEFORE the
1442                    // dequant below, though the bytes are store-owned either
1443                    // way; the NVFP4 build continues underneath because decode
1444                    // still needs it — `w8a16_gemv` cannot index a per-row
1445                    // scale. See weight_loader/qwen35_dense/rowwise_fp8.rs.
1446                    let rowwise_gdn = rowwise_fp8::rowwise_fp8_enabled()
1447                        && rowwise_fp8::proj_is_fp8_per_row(store, &format!("{la}.in_proj_qkv"))
1448                        && rowwise_fp8::proj_is_fp8_per_row(store, &format!("{la}.in_proj_z"))
1449                        && rowwise_fp8::proj_is_fp8_per_row(store, &format!("{la}.out_proj"));
1450                    let (qkvz_rowwise, out_proj_rowwise) = if rowwise_gdn && tp_size == 1 {
1451                        let qkv_r = rowwise_fp8::load_fp8_per_row(
1452                            store,
1453                            &format!("{la}.in_proj_qkv"),
1454                            gpu,
1455                        )?;
1456                        let z_r =
1457                            rowwise_fp8::load_fp8_per_row(store, &format!("{la}.in_proj_z"), gpu)?;
1458                        let out_r =
1459                            rowwise_fp8::load_fp8_per_row(store, &format!("{la}.out_proj"), gpu)?;
1460                        let qkvz_r = rowwise_fp8::concat_fp8_per_row(&qkv_r, &z_r, h, gpu)?;
1461                        // The concat copied both scale vectors; free the
1462                        // per-projection allocs. Weight bytes are store-owned.
1463                        gpu.free(qkv_r.row_scale)?;
1464                        gpu.free(z_r.row_scale)?;
1465                        (Some(qkvz_r), Some(out_r))
1466                    } else {
1467                        (None, None)
1468                    };
1469
1470                    let qkv_dense = load_ssm_proj(&format!("{la}.in_proj_qkv"), qkv_rows, h)?;
1471                    let z_dense = load_ssm_proj(&format!("{la}.in_proj_z"), z_rows, h)?;
1472                    let out_proj_dense =
1473                        load_ssm_proj(&format!("{la}.out_proj"), h, dims.full_value_dim())?;
1474
1475                    let qkvz_dense =
1476                        gpu_concat_rows(&qkv_dense, qkv_rows, &z_dense, z_rows, h, gpu)?;
1477                    // qkv/z BF16 are only inputs to the concat above; free them now
1478                    // rather than leaking them for the layer's lifetime (Atlas issue #A1).
1479                    gpu.free(qkv_dense.weight)?;
1480                    gpu.free(z_dense.weight)?;
1481
1482                    let ba_dense =
1483                        interleave_ba(&in_proj_a, &in_proj_b, dims.full_nv, dims.full_nk, h, gpu)?;
1484
1485                    // GDN HeadParallel shard: cut the FULL concat/interleave/on-disk buffers
1486                    // to this rank's contiguous head range (mirrors the MoE loader,
1487                    // linear_attn_arms.rs). Runs BEFORE both consumers below (the Bf16Raw
1488                    // branch AND the NVFP4/FP8 path), so both get sharded weights. qkvz
1489                    // (segmented [Q|K|V|Z]) + conv (segmented [Q|K|V]) slice per-block; ba
1490                    // slices contiguously; a_log/dt_bias are per-value-head FP32 scalars;
1491                    // out_proj is row-parallel on value_dim (partials summed by the
1492                    // post-out_proj all-reduce already in Qwen3SsmLayer::forward). norm is
1493                    // [vd] shared across value heads -> REPLICATE (never sliced). Free only
1494                    // the fresh qkvz/ba concat buffers; conv/a_log/dt_bias/out_proj sources
1495                    // are store aliases or dequant bufs freed downstream (the NVFP4 path
1496                    // frees the sharded qkvz/out_proj later). At tp==1 the else arm is a
1497                    // pure pass-through and every slicer no-ops -> byte-identical.
1498                    let (qkvz_dense, ba_dense, conv1d, a_log, dt_bias, out_proj_dense) = if tp_size
1499                        > 1
1500                    {
1501                        let d_conv = config.linear_conv_kernel_dim;
1502                        let (qkvz_ptr, _, _) = shard_gdn_qkvz_rows(qkvz_dense.weight, &dims, gpu)?;
1503                        gpu.free(qkvz_dense.weight)?;
1504                        let (ba_ptr, _, _) = shard_gdn_ba_rows(ba_dense.weight, &dims, gpu)?;
1505                        gpu.free(ba_dense.weight)?;
1506                        let (conv_ptr, _, _) =
1507                            shard_gdn_conv_rows(conv1d.weight, &dims, d_conv, gpu)?;
1508                        let (a_log_ptr, _) =
1509                            shard_gdn_value_vector(a_log.weight, &dims, 1, 4, gpu)?;
1510                        let (dt_bias_ptr, _) =
1511                            shard_gdn_value_vector(dt_bias.weight, &dims, 1, 4, gpu)?;
1512                        let (out_ptr, _, _) =
1513                            shard_gdn_out_proj_row_parallel(out_proj_dense.weight, &dims, gpu)?;
1514                        (
1515                            DenseWeight { weight: qkvz_ptr },
1516                            DenseWeight { weight: ba_ptr },
1517                            DenseWeight { weight: conv_ptr },
1518                            DenseWeight { weight: a_log_ptr },
1519                            DenseWeight {
1520                                weight: dt_bias_ptr,
1521                            },
1522                            DenseWeight { weight: out_ptr },
1523                        )
1524                    } else {
1525                        (qkvz_dense, ba_dense, conv1d, a_log, dt_bias, out_proj_dense)
1526                    };
1527
1528                    // Native-BF16 SSM arm (no-metadata dense Holo checkpoints:
1529                    // Nvfp4Variant::Bf16Raw). The standard nvfp4 bundle ships the
1530                    // common/ BF16 dense kernels (dense_gemv_bf16 / dense_gemm_bf16
1531                    // / dense_gemm_bf16_pipelined) that every SSM forward arm's
1532                    // dense fallback already dispatches, so keep the concatenated
1533                    // qkvz_dense [Q|K|V|Z] and out_proj_dense ALIVE and route
1534                    // through those instead of the lossy BF16->NVFP4 runtime
1535                    // requant. No NVFP4/FP8 copy is built at all: in_proj_qkvz +
1536                    // out_proj_dense feed dense_gemv (per-seq decode,
1537                    // ssm_forward.rs:107/412), dense_gemm (batched decode,
1538                    // trait_decode_batched.rs:113/350 + ssm_batched.rs:180/279)
1539                    // and dense_gemm_bf16_pipelined (prefill,
1540                    // trait_prefill_proj.rs:298 + trait_prefill_helper.rs:89).
1541                    // ssm.out_proj stays null — every out_proj arm prefers
1542                    // out_proj_dense when Some; predequant_for_prefill /
1543                    // set_fp8_prefill_only_weights are skipped (NVFP4/FP8 only).
1544                    if matches!(variant, Nvfp4Variant::Bf16Raw) {
1545                        let ssm = SsmWeights {
1546                            in_proj_qkvz: qkvz_dense,
1547                            in_proj_ba: ba_dense,
1548                            conv1d,
1549                            a_log,
1550                            dt_bias,
1551                            norm,
1552                            out_proj: crate::weight_map::QuantizedWeight::null(),
1553                        };
1554                        let mut layer = Qwen3SsmLayer::new_sequential(
1555                            input_norm,
1556                            ssm,
1557                            post_attn_norm,
1558                            ffn,
1559                            None, // qkvz_nvfp4  — BF16 dense fallback used instead
1560                            None, // qkvz_nvfp4_t
1561                            None, // out_proj_nvfp4_t
1562                            config,
1563                            gpu,
1564                        )?;
1565                        // pub field (qwen3_ssm/mod.rs:46); selected by every
1566                        // out_proj arm (ssm_forward.rs:412,
1567                        // trait_decode_batched.rs:350, ssm_batched.rs:279,
1568                        // trait_prefill_helper.rs:89).
1569                        layer.out_proj_dense = Some(out_proj_dense);
1570                        layers.push(Box::new(layer));
1571                        continue;
1572                    }
1573
1574                    let qkvz_size = config.ssm_qkvz_size();
1575
1576                    // GDN ≥FP8 precision policy (2026-07-04). The nvidia
1577                    // Qwen3.6-27B-NVFP4 checkpoint ships GDN in_proj_qkv /
1578                    // out_proj as native F8_E4M3 (modelopt sensitivity
1579                    // analysis deliberately keeps the SSM projections
1580                    // high-precision); `load_ssm_proj` dequants them to BF16,
1581                    // and the code below then RE-quantizes to NVFP4 (4-bit) —
1582                    // a lossy double-quant of the exact tensors the toolchain
1583                    // protected. That regressed BFCL-ST ~7pt (non_live 85.4→
1584                    // 76.6) vs the 06-15 reference. When enabled, keep the
1585                    // BF16 dequant (≥FP8) and route qkvz + out_proj through the
1586                    // dense_gemv / dense_gemm dispatch (in_proj_qkvz +
1587                    // out_proj_dense fields), mirroring the MoE sister loader's
1588                    // arm (qwen35/load_layers/linear_attn_arms.rs). Gated for a
1589                    // clean A/B + KL-drift gate before flipping the default.
1590                    let gdn_bf16 = matches!(
1591                        std::env::var("ATLAS_GDN_BF16_WEIGHTS").ok().as_deref(),
1592                        Some("1")
1593                    );
1594                    if gdn_bf16 {
1595                        let ssm = SsmWeights {
1596                            in_proj_qkvz: DenseWeight {
1597                                weight: qkvz_dense.weight,
1598                            },
1599                            in_proj_ba: ba_dense,
1600                            conv1d,
1601                            a_log,
1602                            dt_bias,
1603                            norm,
1604                            // Unused: out_proj_dense (set below) has higher
1605                            // dispatch priority in both prefill and decode.
1606                            out_proj: crate::weight_map::QuantizedWeight::null(),
1607                        };
1608                        let mut layer = Qwen3SsmLayer::new_sequential(
1609                            input_norm,
1610                            ssm,
1611                            post_attn_norm,
1612                            ffn,
1613                            None,
1614                            None,
1615                            None,
1616                            config,
1617                            gpu,
1618                        )?;
1619                        layer.out_proj_dense = Some(out_proj_dense);
1620                        tracing::info!(
1621                            "SSM[{lp}] ATLAS_GDN_BF16_WEIGHTS: qkvz + out_proj kept BF16 \
1622                             (≥FP8; NVFP4 requant skipped)"
1623                        );
1624                        layers.push(Box::new(layer));
1625                        continue;
1626                    }
1627
1628                    let qkvz_nvfp4 = quantize_to_nvfp4(
1629                        &qkvz_dense,
1630                        qkvz_size,
1631                        h,
1632                        gpu,
1633                        absmax_k,
1634                        quantize_k,
1635                        stream,
1636                    )?;
1637
1638                    let qkvz_nvfp4_t = qkvz_nvfp4.transpose_for_gemm(gpu, qkvz_size, h)?;
1639
1640                    let out_proj_nvfp4 = quantize_to_nvfp4(
1641                        &out_proj_dense,
1642                        h,
1643                        value_dim,
1644                        gpu,
1645                        absmax_k,
1646                        quantize_k,
1647                        stream,
1648                    )?;
1649
1650                    let out_proj_nvfp4_t = out_proj_nvfp4.transpose_for_gemm(gpu, h, value_dim)?;
1651
1652                    // Native FP8 SSM prefill GEMM: build a single-scale FP8
1653                    // copy of `qkvz_dense` [qkvz_size, h] and `out_proj_dense`
1654                    // [h, value_dim] by direct BF16→FP8 truncation. SSM weight
1655                    // magnitudes fit in FP8 E4M3 range (|w| ≤ 448), so no
1656                    // separate scalar dequant is needed at GEMM time — the
1657                    // `fp8_gemm_n128` kernel interprets the FP8 bytes as
1658                    // values directly (mirrors how `predequant_nvfp4_to_fp8`
1659                    // bakes `scale2` into the FP8 stream). PCND: gated.
1660                    let (qkvz_fp8_prefill, out_proj_fp8_prefill) =
1661                        if let Some(b2f_k) = bf16_to_fp8_k {
1662                            let qkvz_total = (qkvz_size * h) as u32;
1663                            let qkvz_fp8 = gpu.alloc(qkvz_size * h)?;
1664                            crate::layers::ops::bf16_to_fp8(
1665                                gpu,
1666                                b2f_k,
1667                                qkvz_dense.weight,
1668                                qkvz_fp8,
1669                                qkvz_total,
1670                                stream,
1671                            )?;
1672                            let out_total = (h * value_dim) as u32;
1673                            let out_fp8 = gpu.alloc(h * value_dim)?;
1674                            crate::layers::ops::bf16_to_fp8(
1675                                gpu,
1676                                b2f_k,
1677                                out_proj_dense.weight,
1678                                out_fp8,
1679                                out_total,
1680                                stream,
1681                            )?;
1682                            gpu.synchronize(stream)?;
1683                            (Some(qkvz_fp8), Some(out_fp8))
1684                        } else {
1685                            (None, None)
1686                        };
1687
1688                    // SSM prefill/decode always dispatch qkvz_nvfp4/_t and the NVFP4
1689                    // out_proj; the BF16 qkvz_dense / out_proj_dense were only quantize
1690                    // inputs. Free them rather than keep a third full-precision copy of
1691                    // the largest SSM tensor across every layer (Atlas issue #A1).
1692                    gpu.free(qkvz_dense.weight)?;
1693                    gpu.free(out_proj_dense.weight)?;
1694
1695                    let ssm = SsmWeights {
1696                        in_proj_qkvz: DenseWeight {
1697                            weight: spark_runtime::gpu::DevicePtr::NULL,
1698                        },
1699                        in_proj_ba: ba_dense,
1700                        conv1d,
1701                        a_log,
1702                        dt_bias,
1703                        norm,
1704                        out_proj: out_proj_nvfp4,
1705                    };
1706
1707                    let mut layer = Qwen3SsmLayer::new_sequential(
1708                        input_norm,
1709                        ssm,
1710                        post_attn_norm,
1711                        ffn,
1712                        Some(qkvz_nvfp4),
1713                        Some(qkvz_nvfp4_t),
1714                        Some(out_proj_nvfp4_t),
1715                        config,
1716                        gpu,
1717                    )?;
1718                    layer.predequant_for_prefill(gpu, config, stream)?;
1719                    // Install the FP8 prefill weights AFTER `predequant_for_prefill`
1720                    // (which sets `out_proj_fp8` from NVFP4 + scale2). The
1721                    // native-FP8 path overrides both pointers when active,
1722                    // routing prefill through `fp8_gemm_n128` instead of
1723                    // `w4a16_gemm_t`. Decode batch paths keep their NVFP4
1724                    // fallback (the `qkvz_nvfp4*` fields above).
1725                    if qkvz_fp8_prefill.is_some() || out_proj_fp8_prefill.is_some() {
1726                        layer.set_fp8_prefill_only_weights(qkvz_fp8_prefill, out_proj_fp8_prefill);
1727                    }
1728                    // …and LAST, so it wins over both of the prefill installs
1729                    // above: the checkpoint's own per-row FP8, which reaches
1730                    // the GEMM with no conversion at all. Decode is untouched.
1731                    if qkvz_rowwise.is_some() {
1732                        layer.set_fp8_rowwise_prefill_weights(qkvz_rowwise, out_proj_rowwise);
1733                        if i == 0 {
1734                            tracing::info!(
1735                                "SSM[{lp}] ATLAS_FP8_ROWWISE: qkvz + out_proj prefill via \
1736                                 native per-row FP8 (no BF16 dequant, no NVFP4 requant); \
1737                                 decode keeps NVFP4"
1738                            );
1739                        }
1740                    }
1741                    layers.push(Box::new(layer));
1742                }
1743                LayerType::SlidingAttention => {
1744                    unreachable!("unexpected SlidingAttention in this loader")
1745                }
1746                LayerType::Moe => unreachable!("Qwen3.5 dense has no standalone MoE layers"),
1747                // GLM-5.3's `deepseek_sparse_attention`: a full-rank mixer whose visible key set
1748                // is chosen at runtime by an indexer. Hard error, not a silent fallthrough into
1749                // the dense-attention arm -- that would attend over the WHOLE cache and look right.
1750                LayerType::SparseAttention => anyhow::bail!(
1751                    "layer {i}: SparseAttention needs a DSA indexer and per-query top-k; Qwen3.5 dense has neither"
1752                ),
1753            }
1754
1755            if (i + 1) % 10 == 0 {
1756                tracing::info!("Loaded layers 0..{}", i + 1);
1757                spark_runtime::progress::layer(i + 1, config.num_hidden_layers);
1758            }
1759        }
1760
1761        tracing::info!(
1762            "Qwen3.5 dense weight loader: {} layers ({} attention, {} SSM, dense FFN)",
1763            layers.len(),
1764            attn_idx,
1765            layers.len() - attn_idx,
1766        );
1767        // #915: the line the next H100 serve is read against. `weights` is the
1768        // checkpoint as the ledger sees it; `derived` is everything this loader
1769        // built on top of it and now OWNS (released at teardown, not swept);
1770        // `not built` is what the pre-#915 loader allocated here and this one
1771        // proved unreachable. Emitted unconditionally — a residency regression
1772        // that only shows under a debug flag is one nobody sees.
1773        tracing::info!("{}", residency.summary(store.resident_bytes()));
1774        for (label, bytes, count) in store.derived().by_label() {
1775            tracing::debug!(
1776                "  derived-weight owner: {:>9.1} MB x{:<5} {label}",
1777                bytes as f64 / (1024.0 * 1024.0),
1778                count,
1779            );
1780        }
1781
1782        Ok(layers)
1783    }
1784
1785    /// Drop the SSM source tensors the native-FP8 GDN arm copied and no longer
1786    /// reads (#915).
1787    ///
1788    /// That arm builds a fused `[QKV|Z]` FP8 weight by device-to-device
1789    /// appending `in_proj_qkv` and `in_proj_z` (`concat_fp8_block_scaled`), and
1790    /// builds `in_proj_ba` by a D2H -> host interleave -> H2D round trip
1791    /// (`interleave_ba`). All four store originals are dead the moment
1792    /// `load_layers` returns — 80 MiB + ~1 MB per SSM layer, ~3.9 GB across the
1793    /// 48 GDN layers of Qwen3.8-27B-FP8, which is what the fused copy costs.
1794    /// Keeping both is the duplicate that came straight out of the KV budget.
1795    ///
1796    /// 🪤 Narrow on purpose. `out_proj.weight` IS `out_proj_fp8w.weight`
1797    /// (zero-copy from the store), `conv1d`, `A_log`, `dt_bias` and
1798    /// `norm.weight` are aliased or conditionally aliased depending on their
1799    /// on-disk dtype, and every attention tensor — and `mlp.down_proj` — is
1800    /// bound zero-copy. Only the names below are freed, and only for layers
1801    /// where the module-private predicate that SELECTED the corresponding
1802    /// concat (`gdn_fp8_arm_selected` for the SSM `[QKV|Z]` weight,
1803    /// `ffn_gateup_fused_selected` for the dense-FFN gate+up weight, #927)
1804    /// says that arm actually ran.
1805    fn prune_after_load(
1806        &self,
1807        store: &mut WeightStore,
1808        config: &ModelConfig,
1809        gpu: &dyn GpuBackend,
1810    ) -> Result<()> {
1811        // Same resolution `load_layers` uses: an explicit `layer_types` list
1812        // wins over the computed pattern, and pruning must be decided from the
1813        // list that actually selected the arms.
1814        let layer_types = if config.layer_types.is_empty() {
1815            (0..config.num_hidden_layers)
1816                .map(|i| config.layer_type(i))
1817                .collect::<Vec<_>>()
1818        } else {
1819            config.layer_types.clone()
1820        };
1821        let mut doomed: std::collections::HashSet<String> = std::collections::HashSet::new();
1822        // The dense-FFN gate+up fusion (#927) consumed these the same way the
1823        // SSM `[QKV|Z]` concat below consumes its two: the fused buffer holds
1824        // the bytes, and `gate_proj`/`up_proj` are VIEWS inside it, so nothing
1825        // aliases the store tensors any more. Releasing them is what makes the
1826        // fusion residency-neutral; keeping them would be the 11.4 GB the
1827        // fused arm exists to not spend. `down_proj` is NOT pruned — it is
1828        // still bound zero-copy.
1829        //
1830        // Same `variant` the load used (`detect_nvfp4_variant` is a pure
1831        // function of the store and the config), and the SAME predicate, so a
1832        // layer that did not fuse cannot be pruned here.
1833        let variant = detect_nvfp4_variant(store, config);
1834        for i in 0..layer_types.len() {
1835            let lp = config.layer_prefix(i);
1836            if !ffn_gateup_fused_selected(store, config, variant, &lp) {
1837                continue;
1838            }
1839            for proj in ["gate_proj", "up_proj"] {
1840                for leaf in ["weight", "weight_scale_inv", "weight_scale"] {
1841                    doomed.insert(format!("{lp}.mlp.{proj}.{leaf}"));
1842                }
1843            }
1844        }
1845        for (i, lt) in layer_types.iter().enumerate() {
1846            if *lt != LayerType::LinearAttention {
1847                continue;
1848            }
1849            let la = format!("{}.linear_attn", config.layer_prefix(i));
1850            if !gdn_fp8_arm_selected(store, &la, config.tp_world_size) {
1851                continue;
1852            }
1853            for leaf in [
1854                "in_proj_qkv.weight",
1855                "in_proj_qkv.weight_scale_inv",
1856                "in_proj_qkv.weight_scale",
1857                "in_proj_z.weight",
1858                "in_proj_z.weight_scale_inv",
1859                "in_proj_z.weight_scale",
1860                "in_proj_a.weight",
1861                "in_proj_b.weight",
1862            ] {
1863                doomed.insert(format!("{la}.{leaf}"));
1864            }
1865        }
1866        if doomed.is_empty() {
1867            return Ok(());
1868        }
1869        let (count, bytes) = store.free_matching(gpu, |name| doomed.contains(name))?;
1870        tracing::info!(
1871            "native FP8: released {count} store tensors ({:.2} GB) consumed by the fused              [QKV|Z] SSM concat, the BA interleave and the dense-FFN gate+up fusion;              out_proj/conv1d/A_log/dt_bias/norm/down_proj kept (still aliased)",
1872            bytes as f64 / 1e9,
1873        );
1874        Ok(())
1875    }
1876
1877    fn load_embedding(
1878        &self,
1879        store: &WeightStore,
1880        config: &ModelConfig,
1881        _gpu: &dyn GpuBackend,
1882    ) -> Result<DenseWeight> {
1883        loaders_b::load_embedding(store, config)
1884    }
1885
1886    fn load_final_norm(
1887        &self,
1888        store: &WeightStore,
1889        config: &ModelConfig,
1890        _gpu: &dyn GpuBackend,
1891    ) -> Result<DenseWeight> {
1892        loaders_b::load_final_norm(store, config)
1893    }
1894
1895    fn load_lm_head(
1896        &self,
1897        store: &WeightStore,
1898        config: &ModelConfig,
1899        gpu: &dyn GpuBackend,
1900    ) -> Result<DenseWeight> {
1901        loaders_b::load_lm_head(store, config, gpu)
1902    }
1903
1904    fn load_mtp_weights(
1905        &self,
1906        store: &WeightStore,
1907        config: &ModelConfig,
1908        gpu: &dyn GpuBackend,
1909    ) -> Result<Option<MtpWeights>> {
1910        if !store.contains("mtp.fc.weight") {
1911            return Ok(None);
1912        }
1913        let variant = detect_nvfp4_variant(store, config);
1914        tracing::info!(
1915            "Loading dense MTP weights (variant={:?}, hidden={}, inter={})",
1916            variant,
1917            config.hidden_size,
1918            config.intermediate_size,
1919        );
1920        // `load_mtp` auto-detects MoE vs dense FFN by inspecting the weight
1921        // names. For dense Qwen3.6-27B-FP8 it returns a MtpWeights with
1922        // `dense_ffn = Some(...)` and NULL placeholders for the MoE fields.
1923        let mtp = load_mtp(store, config.num_experts, gpu, variant)?;
1924        if mtp.dense_ffn.is_some() {
1925            tracing::info!("Dense MTP head ready (FP8 e4m3 projections + dense gate/up/down MLP)");
1926        } else {
1927            tracing::info!(
1928                "MoE MTP head ready ({} experts) — dense loader sees MoE bundle",
1929                mtp.experts.len(),
1930            );
1931        }
1932        Ok(Some(mtp))
1933    }
1934
1935    fn load_vision_encoder(
1936        &self,
1937        store: &WeightStore,
1938        config: &ModelConfig,
1939        gpu: &dyn GpuBackend,
1940    ) -> Result<Option<crate::layers::VisionEncoder>> {
1941        // Dense Qwen3.5 / Holo VL checkpoints (e.g. Holo-3.1-0.8B, Ornith-1.0-9B)
1942        // ship the SAME Qwen3-VL ViT tower as their MoE siblings. The MoE
1943        // loader's `load_vision_encoder` reads only `store` + `config.vision`
1944        // (no MoE-specific state), so reuse it verbatim. The shared model
1945        // forward (`model/trait_impl/*`, gated on `vision_encoder.is_some()`)
1946        // then merges image embeddings — no dense-specific forward changes.
1947        super::qwen35::Qwen35WeightLoader.load_vision_encoder(store, config, gpu)
1948    }
1949}