Skip to main content

cortiq_engine/
loader.rs

1//! Weight loader: CMF tensor directory → Pipeline.
2//!
3//! Storage rule: models WITH task masks are dequantized to f32 (masked
4//! execution needs f32 row access; skill files are small by design).
5//! Models without masks keep quantized matrices zero-copy from the mmap
6//! (`QTensor::Mapped`) — this is what lets a 15B file run in a few GB
7//! of RSS instead of 60 GB of f32.
8//!
9//! Layer kinds come from `arch.layer_types`: FullAttention loads
10//! `self_attn.*` (with auto-detected Qwen3.5 extras: per-head qk-norm by
11//! tensor presence, output gate by q_proj row count); LinearAttention
12//! loads the canonical core `vmf_attn.*` (folded at convert time).
13
14use crate::kv_cache::LayerKvCache;
15use crate::linear_core::{
16    GdnCfg, GdnWeights, ShortConvCfg, ShortConvWeights, VmfPhaseCfg, VmfPhaseWeights,
17};
18use crate::pipeline::{
19    AttnKind, DenseFfn, FfnKind, LayerWeights, MoeFfn, MtpModule, Pipeline, PipelineWeights,
20};
21use crate::qtensor::QTensor;
22use crate::sampler::SamplerConfig;
23use crate::tokenizer::Tokenizer;
24use cortiq_core::quant::dequant_tensor;
25use cortiq_core::{CmfError, CmfModel, LayerType, ModelArch};
26use std::sync::Arc;
27
28/// The refusal every generative entry point (`Pipeline::from_model*`, and
29/// through it run/chat/route/bench) gives a file carrying the DECISION
30/// feature bit. Such a file is served by the decision runtime instead.
31pub const DECISION_MODEL_REFUSAL: &str =
32    "this is a DECISION model; use `cortiq decide` or `cortiq serve`";
33
34const FLINT_NO_ROPE_LAYERS: [usize; 14] = [0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 48];
35
36/// Flint's attention profile is an execution contract, not a converter hint.
37/// Reject headers produced before it was represented rather than silently
38/// decoding their learned sinks with RoPE/softmax semantics.
39fn validate_flint_profile(model: &CmfModel, arch: &ModelArch) -> Result<(), CmfError> {
40    if arch.arch_name != "flint" {
41        return Ok(());
42    }
43    if arch.num_layers != 49
44        || arch.hidden_size != 2048
45        || arch.num_attention_heads != 32
46        || arch.num_kv_heads != 4
47        || arch.head_dim != 128
48        || arch.vocab_size != 150_144
49    {
50        return Err(CmfError::Parse(
51            "Flint geometry is not the released RecursiveSI/flint profile".into(),
52        ));
53    }
54    if arch.sliding_window != Some(513) {
55        return Err(CmfError::Parse(
56            "Flint requires arch.sliding_window=513; run `cortiq repair-flint <model.cmf>` for legacy exports"
57                .into(),
58        ));
59    }
60    let expected_no_rope: Vec<bool> = (0..arch.num_layers)
61        .map(|li| FLINT_NO_ROPE_LAYERS.contains(&li))
62        .collect();
63    if arch.no_rope_layers.as_deref() != Some(expected_no_rope.as_slice()) {
64        return Err(CmfError::Parse(
65            "Flint requires its exact 14-layer no-RoPE schedule; run `cortiq repair-flint <model.cmf>` for legacy exports"
66                .into(),
67        ));
68    }
69    if !arch.attention_sink {
70        return Err(CmfError::Parse(
71            "Flint requires arch.attention_sink=true; run `cortiq repair-flint <model.cmf>` for legacy exports"
72                .into(),
73        ));
74    }
75    let Some(moe) = arch.moe.as_ref() else {
76        return Err(CmfError::Parse("Flint requires an MoE descriptor".into()));
77    };
78    if !(moe.router_sigmoid
79        && moe.norm_topk_prob
80        && moe.num_experts == 256
81        && moe.top_k == 6
82        && moe.moe_intermediate_size == 512
83        && moe.shared_expert_intermediate_size == Some(1024))
84    {
85        return Err(CmfError::Parse(
86            "Flint requires sigmoid top-6 normalized routing with its 256×512 + shared-1024 MoE profile"
87                .into(),
88        ));
89    }
90    for li in 0..arch.num_layers {
91        let name = format!("model.layers.{li}.self_attn.softmax_offset");
92        let Some(sink) = model.tensor(&name) else {
93            return Err(CmfError::MissingTensor(name));
94        };
95        if sink.shape.as_slice() != [arch.num_attention_heads] {
96            return Err(CmfError::Parse(format!(
97                "{name} has shape {:?}, expected [{}]",
98                sink.shape, arch.num_attention_heads
99            )));
100        }
101    }
102    Ok(())
103}
104
105/// Tensor source selector (spec §9): backbone, one skill's overlay, or
106/// a soft superposition of top-m skills (claim 14 working tensors).
107pub enum Overlay<'a> {
108    None,
109    One(&'a str),
110    /// (skill_id, weight); weights sum to 1 (softmax(−E/T) upstream).
111    Blend(&'a [(String, f32)]),
112}
113
114impl Overlay<'_> {
115    fn blend_touches(&self, model: &CmfModel, name: &str) -> bool {
116        match self {
117            Overlay::Blend(list) => list
118                .iter()
119                .any(|(sid, _)| model.tensor(&format!("skill.{sid}.{name}")).is_some()),
120            _ => false,
121        }
122    }
123}
124
125fn dequant_by_name(model: &CmfModel, name: &str) -> Result<Vec<f32>, String> {
126    let entry = model
127        .tensor(name)
128        .ok_or_else(|| format!("tensor '{name}' not found in CMF directory"))?;
129    let mut out = vec![0.0f32; entry.n_elems()];
130    dequant_tensor(entry, model.entry_bytes(entry), &mut out)?;
131    Ok(out)
132}
133
134/// Weighted working tensor (claim 14): Σ wᵢ·Tᵢ, where Tᵢ is the
135/// skill's replacement when present, else the backbone tensor.
136fn blend_f32(model: &CmfModel, name: &str, list: &[(String, f32)]) -> Result<Vec<f32>, String> {
137    let mut acc: Option<Vec<f32>> = None;
138    for (sid, w) in list {
139        let sname = format!("skill.{sid}.{name}");
140        let src = if model.tensor(&sname).is_some() {
141            &sname
142        } else {
143            name
144        };
145        let t = dequant_by_name(model, src)?;
146        match &mut acc {
147            None => {
148                let mut t = t;
149                for v in t.iter_mut() {
150                    *v *= w;
151                }
152                acc = Some(t);
153            }
154            Some(a) => {
155                for (av, tv) in a.iter_mut().zip(&t) {
156                    *av += w * tv;
157                }
158            }
159        }
160    }
161    acc.ok_or_else(|| "empty blend".into())
162}
163
164/// Dequantize a tensor fully into f32 (norms, masked models).
165pub(crate) fn load_f32(model: &CmfModel, name: &str, ov: &Overlay) -> Result<Vec<f32>, String> {
166    if ov.blend_touches(model, name) {
167        if let Overlay::Blend(list) = ov {
168            return blend_f32(model, name, list);
169        }
170    }
171    let skill = match ov {
172        Overlay::One(s) => Some(*s),
173        _ => None,
174    };
175    let entry = model
176        .resolve_tensor(name, skill)
177        .ok_or_else(|| format!("tensor '{name}' not found in CMF directory"))?;
178    let bytes = model.entry_bytes(entry);
179    let mut out = vec![0.0f32; entry.n_elems()];
180    dequant_tensor(entry, bytes, &mut out)?;
181    Ok(out)
182}
183
184/// Build one layer's FFN (dense or MoE) under a given overlay. Shared
185/// by the static loader AND dynamic per-token skill switching
186/// (`Pipeline::set_active_skill`): switching skills = rebuilding the
187/// FFN of the touched layers, cheap because Mapped tensors are just
188/// re-resolved mmap pointers (no dequant, no copy).
189pub(crate) fn build_layer_ffn(
190    model: &Arc<CmfModel>,
191    arch: &ModelArch,
192    li: usize,
193    force_f32: bool,
194    ov: &Overlay,
195) -> Result<FfnKind, CmfError> {
196    build_ffn_at(model, arch, &format!("model.layers.{li}."), force_f32, ov)
197}
198
199/// The FFN under an arbitrary prefix. Split out of `build_layer_ffn` so the
200/// MTP block can reuse it: Qwen3.6's MTP layer carries a full MoE mlp
201/// (router + 256 experts + shared expert), not the dense one the head was
202/// first written against.
203pub(crate) fn build_ffn_at(
204    model: &Arc<CmfModel>,
205    arch: &ModelArch,
206    prefix: &str,
207    force_f32: bool,
208    ov: &Overlay,
209) -> Result<FfnKind, CmfError> {
210    let prefix = prefix.to_string();
211    let load_dense = |p: &str| -> Result<DenseFfn, CmfError> {
212        let gate_proj = load_matrix(model, &format!("{p}gate_proj.weight"), force_f32, ov)?;
213        let up_proj = load_matrix(model, &format!("{p}up_proj.weight"), force_f32, ov)?;
214        let down_proj = load_matrix(model, &format!("{p}down_proj.weight"), force_f32, ov)?;
215        // FFN triple invariant (holds for dense and each MoE expert;
216        // enforced loudly so a malformed defrag/repack — spec §11 — fails
217        // at load instead of silently mis-computing). inter' is per-layer.
218        let inter = gate_proj.rows();
219        if up_proj.rows() != inter || down_proj.cols() != inter {
220            return Err(CmfError::Parse(format!(
221                "{p}: FFN dims disagree (gate.rows={inter}, up.rows={}, \
222                 down.cols={}); all three must equal inter'",
223                up_proj.rows(),
224                down_proj.cols()
225            )));
226        }
227        if down_proj.rows() != arch.hidden_size {
228            return Err(CmfError::Parse(format!(
229                "{p}: down_proj.rows={} != hidden_size={}",
230                down_proj.rows(),
231                arch.hidden_size
232            )));
233        }
234        // The transposed down, when the file carries one: the per-token
235        // sparse path needs a neuron's down weights contiguous.
236        let dt_name = format!("{p}down_proj.t.weight");
237        let down_t = match model.tensor(&dt_name) {
238            Some(_) => Some(load_matrix(model, &dt_name, force_f32, ov)?),
239            None => None,
240        };
241        if let Some(t) = &down_t
242            && (t.rows() != inter || t.cols() != arch.hidden_size)
243        {
244            return Err(CmfError::Parse(format!(
245                "{p}down_proj.t: [{}, {}] != [{inter}, {}]",
246                t.rows(),
247                t.cols(),
248                arch.hidden_size
249            )));
250        }
251        // Task tubes (`…gate_proj.tube1.weight`, …): the neurons only
252        // some tasks compute, each stored as its own triple so every
253        // kernel runs it unchanged and an inactive tube's bytes are
254        // never touched. Numbering is dense from 1; the first gap ends
255        // the tube list.
256        let mut segs = Vec::new();
257        let mut start = inter;
258        for k in 1.. {
259            let gn = format!("{p}gate_proj.tube{k}.weight");
260            if model.tensor(&gn).is_none() {
261                break;
262            }
263            let gate = load_matrix(model, &gn, force_f32, ov)?;
264            let up = load_matrix(model, &format!("{p}up_proj.tube{k}.weight"), force_f32, ov)?;
265            let down = load_matrix(
266                model,
267                &format!("{p}down_proj.tube{k}.weight"),
268                force_f32,
269                ov,
270            )?;
271            let width = gate.rows();
272            if up.rows() != width || down.cols() != width || down.rows() != arch.hidden_size {
273                return Err(CmfError::Parse(format!(
274                    "{p}tube{k}: dims disagree (gate.rows={width}, up.rows={}, \
275                     down=[{}, {}], hidden={})",
276                    up.rows(),
277                    down.rows(),
278                    down.cols(),
279                    arch.hidden_size
280                )));
281            }
282            segs.push(crate::pipeline::FfnSeg {
283                gate,
284                up,
285                down,
286                start,
287                width,
288            });
289            start += width;
290        }
291        Ok(DenseFfn {
292            gate_proj,
293            up_proj,
294            down_proj,
295            act: crate::pipeline::Act::from_arch_full(arch),
296            down_t,
297            segs,
298        })
299    };
300    let router_name = format!("{prefix}mlp.gate.weight");
301    // Cortiq Embryo: resonance-routed experts carry NO gate tensor — the
302    // MoE is keyed on the first expert + the arch flag (a grown genome
303    // appends `mlp.experts.{E}.*` records without rewriting anything).
304    let resonance_moe = model.tensor(&router_name).is_none()
305        && arch.moe.as_ref().is_some_and(|m| m.router_resonance)
306        && model
307            .tensor(&format!("{prefix}mlp.experts.0.gate_proj.weight"))
308            .is_some();
309    if model.tensor(&router_name).is_none() && !resonance_moe {
310        return Ok(FfnKind::Dense(load_dense(&format!("{prefix}mlp."))?));
311    }
312    let cfg = arch.moe.as_ref().ok_or_else(|| {
313        CmfError::Parse(format!(
314            "{router_name} present but header has no arch.moe block"
315        ))
316    })?;
317    // Experts enumerate by TENSOR PRESENCE up to the header count — a
318    // moe-defrag'd specialist keeps a per-layer contiguous prefix of
319    // renumbered experts (fewer than arch.moe.num_experts), with the
320    // router rows sliced to match.
321    let mut experts = Vec::new();
322    for e in 0..cfg.num_experts {
323        if model
324            .tensor(&format!("{prefix}mlp.experts.{e}.gate_proj.weight"))
325            .is_none()
326        {
327            break;
328        }
329        experts.push(load_dense(&format!("{prefix}mlp.experts.{e}."))?);
330    }
331    if experts.is_empty() {
332        return Err(CmfError::Parse(format!(
333            "{prefix}: router present but no expert tensors"
334        )));
335    }
336    // Growth records (`kind = "expert_append"`, spec §9.5.1): the experts
337    // the records append to THIS layer, mounted behind the trunk experts
338    // in header order. `arch.moe.num_experts` stays E0; the trunk count
339    // is `e0`, the tail `experts[e0..]` is described by `grown`.
340    let e0 = experts.len();
341    let grown_loads = if resonance_moe {
342        mount_growth(model, &prefix, ov, &load_dense)?
343    } else {
344        Vec::new()
345    };
346    let mut grown_desc: Vec<(Vec<f32>, Vec<f32>, f32, f32)> = Vec::new();
347    let mut grown: Vec<crate::pipeline::GrownExpert> = Vec::new();
348    for g in grown_loads {
349        experts.push(g.ffn);
350        grown_desc.push((g.mu, g.u, g.bias, g.shell));
351        grown.push(g.meta);
352    }
353    let shared = if model
354        .tensor(&format!("{prefix}mlp.shared_expert.gate_proj.weight"))
355        .is_some()
356    {
357        let gate_name = format!("{prefix}mlp.shared_expert_gate.weight");
358        Some((
359            load_dense(&format!("{prefix}mlp.shared_expert."))?,
360            if model.tensor(&gate_name).is_some() {
361                Some(load_matrix(model, &gate_name, force_f32, ov)?)
362            } else {
363                None
364            },
365        ))
366    } else {
367        None
368    };
369    // LFM2-MoE selection bias (`mlp.expert_bias`): present iff the model
370    // routes with a bias; loaded by tensor presence.
371    let bias_name = format!("{prefix}mlp.expert_bias");
372    let expert_bias = if model.tensor(&bias_name).is_some() {
373        Some(load_f32(model, &bias_name, ov).map_err(CmfError::Parse)?)
374    } else {
375        None
376    };
377    // CMF_MOE_TOPK=N (opt-in): route to fewer experts than the header
378    // asks. MoE decode is memory-bound — every selected expert streams
379    // its three matrices per token — so halving k halves that traffic;
380    // the renormalized top-k keeps the mixture a proper average.
381    // Quality is the experiment — measure ppl before trusting.
382    let top_k = std::env::var("CMF_MOE_TOPK")
383        .ok()
384        .and_then(|v| v.parse::<usize>().ok())
385        .filter(|&k| k >= 1 && k <= cfg.top_k)
386        .inspect(|k| tracing::info!("MoE top_k override: {} (header {})", k, cfg.top_k))
387        .unwrap_or(cfg.top_k);
388    // CMF_MOE_TAU=0.x (opt-in): adaptive routing — see MoeFfn::route_tau.
389    let route_tau = std::env::var("CMF_MOE_TAU")
390        .ok()
391        .and_then(|v| v.parse::<f32>().ok())
392        .filter(|&t| t > 0.0 && t < 1.0)
393        .inspect(|t| tracing::info!("MoE adaptive routing: tau {t}"));
394    let mask = moe_task_mask(model, &prefix, experts.len());
395    let router = if resonance_moe {
396        // never read (selection is by descriptors); zero placeholder in RAM
397        QTensor::from_f32(
398            vec![0.0; experts.len() * arch.hidden_size],
399            experts.len(),
400            arch.hidden_size,
401        )
402    } else {
403        load_matrix(model, &router_name, force_f32, ov)?
404    };
405    if router.rows() != experts.len() {
406        return Err(CmfError::Parse(format!(
407            "{router_name}: {} rows != {} experts",
408            router.rows(),
409            experts.len()
410        )));
411    }
412    let top_k = top_k.min(experts.len());
413    // Gemma-4: per-expert weight scale after the top-k renorm; its
414    // presence also marks the scale-less-rms router input (the folded
415    // router gain — see the converter).
416    let pes_name = format!("{prefix}mlp.per_expert_scale");
417    let per_expert_scale = if model.tensor(&pes_name).is_some() {
418        Some(load_f32(model, &pes_name, ov).map_err(CmfError::Parse)?)
419    } else {
420        None
421    };
422    let router_input_norm = per_expert_scale.is_some();
423    // Cortiq Embryo resonance descriptors: per-expert records
424    // `mlp.experts.{e}.desc.{mu,u,bias}` (append-only growth) or the legacy
425    // per-layer `mlp.desc.{mu,u,bias}` [E, ...]. Present → the router is a
426    // placeholder and selection is by reconstruction error.
427    let per_expert = model
428        .tensor(&format!("{prefix}mlp.experts.0.desc.mu"))
429        .is_some();
430    if !per_expert && !grown.is_empty() {
431        return Err(CmfError::Parse(format!(
432            "{prefix}: expert_append records need per-expert descriptors \
433             (mlp.experts.0.desc.mu); the stacked mlp.desc.* form cannot be grown"
434        )));
435    }
436    let resonance = if per_expert {
437        // Trunk descriptors first (E0 rows), then the grown rows behind
438        // them: `shell` is +inf on the trunk, the record's finite
439        // `desc.shell` on a grown expert.
440        let ne_d = e0;
441        let hidden = arch.hidden_size;
442        let mut mu = Vec::with_capacity(experts.len() * hidden);
443        let mut u = Vec::new();
444        let mut bias = Vec::with_capacity(experts.len());
445        let mut k = 0usize;
446        for e in 0..ne_d {
447            let m = load_f32(model, &format!("{prefix}mlp.experts.{e}.desc.mu"), ov)
448                .map_err(CmfError::Parse)?;
449            if m.len() != hidden {
450                return Err(CmfError::Parse(format!(
451                    "{prefix}mlp.experts.{e}.desc.mu: {} != {hidden}",
452                    m.len()
453                )));
454            }
455            mu.extend_from_slice(&m);
456            let un = format!("{prefix}mlp.experts.{e}.desc.u");
457            if model.tensor(&un).is_some() {
458                let ue = load_f32(model, &un, ov).map_err(CmfError::Parse)?;
459                let ke = ue.len() / hidden.max(1);
460                if e == 0 {
461                    k = ke;
462                }
463                if ke != k {
464                    return Err(CmfError::Parse(format!("{un}: rank {ke} != {k}")));
465                }
466                u.extend_from_slice(&ue);
467            }
468            let bn = format!("{prefix}mlp.experts.{e}.desc.bias");
469            bias.push(if model.tensor(&bn).is_some() {
470                load_f32(model, &bn, ov)
471                    .map_err(CmfError::Parse)?
472                    .first()
473                    .copied()
474                    .unwrap_or(0.0)
475            } else {
476                0.0
477            });
478        }
479        let mut shell = vec![f32::INFINITY; ne_d];
480        for (gm, gu, gb, gs) in &grown_desc {
481            if gm.len() != hidden || gu.len() != k * hidden {
482                return Err(CmfError::Parse(format!(
483                    "{prefix}: grown expert descriptor {}×{} != trunk {hidden}×{k}",
484                    gm.len(),
485                    gu.len() / hidden.max(1)
486                )));
487            }
488            mu.extend_from_slice(gm);
489            u.extend_from_slice(gu);
490            bias.push(*gb);
491            shell.push(*gs);
492        }
493        Some(crate::pipeline::Resonance {
494            mu,
495            u,
496            k,
497            bias,
498            shell,
499        })
500    } else if model.tensor(&format!("{prefix}mlp.desc.mu")).is_some() {
501        let mu = load_f32(model, &format!("{prefix}mlp.desc.mu"), ov).map_err(CmfError::Parse)?;
502        let ne_d = experts.len();
503        let hidden = arch.hidden_size;
504        if mu.len() != ne_d * hidden {
505            return Err(CmfError::Parse(format!(
506                "{prefix}mlp.desc.mu: {} != {ne_d}×{hidden}",
507                mu.len()
508            )));
509        }
510        let u_name = format!("{prefix}mlp.desc.u");
511        let (u, k) = if model.tensor(&u_name).is_some() {
512            let u = load_f32(model, &u_name, ov).map_err(CmfError::Parse)?;
513            let k = u.len() / (ne_d * hidden).max(1);
514            (u, k)
515        } else {
516            (Vec::new(), 0)
517        };
518        let b_name = format!("{prefix}mlp.desc.bias");
519        let bias = if model.tensor(&b_name).is_some() {
520            load_f32(model, &b_name, ov).map_err(CmfError::Parse)?
521        } else {
522            vec![0.0; ne_d]
523        };
524        Some(crate::pipeline::Resonance {
525            mu,
526            u,
527            k,
528            bias,
529            shell: Vec::new(),
530        })
531    } else {
532        None
533    };
534    let moe = MoeFfn {
535        grown,
536        router,
537        experts,
538        top_k,
539        route_tau,
540        norm_topk_prob: cfg.norm_topk_prob,
541        router_sigmoid: cfg.router_sigmoid,
542        // Source-specific selected-sigmoid renormalization law. Recursive
543        // Flint and MiniMax M3.1 both preserve their reference runtime's
544        // FP32 `sum + 1e-20`; the older LFM2/DeepSeek noaux contract keeps
545        // its established `+1e-6` floor.
546        sigmoid_denom_eps: match arch.arch_name.as_str() {
547            "flint" | "minimax_m3_vl" => 1e-20,
548            _ => 1e-6,
549        },
550        expert_bias,
551        routed_scaling: cfg.routed_scaling_factor.unwrap_or(1.0),
552        shared,
553        stats: std::cell::RefCell::new(Vec::new()),
554        act_sq: std::cell::RefCell::new(Vec::new()),
555        act_rows: std::cell::RefCell::new(Vec::new()),
556        mask,
557        per_expert_scale,
558        router_input_norm,
559        resonance,
560    };
561    // Gemma-4 dual-branch layer: a dense MLP coexists with the routed
562    // experts, each branch inside its own norm sandwich.
563    if model
564        .tensor(&format!("{prefix}mlp.gate_proj.weight"))
565        .is_some()
566    {
567        let norm = |suffix: &str| -> Result<Vec<f32>, CmfError> {
568            load_f32(model, &format!("{prefix}{suffix}.weight"), ov).map_err(CmfError::Parse)
569        };
570        return Ok(FfnKind::DenseMoe(Box::new(crate::pipeline::DenseMoeFfn {
571            dense: load_dense(&format!("{prefix}mlp."))?,
572            moe,
573            post_norm_1: norm("post_feedforward_layernorm_1")?,
574            pre_norm_2: norm("pre_feedforward_layernorm_2")?,
575            post_norm_2: norm("post_feedforward_layernorm_2")?,
576        })));
577    }
578    Ok(FfnKind::Moe(moe))
579}
580
581/// Check the optional, tensor-derived MTP width declaration against the
582/// dense block actually loaded from the directory.  An MTP draft is allowed
583/// to have an independently compacted FFN, so the trunk-wide
584/// `arch.intermediate_size` is intentionally not part of this comparison.
585///
586/// `ffn_intermediate_sizes` has no unambiguous meaning for a routed or
587/// segmented FFN.  Refuse such a combination rather than interpreting a
588/// dense-width declaration as an expert width (or a core-vs-tube width).
589fn validate_generic_mtp_ffn_width(
590    cfg: &cortiq_core::MtpConfig,
591    ffn: &FfnKind,
592) -> Result<(), CmfError> {
593    let Some(widths) = cfg.ffn_intermediate_sizes.as_deref() else {
594        return Ok(());
595    };
596    if widths.len() != cfg.num_layers {
597        return Err(CmfError::Parse(format!(
598            "MTP ffn_intermediate_sizes has {} entries, expected {} (one per draft layer)",
599            widths.len(),
600            cfg.num_layers
601        )));
602    }
603    if widths.iter().any(|&width| width == 0) {
604        return Err(CmfError::Parse(
605            "MTP ffn_intermediate_sizes must contain only positive widths".into(),
606        ));
607    }
608    let FfnKind::Dense(dense) = ffn else {
609        return Err(CmfError::Parse(
610            "MTP ffn_intermediate_sizes is valid only for a dense MTP FFN; omit it for routed MTP"
611                .into(),
612        ));
613    };
614    if !dense.segs.is_empty() {
615        return Err(CmfError::Parse(
616            "MTP ffn_intermediate_sizes requires an unsplit dense MTP FFN; omit it for tube-segmented MTP"
617                .into(),
618        ));
619    }
620    let actual = dense.gate_proj.rows();
621    let declared = widths[0];
622    if declared != actual {
623        return Err(CmfError::Parse(format!(
624            "MTP ffn_intermediate_sizes[0]={declared}, but model.mtp.layers.0.mlp.gate_proj.weight has {actual} rows"
625        )));
626    }
627    Ok(())
628}
629
630// ───────────────────────── growth records ─────────────────────────
631
632/// Which `expert_append` records the loader mounts (`CMF_GROWTH`).
633#[derive(Clone, Copy, PartialEq, Eq, Debug)]
634pub enum GrowthMode {
635    /// Records with `status == "active"` (the default).
636    Active,
637    /// Every record that is not retired (`CMF_GROWTH=all`: quarantine
638    /// and stale_regate too — the gate measurement of a fresh record).
639    All,
640    /// None (`CMF_GROWTH=off`: the plain genome, F0's forward).
641    Off,
642}
643
644impl GrowthMode {
645    pub fn label(self) -> &'static str {
646        match self {
647            Self::Active => "active",
648            Self::All => "all",
649            Self::Off => "off",
650        }
651    }
652
653    /// Does this mode mount a record of `status`?
654    pub fn admits(self, status: Option<&str>) -> bool {
655        match self {
656            Self::Off => false,
657            Self::Active => status == Some("active"),
658            Self::All => status != Some("retired"),
659        }
660    }
661}
662
663/// `CMF_GROWTH` = `active` (unset) | `all` | `off`.
664pub fn growth_mode() -> GrowthMode {
665    match std::env::var("CMF_GROWTH")
666        .ok()
667        .as_deref()
668        .map(|v| v.trim().to_ascii_lowercase())
669        .as_deref()
670    {
671        Some("off") | Some("0") | Some("none") => GrowthMode::Off,
672        Some("all") => GrowthMode::All,
673        _ => GrowthMode::Active,
674    }
675}
676
677/// The `expert_append` records the current [`growth_mode`] mounts, with
678/// their positions in `header.skills` (the chain rule of the format is
679/// evaluated at that position).
680pub fn mounted_growth_records(
681    header: &cortiq_core::CmfHeader,
682) -> Vec<(usize, &cortiq_core::SkillRecord)> {
683    let mode = growth_mode();
684    header
685        .skills
686        .iter()
687        .enumerate()
688        .filter(|(_, s)| {
689            s.kind.as_deref() == Some(cortiq_core::knowledge::skill_kind::EXPERT_APPEND)
690                && mode.admits(s.status.as_deref())
691        })
692        .collect()
693}
694
695/// One grown expert as the loader read it from a record.
696struct GrownLoad {
697    ffn: DenseFfn,
698    mu: Vec<f32>,
699    u: Vec<f32>,
700    bias: f32,
701    shell: f32,
702    meta: crate::pipeline::GrownExpert,
703}
704
705/// The layer index of a `model.layers.{l}.` prefix (None for the MTP
706/// block and other prefixes — no growth record addresses those).
707fn layer_of_prefix(prefix: &str) -> Option<usize> {
708    prefix
709        .strip_prefix("model.layers.")?
710        .strip_suffix('.')?
711        .parse()
712        .ok()
713}
714
715/// The grown experts of the mounted `expert_append` records that grow the
716/// layer `prefix` addresses, in header order, each read from the record's
717/// own tensors (`skill.{id}.model.layers.{l}.mlp.experts.{e}.*`, the
718/// names the format's layout plan gives for the record's position). One
719/// log line per mounted record and layer.
720fn mount_growth(
721    model: &Arc<CmfModel>,
722    prefix: &str,
723    ov: &Overlay,
724    load_dense: &dyn Fn(&str) -> Result<DenseFfn, CmfError>,
725) -> Result<Vec<GrownLoad>, CmfError> {
726    use cortiq_core::knowledge::expert_leaf;
727    let Some(layer) = layer_of_prefix(prefix) else {
728        return Ok(Vec::new());
729    };
730    let records = mounted_growth_records(&model.header);
731    let mut out = Vec::new();
732    for (at, rec) in records {
733        if !rec.layers.contains(&layer) {
734            continue;
735        }
736        let plan = cortiq_core::expert_append_layout(&model.header, &model.tensors, at, rec)
737            .map_err(|e| CmfError::Parse(format!("{prefix}: growth record '{}': {e}", rec.id)))?;
738        let mut by_expert: std::collections::BTreeMap<usize, Vec<&cortiq_core::ExpertTensorSpec>> =
739            Default::default();
740        for p in plan.iter().filter(|p| p.layer == layer) {
741            by_expert.entry(p.expert).or_default().push(p);
742        }
743        let first = out.len();
744        for (e, leaves) in &by_expert {
745            let name = |leaf: &str| -> Result<String, CmfError> {
746                leaves
747                    .iter()
748                    .find(|p| p.leaf == leaf)
749                    .map(|p| p.name.clone())
750                    .ok_or_else(|| {
751                        CmfError::Parse(format!(
752                            "{prefix}: growth record '{}' expert {e}: layout has no '{leaf}'",
753                            rec.id
754                        ))
755                    })
756            };
757            let ffn = load_dense(&format!("skill.{}.{prefix}mlp.experts.{e}.", rec.id))?;
758            let mu = load_f32(model, &name(expert_leaf::MU)?, ov).map_err(CmfError::Parse)?;
759            let u = if leaves.iter().any(|p| p.leaf == expert_leaf::U) {
760                load_f32(model, &name(expert_leaf::U)?, ov).map_err(CmfError::Parse)?
761            } else {
762                Vec::new()
763            };
764            let scalar = |leaf: &str| -> Result<f32, CmfError> {
765                load_f32(model, &name(leaf)?, ov)
766                    .map_err(CmfError::Parse)?
767                    .first()
768                    .copied()
769                    .ok_or_else(|| {
770                        CmfError::Parse(format!(
771                            "{prefix}: growth record '{}' expert {e}: empty '{leaf}'",
772                            rec.id
773                        ))
774                    })
775            };
776            let bias = scalar(expert_leaf::BIAS)?;
777            let shell = scalar(expert_leaf::SHELL)?;
778            if !shell.is_finite() {
779                return Err(CmfError::Parse(format!(
780                    "{prefix}: growth record '{}' expert {e}: desc.shell {shell} is not finite",
781                    rec.id
782                )));
783            }
784            out.push(GrownLoad {
785                ffn,
786                mu,
787                u,
788                bias,
789                shell,
790                meta: crate::pipeline::GrownExpert {
791                    record: rec.id.clone(),
792                    record_index: at,
793                    layer,
794                    expert: *e,
795                },
796            });
797        }
798        let declared: Vec<usize> = by_expert.keys().copied().collect();
799        tracing::info!(
800            "growth: layer {layer}: mounted expert_append '{}' (status {}) — {} experts, declared {:?}, shells {:?}",
801            rec.id,
802            rec.status.as_deref().unwrap_or("?"),
803            by_expert.len(),
804            declared,
805            out[first..].iter().map(|g| g.shell).collect::<Vec<_>>()
806        );
807    }
808    Ok(out)
809}
810
811/// Task mask over routed experts: DTG-MA applied to MoE.
812///
813/// This is deliberately diagnostic-only. A route-mass sidecar can look good
814/// on a short perplexity window and still collapse during a long
815/// autoregressive generation: excluding a low-mass expert changes the model,
816/// and the changed prefix changes every later route. Consequently a nearby
817/// `<model>.moe-mass.json` is NEVER adopted implicitly. `CMF_MOE_MASK=...`
818/// remains an explicit experiment and accepts both weighted and legacy count
819/// files; production acceleration must preserve the full router and treat a
820/// non-resident winner as an exact cold completion.
821pub(crate) fn moe_task_mask(
822    _model: &std::sync::Arc<CmfModel>,
823    prefix: &str,
824    ne: usize,
825) -> Option<Vec<bool>> {
826    use std::sync::OnceLock;
827    static CFG: OnceLock<Option<(std::collections::HashMap<usize, Vec<u64>>, f64)>> =
828        OnceLock::new();
829    let cfg = CFG.get_or_init(|| {
830        let path = std::path::PathBuf::from(std::env::var("CMF_MOE_MASK").ok()?);
831        let shown = path.display();
832        let text = std::fs::read_to_string(&path)
833            .map_err(|e| tracing::warn!("CMF_MOE_MASK: cannot read {shown}: {e}"))
834            .ok()?;
835        let map: std::collections::HashMap<String, Vec<u64>> = serde_json::from_str(&text)
836            .map_err(|e| tracing::warn!("CMF_MOE_MASK: bad JSON in {shown}: {e}"))
837            .ok()?;
838        // Weighted dumps store normalized route mass in fixed-point units
839        // and therefore have per-layer totals many orders above the old
840        // top-k vote counts. The magnitude distinguishes the two explicit
841        // diagnostic formats without relying on a special filename.
842        let weighted = map
843            .values()
844            .any(|row| row.iter().copied().sum::<u64>() >= 1_000_000);
845        let cover = std::env::var("CMF_MOE_MASK_COVER")
846            .ok()
847            .and_then(|v| v.parse::<f64>().ok())
848            .filter(|&c| c > 0.0 && c <= 1.0)
849            .unwrap_or(if weighted { 0.925 } else { 0.9 });
850        tracing::info!("MoE task mask: {shown}, cover {cover}");
851        Some((
852            map.into_iter()
853                .filter_map(|(k, v)| Some((k.parse::<usize>().ok()?, v)))
854                .collect(),
855            cover,
856        ))
857    });
858    let (stats, cover) = cfg.as_ref()?;
859    // The layer index rides in the tensor prefix ("model.layers.N.").
860    let li: usize = prefix
861        .split("layers.")
862        .nth(1)?
863        .split('.')
864        .next()?
865        .parse()
866        .ok()?;
867    let counts = stats.get(&li)?;
868    if counts.len() != ne {
869        tracing::warn!(
870            "CMF_MOE_MASK: layer {li} has {} counts, model has {ne} experts — skipped",
871            counts.len()
872        );
873        return None;
874    }
875    let total: u64 = counts.iter().sum();
876    if total == 0 {
877        return None;
878    }
879    let mut order: Vec<usize> = (0..ne).collect();
880    order.sort_unstable_by_key(|&e| std::cmp::Reverse(counts[e]));
881    let mut mask = vec![false; ne];
882    let mut acc = 0u64;
883    let mut kept = 0usize;
884    for &e in &order {
885        mask[e] = true;
886        acc += counts[e];
887        kept += 1;
888        if (acc as f64) >= cover * (total as f64) {
889            break;
890        }
891    }
892    tracing::info!(
893        "MoE task mask L{li}: {kept}/{ne} experts for {:.0}% mass",
894        cover * 100.0
895    );
896    Some(mask)
897}
898
899pub(crate) fn load_matrix(
900    model: &Arc<CmfModel>,
901    name: &str,
902    force_f32: bool,
903    ov: &Overlay,
904) -> Result<QTensor, CmfError> {
905    // Claim 14: a blended working tensor is materialized in f32 and
906    // held resident (the overlay-cache slot); single skills stay
907    // zero-copy pointers into the mmap.
908    if ov.blend_touches(model, name) {
909        if let Overlay::Blend(list) = ov {
910            let entry = model
911                .tensor(name)
912                .ok_or_else(|| CmfError::MissingTensor(name.to_string()))?;
913            let data =
914                blend_f32(model, name, list).map_err(|e| CmfError::Parse(format!("blend: {e}")))?;
915            return Ok(QTensor::from_f32(data, entry.shape[0], entry.shape[1]));
916        }
917    }
918    let skill = match ov {
919        Overlay::One(s) => Some(*s),
920        _ => None,
921    };
922    // Tensor-source indirection (spec §9): the skill's replacement is
923    // read in place of the backbone tensor — either/or, never a sum.
924    let name: &str = &match skill {
925        Some(sid) if model.tensor(&format!("skill.{sid}.{name}")).is_some() => {
926            format!("skill.{sid}.{name}")
927        }
928        _ => name.to_string(),
929    };
930    let err = |e: String| CmfError::Parse(format!("weight loading: {e}"));
931    if force_f32 {
932        let entry = model
933            .tensor(name)
934            .ok_or_else(|| CmfError::MissingTensor(name.to_string()))?;
935        if entry.shape.len() != 2 {
936            return Err(err(format!("'{name}' is not 2-D")));
937        }
938        let data = load_f32(model, name, &Overlay::None).map_err(err)?;
939        Ok(QTensor::from_f32(data, entry.shape[0], entry.shape[1]))
940    } else {
941        QTensor::from_model(model, name).map_err(err)
942    }
943}
944
945impl Pipeline {
946    /// Build a runnable pipeline from an opened CMF model.
947    pub fn from_model(
948        model: &Arc<CmfModel>,
949        sampler_config: SamplerConfig,
950    ) -> Result<Self, CmfError> {
951        Self::from_model_with_skill(model, sampler_config, None)
952    }
953
954    /// Build an encoder-only pipeline from an opened CMF model.
955    ///
956    /// Some component models (for example a text tower used by an image
957    /// pipeline) intentionally end at the final normalized hidden states and
958    /// therefore have no language-model head.  Keep that exception explicit:
959    /// regular [`Self::from_model`] continues to reject a non-tied model
960    /// without `lm_head.weight`, so a partially packed generative model can
961    /// never be mistaken for a runnable one.
962    ///
963    /// The returned pipeline is for [`Self::encode_hidden_states`] only.  Its
964    /// placeholder head is deliberately one row wide and must not be exposed
965    /// as a generative model.
966    pub fn from_encoder_model(
967        model: &Arc<CmfModel>,
968        sampler_config: SamplerConfig,
969    ) -> Result<Self, CmfError> {
970        Self::from_model_with_overlay(model, sampler_config, &Overlay::None, true)
971    }
972
973    /// Same, with a skill overlaid (spec §9): every layer tensor is
974    /// resolved through tensor-source indirection — the skill's
975    /// full-shape replacement is read in place of the backbone tensor.
976    /// No per-skill model is ever assembled: Mapped tensors are
977    /// pointers into the one shared mmap.
978    pub fn from_model_with_skill(
979        model: &Arc<CmfModel>,
980        sampler_config: SamplerConfig,
981        skill: Option<&str>,
982    ) -> Result<Self, CmfError> {
983        match skill {
984            Some(s) => {
985                Self::from_model_with_overlay(model, sampler_config, &Overlay::One(s), false)
986            }
987            None => Self::from_model_with_overlay(model, sampler_config, &Overlay::None, false),
988        }
989    }
990
991    /// Soft superposition (claim 14): working tensors accumulated from
992    /// the given (skill, weight) list — softmax(−E/T) upstream.
993    pub fn from_model_with_blend(
994        model: &Arc<CmfModel>,
995        sampler_config: SamplerConfig,
996        blend: &[(String, f32)],
997    ) -> Result<Self, CmfError> {
998        Self::from_model_with_overlay(model, sampler_config, &Overlay::Blend(blend), false)
999    }
1000
1001    fn skill_file_guard(model: &CmfModel) -> Result<(), CmfError> {
1002        // A decision profile (encoder + resonance skills) has no language
1003        // model in it at all; the generative pipeline must not try to
1004        // assemble one from its tensors.
1005        if model.required_features & cortiq_core::format::features::DECISION != 0 {
1006            return Err(CmfError::Parse(DECISION_MODEL_REFUSAL.into()));
1007        }
1008        // A standalone skill file carries a PARTIAL tensor set cut against
1009        // a base; running it would be half a network answering questions.
1010        if model.required_features & cortiq_core::format::features::SKILL_FILE != 0 {
1011            return Err(CmfError::Parse(
1012                "this file is a standalone SKILL, not a runnable model — attach it: \
1013                 cortiq skill apply <base.cmf> <this file> -o specialist.cmf"
1014                    .into(),
1015            ));
1016        }
1017        Ok(())
1018    }
1019
1020    fn from_model_with_overlay(
1021        model: &Arc<CmfModel>,
1022        sampler_config: SamplerConfig,
1023        ov: &Overlay,
1024        encoder_only: bool,
1025    ) -> Result<Self, CmfError> {
1026        // Refuse non-runnable files first, before any process-wide state
1027        // (the device cache directory, the graph verdict) is touched on
1028        // their behalf.
1029        Self::skill_file_guard(model)?;
1030        // Small device caches (probe verdicts, compiled pipelines) go
1031        // beside the model: it is a directory the caller demonstrably
1032        // writes to, which `std::env::temp_dir()` is not inside an
1033        // Android app sandbox.
1034        if let Some(dir) = model.path.parent() {
1035            crate::gpu::set_cache_dir(dir.to_path_buf());
1036        }
1037        // The token-graph refusal verdict lives in each pipeline
1038        // (`Pipeline::graph_refused`): a new pipeline starts clean and
1039        // loading one — a skill lane mid-traffic — never touches the
1040        // verdict of the others (R4/NF-2; this used to reset a
1041        // process-wide flag under running slots).
1042        let skill = match ov {
1043            Overlay::One(s) => Some(*s),
1044            _ => None,
1045        };
1046        if let Some(sid) = skill {
1047            let known = model.header.skills.iter().any(|s| s.id == sid)
1048                || model.skill_tensors(sid).next().is_some();
1049            if !known {
1050                return Err(CmfError::Parse(format!(
1051                    "skill '{sid}' not in this container (header.skills: {:?})",
1052                    model
1053                        .header
1054                        .skills
1055                        .iter()
1056                        .map(|s| &s.id)
1057                        .collect::<Vec<_>>()
1058                )));
1059            }
1060            tracing::info!(
1061                "skill '{sid}': {} replacement tensors overlaid",
1062                model.skill_tensors(sid).count()
1063            );
1064        }
1065        let arch = model.arch().clone();
1066        let err = |e: String| CmfError::Parse(format!("weight loading: {e}"));
1067        if let Some(heads) = &arch.attention_heads_per_layer {
1068            if heads.len() != arch.num_layers {
1069                return Err(CmfError::Parse(format!(
1070                    "arch.attention_heads_per_layer has {} entries, expected {}",
1071                    heads.len(),
1072                    arch.num_layers
1073                )));
1074            }
1075            if let Some((li, &nh)) = heads
1076                .iter()
1077                .enumerate()
1078                .find(|(_, nh)| **nh == 0 || **nh % arch.num_kv_heads != 0)
1079            {
1080                return Err(CmfError::Parse(format!(
1081                    "layer {li} has {nh} Q heads, which must be nonzero and divisible by {} KV heads",
1082                    arch.num_kv_heads
1083                )));
1084            }
1085        }
1086        if arch
1087            .layer_types
1088            .iter()
1089            .any(|t| matches!(t, LayerType::SlidingAttention))
1090            && arch.sliding_window.is_none()
1091        {
1092            return Err(CmfError::Parse(
1093                "model has SlidingAttention layers but no arch.sliding_window".into(),
1094            ));
1095        }
1096        validate_flint_profile(model, &arch)?;
1097
1098        // Masks × quantized mmap: only the HEAD-mask path needs f32
1099        // slices, so f32 is forced only when some mask actually restricts
1100        // attention heads. FFN masks run sparse directly on the quant
1101        // bytes (sparse_ffn_quant), and embed/lm_head are never masked.
1102        // The old condition forced f32 for ANY mask: a 4.17 B file whose
1103        // mask touched only the FFN dequantized to 16.7 GB at load and
1104        // ran the bare-f32 GEMMs — 0.0 tok/s on a laptop that swapped,
1105        // and a 30× crawl on a 48-core server. A mask with no head rows
1106        // costs nothing now.
1107        let heads_masked = model.masks.masks.iter().any(|m| {
1108            m.head_masks.iter().any(|row| {
1109                let mut bits = 0usize;
1110                for &b in row.iter() {
1111                    bits += b.count_ones() as usize;
1112                }
1113                !row.is_empty() && bits < arch.num_attention_heads
1114            })
1115        });
1116        let force_f32 = heads_masked; // attention only (head masks)
1117
1118        // ── Tokenizer: embedded → sidecar → byte-level fallback ──
1119        let mut tokenizer = if let Some(vocab_bytes) = &model.vocab {
1120            Tokenizer::from_bytes(vocab_bytes)
1121                .map_err(|e| CmfError::Parse(format!("embedded tokenizer: {e}")))?
1122        } else if let Some(g) = &model.header.genome {
1123            // A genome binds its tokenizer (the trunk hash covers the VOCAB
1124            // section): whatever tokenizer.json lies beside the file is not
1125            // part of it (NF-5; core refuses such a file at open as well).
1126            return Err(CmfError::Parse(format!(
1127                "genome '{}' carries no embedded tokenizer (VOCAB) — a sidecar tokenizer.json \
1128                 is not part of the genome; refusing",
1129                g.id
1130            )));
1131        } else {
1132            let sidecar = model.path.with_file_name("tokenizer.json");
1133            if sidecar.exists() {
1134                Tokenizer::from_file(&sidecar)
1135                    .map_err(|e| CmfError::Parse(format!("sidecar tokenizer: {e}")))?
1136            } else {
1137                tracing::warn!("no tokenizer in file or sidecar — using byte-level fallback");
1138                Tokenizer::byte_level()
1139            }
1140        };
1141        // Chat/eos bundle (spec §6.1): the FILE defines chat behavior.
1142        if let Some(tc) = &model.header.tokenizer_config {
1143            tokenizer.chat_template = tc.chat_template.clone();
1144            tokenizer.extra_eos.extend(tc.eos_token_ids.iter().copied());
1145            if tokenizer.bos_token_id.is_none() {
1146                tokenizer.bos_token_id = tc.bos_token_id;
1147            }
1148            tracing::info!(
1149                "chat bundle: template {} chars, {} stop ids",
1150                tc.chat_template.as_deref().map(str::len).unwrap_or(0),
1151                tc.eos_token_ids.len()
1152            );
1153        }
1154        // Gemma's contract requires <bos> at sequence start, but its
1155        // tokenizer.json post-processor does not add it (the chat
1156        // template does). Raw prompts need it too — word salad without.
1157        if arch.arch_name.to_lowercase().contains("gemma") && tokenizer.bos_token_id.is_some() {
1158            tokenizer.add_bos = true;
1159        }
1160
1161        // ── Top-level weights (never masked → always quantized) ──
1162        let embed_tokens = load_matrix(model, "model.embed_tokens.weight", false, ov)?;
1163        let final_norm = if arch.qwen4_exp.is_some() || arch.dory.is_some() {
1164            // qwen4_exp folds its four streams through a learned global
1165            // hyper mixer and has no conventional final RMSNorm; Dory's hidden
1166            // state is on the unit sphere and goes straight to the head.
1167            vec![0.0; arch.hidden_size]
1168        } else {
1169            load_f32(model, "model.norm.weight", ov).map_err(err)?
1170        };
1171        let lm_head = if model.tensor("lm_head.weight").is_some() {
1172            load_matrix(model, "lm_head.weight", false, ov)?
1173        } else if arch.tie_word_embeddings {
1174            // Tied: reuse the embedding matrix (re-open, cheap for Mapped).
1175            load_matrix(model, "model.embed_tokens.weight", false, ov)?
1176        } else if encoder_only {
1177            // `Pipeline` owns an LM-head slot for the generative APIs, but an
1178            // encoder component correctly has none.  Keep the inert stand-in
1179            // tiny: `encode_hidden_states` never reads it, and the public
1180            // generative constructors above still fail before reaching here.
1181            QTensor::from_f32(vec![0.0; arch.hidden_size], 1, arch.hidden_size)
1182        } else {
1183            return Err(CmfError::MissingTensor(
1184                "lm_head.weight (and tie_word_embeddings is false)".into(),
1185            ));
1186        };
1187
1188        // ── Linear-core geometry (required if any linear layer exists) ──
1189        let has_linear = arch
1190            .layer_types
1191            .iter()
1192            .any(|t| matches!(t, LayerType::LinearAttention));
1193        let mut vmf_cfg = None;
1194        let mut gdn_cfg = None;
1195        // `Some` means this file uses the versioned Phase-Delta operator;
1196        // the sorted indices are threaded into each layer's weights below.
1197        // Legacy kinds must not carry selector metadata: accepting and
1198        // ignoring it would recreate the original silent semantic break.
1199        let mut phase_delta_layers: Option<Vec<usize>> = None;
1200        if !has_linear
1201            && arch
1202                .linear_core
1203                .as_ref()
1204                .is_some_and(|lc| lc.phase_delta_layers.is_some())
1205        {
1206            return Err(CmfError::Parse(
1207                "phase_delta_layers is only valid with LinearAttention and \
1208                 vmf_phase_delta_v1"
1209                    .into(),
1210            ));
1211        }
1212        if has_linear {
1213            let lc = arch.linear_core.as_ref().ok_or_else(|| {
1214                CmfError::Parse(
1215                    "model has LinearAttention layers but no arch.linear_core — \
1216                     reconvert with the current converter"
1217                        .into(),
1218                )
1219            })?;
1220            let need = |v: Option<usize>, name: &str| {
1221                v.ok_or_else(|| CmfError::Parse(format!("linear core needs arch.{name}")))
1222            };
1223            match lc.kind.as_str() {
1224                "vmf_phase" => {
1225                    if lc.phase_delta_layers.is_some() {
1226                        return Err(CmfError::Parse(
1227                            "legacy vmf_phase cannot carry phase_delta_layers; use vmf_phase_delta_v1"
1228                                .into(),
1229                        ));
1230                    }
1231                    vmf_cfg = Some(VmfPhaseCfg {
1232                        num_heads: lc.num_heads,
1233                        nphase: need(lc.nphase, "linear_core.nphase")?,
1234                        value_head_dim: lc.value_head_dim,
1235                        hidden_size: arch.hidden_size,
1236                        // Phase-mass correction: default 0 (disabled); CMF_PHASE_MASS
1237                        // widens the phase kernel for folded-unhealed models.
1238                        phase_mass: std::env::var("CMF_PHASE_MASS")
1239                            .ok()
1240                            .and_then(|v| v.parse().ok())
1241                            .unwrap_or(0.0),
1242                    });
1243                }
1244                "vmf_phase_delta_v1" => {
1245                    let mut selected = lc.phase_delta_layers.clone().ok_or_else(|| {
1246                        CmfError::Parse(
1247                            "vmf_phase_delta_v1 requires a non-empty phase_delta_layers selector"
1248                                .into(),
1249                        )
1250                    })?;
1251                    if selected.is_empty() {
1252                        return Err(CmfError::Parse(
1253                            "vmf_phase_delta_v1 phase_delta_layers is empty".into(),
1254                        ));
1255                    }
1256                    if arch.layer_types.len() != arch.num_layers {
1257                        return Err(CmfError::Parse(format!(
1258                            "phase_delta layer schedule has {} entries, expected {}",
1259                            arch.layer_types.len(),
1260                            arch.num_layers
1261                        )));
1262                    }
1263                    selected.sort_unstable();
1264                    for pair in selected.windows(2) {
1265                        if pair[0] == pair[1] {
1266                            return Err(CmfError::Parse(format!(
1267                                "phase_delta_layers contains duplicate layer {}",
1268                                pair[0]
1269                            )));
1270                        }
1271                    }
1272                    for &li in &selected {
1273                        if li >= arch.num_layers {
1274                            return Err(CmfError::Parse(format!(
1275                                "phase_delta layer {li} out of range for {} layers",
1276                                arch.num_layers
1277                            )));
1278                        }
1279                        if !matches!(arch.layer_types[li], LayerType::LinearAttention) {
1280                            return Err(CmfError::Parse(format!(
1281                                "phase_delta layer {li} is not a LinearAttention layer"
1282                            )));
1283                        }
1284                    }
1285                    let nphase = need(lc.nphase, "linear_core.nphase")?;
1286                    if lc.num_heads == 0 || nphase == 0 || lc.value_head_dim == 0 {
1287                        return Err(CmfError::Parse(
1288                            "vmf_phase_delta_v1 requires positive heads, nphase, and value_head_dim"
1289                                .into(),
1290                        ));
1291                    }
1292                    phase_delta_layers = Some(selected);
1293                    vmf_cfg = Some(VmfPhaseCfg {
1294                        num_heads: lc.num_heads,
1295                        nphase,
1296                        value_head_dim: lc.value_head_dim,
1297                        hidden_size: arch.hidden_size,
1298                        // Phase-Delta's normalized features are a closed
1299                        // operator contract. CMF_PHASE_MASS is a legacy
1300                        // tuning knob and is intentionally ignored by the
1301                        // phase_delta branch in linear_core.
1302                        phase_mass: 0.0,
1303                    });
1304                }
1305                "gated_delta_net" => {
1306                    if lc.phase_delta_layers.is_some() {
1307                        return Err(CmfError::Parse(
1308                            "gated_delta_net cannot carry phase_delta_layers".into(),
1309                        ));
1310                    }
1311                    gdn_cfg = Some(GdnCfg {
1312                        num_v_heads: lc.num_heads,
1313                        num_k_heads: need(arch.linear_num_key_heads, "linear_num_key_heads")?,
1314                        key_head_dim: need(arch.linear_key_head_dim, "linear_key_head_dim")?,
1315                        value_head_dim: lc.value_head_dim,
1316                        conv_kernel: need(arch.linear_conv_kernel_dim, "linear_conv_kernel_dim")?,
1317                        hidden_size: arch.hidden_size,
1318                        rms_eps: arch.rms_norm_eps,
1319                        output_gate_sigmoid: false,
1320                    });
1321                }
1322                other => {
1323                    return Err(CmfError::Parse(format!(
1324                        "unknown linear core '{other}' (this runtime executes: \
1325                         gated_delta_net, vmf_phase, vmf_phase_delta_v1)"
1326                    )));
1327                }
1328            }
1329        }
1330
1331        // ── KDA geometry (Kimi Linear / Kimi-K3 delta-attention layers) ──
1332        let has_kda = arch.layer_types.iter().any(|t| matches!(t, LayerType::Kda));
1333        let kda_cfg = if has_kda {
1334            let need = |v: Option<usize>, name: &str| {
1335                v.ok_or_else(|| CmfError::Parse(format!("KDA core needs arch.{name}")))
1336            };
1337            Some(crate::linear_core::KdaCfg {
1338                num_heads: need(arch.linear_num_key_heads, "linear_num_key_heads")?,
1339                head_k_dim: need(arch.linear_key_head_dim, "linear_key_head_dim")?,
1340                head_v_dim: need(arch.linear_value_head_dim, "linear_value_head_dim")?,
1341                conv_kernel: need(arch.linear_conv_kernel_dim, "linear_conv_kernel_dim")?,
1342                hidden_size: arch.hidden_size,
1343                rms_eps: arch.rms_norm_eps,
1344            })
1345        } else {
1346            None
1347        };
1348
1349        // ── Short-convolution geometry (LFM2 conv mixer layers) ──
1350        let has_short_conv = arch
1351            .layer_types
1352            .iter()
1353            .any(|t| matches!(t, LayerType::ShortConv));
1354        let short_conv_cfg = if has_short_conv {
1355            Some(ShortConvCfg {
1356                hidden_size: arch.hidden_size,
1357                kernel: arch.linear_conv_kernel_dim.ok_or_else(|| {
1358                    CmfError::Parse(
1359                        "model has ShortConv layers but no arch.linear_conv_kernel_dim — \
1360                         reconvert with the current converter"
1361                            .into(),
1362                    )
1363                })?,
1364            })
1365        } else {
1366            None
1367        };
1368
1369        // ── Layers ──
1370        let load_full_attn = |prefix: &str, layer: Option<usize>| -> Result<AttnKind, CmfError> {
1371            let t = |suffix: &str| load_matrix(model, &format!("{prefix}{suffix}"), force_f32, ov);
1372            let n = |suffix: &str| -> Option<Vec<f32>> {
1373                model
1374                    .tensor(&format!("{prefix}{suffix}"))
1375                    .and_then(|_| load_f32(model, &format!("{prefix}{suffix}"), ov).ok())
1376            };
1377            // DeepSeek-V2 MLA: the latent projections replace the k/v pair.
1378            if let Some(mla) = arch.mla.as_ref() {
1379                // Compressed q (K3/V3): q_a → rms → q_b; direct otherwise.
1380                let (q_proj, q_a, q_a_norm) = if mla.q_lora_rank.is_some() {
1381                    (
1382                        t("self_attn.q_b_proj.weight")?,
1383                        Some(t("self_attn.q_a_proj.weight")?),
1384                        Some(n("self_attn.q_a_layernorm.weight").ok_or_else(|| {
1385                            CmfError::Parse(format!("{prefix}: MLA needs q_a_layernorm"))
1386                        })?),
1387                    )
1388                } else {
1389                    (t("self_attn.q_proj.weight")?, None, None)
1390                };
1391                let hd = mla.qk_rope_head_dim + mla.qk_nope_head_dim;
1392                let nh = q_proj.rows() / hd;
1393                // YaRN mscale²: DeepSeek corrects the softmax scale by
1394                // (0.1·mscale_all_dim·ln(factor)+1)².
1395                let mut scale = 1.0 / (hd as f32).sqrt();
1396                if let Some(y) = arch.yarn.as_ref() {
1397                    if let Some(m) = y.mscale_all_dim.filter(|&m| m > 0.0) {
1398                        let ms = 0.1 * m * y.factor.ln() + 1.0;
1399                        scale *= ms * ms;
1400                    }
1401                }
1402                return Ok(AttnKind::Mla(Box::new(crate::pipeline::MlaWeights {
1403                    q_proj,
1404                    q_a,
1405                    q_a_norm,
1406                    kv_a: t("self_attn.kv_a_proj_with_mqa.weight")?,
1407                    kv_a_norm: n("self_attn.kv_a_layernorm.weight").ok_or_else(|| {
1408                        CmfError::Parse(format!("{prefix}: MLA needs kv_a_layernorm"))
1409                    })?,
1410                    kv_b: t("self_attn.kv_b_proj.weight")?,
1411                    o_proj: t("self_attn.o_proj.weight")?,
1412                    nh,
1413                    qk_rope: mla.qk_rope_head_dim,
1414                    qk_nope: mla.qk_nope_head_dim,
1415                    v_dim: mla.v_head_dim,
1416                    lora: mla.kv_lora_rank,
1417                    scale,
1418                    nope: mla.nope,
1419                })));
1420            }
1421            let wq = t("self_attn.q_proj.weight")?;
1422            let nh = layer
1423                .and_then(|li| {
1424                    arch.attention_heads_per_layer
1425                        .as_ref()
1426                        .and_then(|v| v.get(li).copied())
1427                })
1428                .unwrap_or(arch.num_attention_heads);
1429            // Qwen3.5 output gate: q_proj rows = 2·nh·hd (per-head [q; gate]).
1430            // Gemma-4 global layers legitimately have nh·global_head_dim
1431            // rows (which can equal 2·nh·hd) — never gated.
1432            let output_gate = arch.global_head_dim.is_none() && wq.rows() == 2 * nh * arch.head_dim;
1433            // Gemma-4 global layers run MQA at global_head_dim — their
1434            // q_proj legitimately carries nh·ghd rows.
1435            let is_global_layer = arch.global_head_dim.is_some()
1436                && layer.is_some_and(|li| {
1437                    arch.sliding_window_pattern
1438                        .is_some_and(|p| p > 0 && (li + 1) % p == 0)
1439                });
1440            let expect = if is_global_layer {
1441                nh * arch.global_head_dim.unwrap_or(arch.head_dim)
1442            } else {
1443                nh * arch.head_dim
1444            };
1445            if !output_gate && wq.rows() != expect {
1446                return Err(CmfError::Parse(format!(
1447                    "{prefix}self_attn.q_proj.weight rows={} != heads({nh}) * head_dim({})",
1448                    wq.rows(),
1449                    expect / nh.max(1)
1450                )));
1451            }
1452            let gate_name = format!("{prefix}self_attn.g_proj.weight");
1453            let softplus_gate = if model.tensor(&gate_name).is_some() {
1454                let gate = load_matrix(model, &gate_name, force_f32, ov)?;
1455                if gate.cols() != arch.hidden_size {
1456                    return Err(CmfError::Parse(format!(
1457                        "{gate_name} cols={} != hidden_size ({})",
1458                        gate.cols(),
1459                        arch.hidden_size
1460                    )));
1461                }
1462                let per_head = if gate.rows() == nh {
1463                    true
1464                } else if gate.rows() == nh * arch.head_dim {
1465                    false
1466                } else {
1467                    return Err(CmfError::Parse(format!(
1468                        "{gate_name} rows={} must equal heads ({nh}) or heads*head_dim ({})",
1469                        gate.rows(),
1470                        nh * arch.head_dim
1471                    )));
1472                };
1473                Some((gate, per_head))
1474            } else {
1475                None
1476            };
1477            // Qwen2-family projection biases (by tensor presence).
1478            let bias = match (
1479                n("self_attn.q_proj.bias"),
1480                n("self_attn.k_proj.bias"),
1481                n("self_attn.v_proj.bias"),
1482            ) {
1483                (Some(a), Some(b), Some(c)) => Some((a, b, c)),
1484                _ => None,
1485            };
1486            let wk = t("self_attn.k_proj.weight")?;
1487            let wv = t("self_attn.v_proj.weight")?;
1488            let wo = t("self_attn.o_proj.weight")?;
1489            // K/V/O geometry, checked here and never at run time: a
1490            // mapped matvec accepts any `out`/`x` at least as long as its
1491            // rows/cols, so a V narrower than the cache's head or an
1492            // o_proj wider than nh·v would otherwise run silently wrong.
1493            // KV heads come from the header — per layer when the model
1494            // varies them (MiMo-V2: 4 full / 8 sliding), Gemma-4 global
1495            // layers carry their own (heads, width).
1496            let (nkv_l, hd_l) = if is_global_layer {
1497                (
1498                    arch.num_global_kv_heads.unwrap_or(arch.num_kv_heads),
1499                    arch.global_head_dim.unwrap_or(arch.head_dim),
1500                )
1501            } else {
1502                (
1503                    layer
1504                        .and_then(|li| {
1505                            arch.kv_heads_per_layer
1506                                .as_ref()
1507                                .and_then(|v| v.get(li).copied())
1508                        })
1509                        .unwrap_or(arch.num_kv_heads),
1510                    arch.head_dim,
1511                )
1512            };
1513            let vd = if is_global_layer {
1514                hd_l
1515            } else {
1516                arch.v_head_dim.unwrap_or(hd_l)
1517            };
1518            let shape_err = |what: String| {
1519                CmfError::Parse(format!(
1520                    "{prefix}self_attn: {what} (heads {nh}, kv heads {nkv_l}, head_dim {hd_l}, \
1521                     v_head_dim {vd}) — file and header disagree"
1522                ))
1523            };
1524            if nkv_l == 0 || nh % nkv_l != 0 {
1525                return Err(shape_err(format!(
1526                    "{nkv_l} KV heads must be nonzero and divide {nh} Q heads"
1527                )));
1528            }
1529            if vd == 0 || vd > hd_l {
1530                return Err(shape_err(format!("v_head_dim {vd} must be in 1..={hd_l}")));
1531            }
1532            if wk.rows() != nkv_l * hd_l {
1533                return Err(shape_err(format!(
1534                    "k_proj rows={} != kv_heads*head_dim={}",
1535                    wk.rows(),
1536                    nkv_l * hd_l
1537                )));
1538            }
1539            if wv.rows() != nkv_l * vd {
1540                return Err(shape_err(format!(
1541                    "v_proj rows={} != kv_heads*v_head_dim={}",
1542                    wv.rows(),
1543                    nkv_l * vd
1544                )));
1545            }
1546            if wo.cols() != nh * vd {
1547                return Err(shape_err(format!(
1548                    "o_proj cols={} != heads*v_head_dim={}",
1549                    wo.cols(),
1550                    nh * vd
1551                )));
1552            }
1553            if vd < hd_l && (output_gate || softplus_gate.is_some()) {
1554                return Err(shape_err(
1555                    "an attention output gate with V heads narrower than Q/K is not supported"
1556                        .into(),
1557                ));
1558            }
1559            Ok(AttnKind::Full {
1560                wq,
1561                wk,
1562                wv,
1563                wo,
1564                q_norm: n("self_attn.q_norm.weight"),
1565                k_norm: n("self_attn.k_norm.weight"),
1566                output_gate,
1567                softplus_gate,
1568                bias,
1569            })
1570        };
1571
1572        let load_linear_attn = |prefix: &str, li: usize| -> Result<AttnKind, CmfError> {
1573            if gdn_cfg.is_some() {
1574                // Faithful vendor operator: tensor names 1:1 with the source.
1575                let t = |suffix: &str| {
1576                    load_matrix(
1577                        model,
1578                        &format!("{prefix}linear_attn.{suffix}"),
1579                        force_f32,
1580                        ov,
1581                    )
1582                };
1583                let f = |suffix: &str| {
1584                    load_f32(model, &format!("{prefix}linear_attn.{suffix}"), ov).map_err(err)
1585                };
1586                return Ok(AttnKind::LinearGdn(GdnWeights {
1587                    in_proj_qkv: t("in_proj_qkv.weight")?,
1588                    in_proj_z: t("in_proj_z.weight")?,
1589                    in_proj_a: t("in_proj_a.weight")?,
1590                    in_proj_b: t("in_proj_b.weight")?,
1591                    conv1d: f("conv1d.weight")?,
1592                    a_log: f("A_log")?,
1593                    dt_bias: f("dt_bias")?,
1594                    norm: f("norm.weight")?,
1595                    out_proj: t("out_proj.weight")?,
1596                }));
1597            }
1598            let t = |suffix: &str| {
1599                load_matrix(model, &format!("{prefix}vmf_attn.{suffix}"), force_f32, ov)
1600            };
1601            let a_log = load_f32(model, &format!("{prefix}vmf_attn.A_log"), ov).map_err(err)?;
1602            // Selective-write gate κ (hybrid_k core): optional by tensor
1603            // presence — files without it run the classic phase kernel
1604            // bit-identically.
1605            let k_gate = if model
1606                .tensor(&format!("{prefix}vmf_attn.k_gate.weight"))
1607                .is_some()
1608            {
1609                Some((
1610                    t("k_gate.weight")?,
1611                    load_f32(model, &format!("{prefix}vmf_attn.k_gate.bias"), ov).map_err(err)?,
1612                ))
1613            } else {
1614                None
1615            };
1616            // Optional short causal conv (embryo genomes born with
1617            // --conv-k): `[hidden, 1, k]` taps, flattened.
1618            let conv = if model
1619                .tensor(&format!("{prefix}vmf_attn.conv1d.weight"))
1620                .is_some()
1621            {
1622                Some(load_f32(model, &format!("{prefix}vmf_attn.conv1d.weight"), ov).map_err(err)?)
1623            } else {
1624                None
1625            };
1626            let thq = t("thq.weight")?;
1627            let thk = t("thk.weight")?;
1628            let v_proj = t("v_proj.weight")?;
1629            let out_proj = t("out_proj.weight")?;
1630            let phase_delta = phase_delta_layers
1631                .as_ref()
1632                .is_some_and(|layers| layers.binary_search(&li).is_ok());
1633            if phase_delta {
1634                let cfg = vmf_cfg.ok_or_else(|| {
1635                    CmfError::Parse("phase_delta layer has no VMF geometry".into())
1636                })?;
1637                let expect = |name: &str, got: (usize, usize), want: (usize, usize)| {
1638                    if got != want {
1639                        Err(CmfError::Parse(format!(
1640                            "phase_delta {name} geometry [{}, {}] != [{}, {}]",
1641                            got.0, got.1, want.0, want.1
1642                        )))
1643                    } else {
1644                        Ok(())
1645                    }
1646                };
1647                expect(
1648                    "thq",
1649                    (thq.rows(), thq.cols()),
1650                    (cfg.num_heads * cfg.nphase, cfg.hidden_size),
1651                )?;
1652                expect(
1653                    "thk",
1654                    (thk.rows(), thk.cols()),
1655                    (cfg.num_heads * cfg.nphase, cfg.hidden_size),
1656                )?;
1657                expect(
1658                    "v_proj",
1659                    (v_proj.rows(), v_proj.cols()),
1660                    (cfg.num_heads * cfg.value_head_dim, cfg.hidden_size),
1661                )?;
1662                expect(
1663                    "out_proj",
1664                    (out_proj.rows(), out_proj.cols()),
1665                    (cfg.hidden_size, cfg.num_heads * cfg.value_head_dim),
1666                )?;
1667                if a_log.len() != cfg.num_heads * 2 * cfg.nphase {
1668                    return Err(CmfError::Parse(format!(
1669                        "phase_delta A_log length {} != {}",
1670                        a_log.len(),
1671                        cfg.num_heads * 2 * cfg.nphase
1672                    )));
1673                }
1674                if let Some((kw, kb)) = &k_gate {
1675                    expect(
1676                        "k_gate",
1677                        (kw.rows(), kw.cols()),
1678                        (cfg.num_heads, cfg.hidden_size),
1679                    )?;
1680                    if kb.len() != cfg.num_heads {
1681                        return Err(CmfError::Parse(format!(
1682                            "phase_delta k_gate.bias length {} != {}",
1683                            kb.len(),
1684                            cfg.num_heads
1685                        )));
1686                    }
1687                }
1688                if let Some(c) = &conv {
1689                    let n = model
1690                        .tensor(&format!("{prefix}vmf_attn.conv1d.weight"))
1691                        .ok_or_else(|| {
1692                            CmfError::Parse(
1693                                "phase_delta conv tensor disappeared during load".into(),
1694                            )
1695                        })?;
1696                    if n.shape.len() != 3
1697                        || n.shape[0] != cfg.hidden_size
1698                        || n.shape[1] != 1
1699                        || n.shape[2] < 2
1700                        || c.len() != n.shape.iter().product::<usize>()
1701                    {
1702                        return Err(CmfError::Parse(format!(
1703                            "phase_delta conv geometry {:?} / {} bytes is incompatible",
1704                            n.shape,
1705                            c.len()
1706                        )));
1707                    }
1708                }
1709            }
1710            Ok(AttnKind::Linear(VmfPhaseWeights {
1711                thq,
1712                conv,
1713                thk,
1714                v_proj,
1715                out_proj,
1716                decay: a_log.iter().map(|&a| (-(a as f64).exp()).exp()).collect(),
1717                k_gate,
1718                phase_delta,
1719            }))
1720        };
1721
1722        // LFM2 short-conv mixer: in_proj [3·hidden, hidden], a depthwise
1723        // conv (stored f16 as `[hidden, 1, kernel]` → flattened taps), and
1724        // out_proj [hidden, hidden]. Names canonicalized at convert time.
1725        let load_short_conv = |prefix: &str| -> Result<AttnKind, CmfError> {
1726            let t = |suffix: &str| {
1727                load_matrix(
1728                    model,
1729                    &format!("{prefix}short_conv.{suffix}"),
1730                    force_f32,
1731                    ov,
1732                )
1733            };
1734            Ok(AttnKind::ShortConv(ShortConvWeights {
1735                in_proj: t("in_proj.weight")?,
1736                conv: load_f32(model, &format!("{prefix}short_conv.conv.weight"), ov)
1737                    .map_err(err)?,
1738                out_proj: t("out_proj.weight")?,
1739            }))
1740        };
1741
1742        // KDA layer (Kimi Linear / Kimi-K3): faithful vendor tensors under
1743        // the `kda_attn.` canonical prefix. The output gate is full-rank
1744        // (g_proj, K3) or low-rank (g_a/g_b, Kimi-Linear-48B) by presence.
1745        let load_kda = |prefix: &str| -> Result<AttnKind, CmfError> {
1746            let t = |suffix: &str| {
1747                load_matrix(model, &format!("{prefix}kda_attn.{suffix}"), force_f32, ov)
1748            };
1749            let f = |suffix: &str| {
1750                load_f32(model, &format!("{prefix}kda_attn.{suffix}"), ov).map_err(err)
1751            };
1752            let gate = if model
1753                .tensor(&format!("{prefix}kda_attn.g_proj.weight"))
1754                .is_some()
1755            {
1756                crate::linear_core::KdaOutGate::Full(t("g_proj.weight")?)
1757            } else {
1758                crate::linear_core::KdaOutGate::LowRank(
1759                    t("g_a_proj.weight")?,
1760                    t("g_b_proj.weight")?,
1761                )
1762            };
1763            Ok(AttnKind::Kda(Box::new(crate::linear_core::KdaWeights {
1764                q_proj: t("q_proj.weight")?,
1765                k_proj: t("k_proj.weight")?,
1766                v_proj: t("v_proj.weight")?,
1767                conv_q: f("q_conv1d.weight")?,
1768                conv_k: f("k_conv1d.weight")?,
1769                conv_v: f("v_conv1d.weight")?,
1770                f_a: t("f_a_proj.weight")?,
1771                f_b: t("f_b_proj.weight")?,
1772                dt_bias: f("dt_bias")?,
1773                a_log: f("A_log")?,
1774                b_proj: t("b_proj.weight")?,
1775                gate,
1776                o_norm: f("o_norm.weight")?,
1777                o_proj: t("o_proj.weight")?,
1778                gate_lower_bound: arch.kda_gate_lower_bound.map(|v| v as f32),
1779            })))
1780        };
1781
1782        // Natively bounded anchor (Embryo-O1 `swa_sink_v1`): the plain
1783        // q/k/v/o projections plus the TRAINED sink vectors
1784        // `self_attn.sink_k/sink_v.weight [kvh, S, hd]` (f32, weights —
1785        // not positions). The operator carries no qk-norm, gate or bias:
1786        // their presence is a contract violation, not something to
1787        // silently execute differently from the trainer.
1788        let load_bounded_attn = |prefix: &str, li: usize| -> Result<AttnKind, CmfError> {
1789            let ac = arch.anchor_core.as_ref().ok_or_else(|| {
1790                CmfError::Parse(format!(
1791                    "layer {li} is BoundedAttention but the header carries no anchor_core"
1792                ))
1793            })?;
1794            let t = |suffix: &str| load_matrix(model, &format!("{prefix}{suffix}"), force_f32, ov);
1795            let (nkv, hd, nh) = (arch.num_kv_heads, arch.head_dim, arch.num_attention_heads);
1796            for extra in [
1797                "self_attn.q_norm.weight",
1798                "self_attn.k_norm.weight",
1799                "self_attn.g_proj.weight",
1800                "self_attn.q_proj.bias",
1801                "self_attn.k_proj.bias",
1802                "self_attn.v_proj.bias",
1803            ] {
1804                if model.tensor(&format!("{prefix}{extra}")).is_some() {
1805                    return Err(CmfError::Parse(format!(
1806                        "{prefix}{extra}: the bounded anchor operator carries no qk-norm, \
1807                         gate or bias (docs/EMBRYO_BOUNDED_ANCHOR.md §1)"
1808                    )));
1809                }
1810            }
1811            let sink = |name: &str| -> Result<Vec<f32>, CmfError> {
1812                let full = format!("{prefix}self_attn.{name}.weight");
1813                let e = model.tensor(&full).ok_or_else(|| {
1814                    CmfError::MissingTensor(format!(
1815                        "{full} (a bounded anchor needs its trained sinks)"
1816                    ))
1817                })?;
1818                if e.shape.len() != 3
1819                    || e.shape[0] != nkv
1820                    || e.shape[1] != ac.sink
1821                    || e.shape[2] != hd
1822                {
1823                    return Err(CmfError::Parse(format!(
1824                        "{full}: shape {:?} != [{nkv}, {}, {hd}] (num_kv_heads, anchor_core.sink, head_dim)",
1825                        e.shape, ac.sink
1826                    )));
1827                }
1828                load_f32(model, &full, ov).map_err(err)
1829            };
1830            let wq = t("self_attn.q_proj.weight")?;
1831            let wk = t("self_attn.k_proj.weight")?;
1832            let wv = t("self_attn.v_proj.weight")?;
1833            let wo = t("self_attn.o_proj.weight")?;
1834            let expect = |name: &str, got: (usize, usize), want: (usize, usize)| {
1835                if got != want {
1836                    Err(CmfError::Parse(format!(
1837                        "{prefix}self_attn.{name}.weight is {}x{}, expected {}x{}",
1838                        got.0, got.1, want.0, want.1
1839                    )))
1840                } else {
1841                    Ok(())
1842                }
1843            };
1844            expect("q_proj", (wq.rows(), wq.cols()), (nh * hd, arch.hidden_size))?;
1845            expect("k_proj", (wk.rows(), wk.cols()), (nkv * hd, arch.hidden_size))?;
1846            expect("v_proj", (wv.rows(), wv.cols()), (nkv * hd, arch.hidden_size))?;
1847            expect("o_proj", (wo.rows(), wo.cols()), (arch.hidden_size, nh * hd))?;
1848            Ok(AttnKind::Bounded(Box::new(crate::bounded::BoundedWeights {
1849                wq,
1850                wk,
1851                wv,
1852                wo,
1853                sink_k: sink("sink_k")?,
1854                sink_v: sink("sink_v")?,
1855                sink: ac.sink,
1856                window: ac.window,
1857                group_windows: ac.group_windows.clone(),
1858            })))
1859        };
1860
1861        fn anyhow_like(ok: bool) -> Result<(), ()> {
1862            if ok { Ok(()) } else { Err(()) }
1863        }
1864        let mut layers = Vec::with_capacity(arch.num_layers);
1865        let is_g3n = arch.g3n.is_some();
1866        // Architectures that load their own layer stack below. DeepSeek-V4
1867        // has none of the canonical projections — no q/k/v/o_proj, no
1868        // per-layer gate_proj — so the generic loop would demand
1869        // `self_attn.q_proj.weight` and fail before its own loader ever ran.
1870        let owns_its_layers = is_g3n
1871            || arch.arch_name == "deepseek_v4"
1872            || arch.arch_name == "deepseek_v41"
1873            || arch.dory.is_some()
1874            || arch.qwen4_exp.is_some();
1875        for li in 0..(if owns_its_layers { 0 } else { arch.num_layers }) {
1876            let prefix = format!("model.layers.{li}.");
1877            let attn = match arch.layer_types.get(li) {
1878                Some(LayerType::LinearAttention) => load_linear_attn(&prefix, li)?,
1879                Some(LayerType::Kda) => load_kda(&prefix)?,
1880                Some(LayerType::ShortConv) => load_short_conv(&prefix)?,
1881                Some(LayerType::BoundedAttention) => load_bounded_attn(&prefix, li)?,
1882                _ => load_full_attn(&prefix, Some(li))?,
1883            };
1884            // Gemma-2/3 sandwich: `pre_feedforward_layernorm` present →
1885            // it is the pre-FFN norm, and post_attention/post_feedforward
1886            // норms apply to the branch OUTPUTS before their residuals.
1887            let pre_ffn = format!("{prefix}pre_feedforward_layernorm.weight");
1888            let sandwich = model.tensor(&pre_ffn).is_some();
1889            layers.push(LayerWeights {
1890                input_norm: load_f32(model, &format!("{prefix}input_layernorm.weight"), ov)
1891                    .map_err(err)?,
1892                post_norm: if sandwich {
1893                    load_f32(model, &pre_ffn, ov).map_err(err)?
1894                } else {
1895                    load_f32(
1896                        model,
1897                        &format!("{prefix}post_attention_layernorm.weight"),
1898                        ov,
1899                    )
1900                    .map_err(err)?
1901                },
1902                attn_out_norm: if sandwich {
1903                    Some(
1904                        load_f32(
1905                            model,
1906                            &format!("{prefix}post_attention_layernorm.weight"),
1907                            ov,
1908                        )
1909                        .map_err(err)?,
1910                    )
1911                } else {
1912                    None
1913                },
1914                ffn_out_norm: if sandwich {
1915                    Some(
1916                        load_f32(
1917                            model,
1918                            &format!("{prefix}post_feedforward_layernorm.weight"),
1919                            ov,
1920                        )
1921                        .map_err(err)?,
1922                    )
1923                } else {
1924                    None
1925                },
1926                // Gemma-4: learned scalar multiplying the layer output.
1927                layer_scale: model
1928                    .tensor(&format!("{prefix}layer_scalar"))
1929                    .and_then(|_| {
1930                        load_f32(model, &format!("{prefix}layer_scalar"), ov)
1931                            .ok()
1932                            .and_then(|v| v.first().copied())
1933                    }),
1934                // FFN always quantized — masks run sparse on quant bytes.
1935                ffn: build_layer_ffn(model, &arch, li, false, ov)?,
1936                attn,
1937            });
1938        }
1939
1940        // ── MTP head (optional, spec §2.1) ──
1941        //
1942        // The header declaring an MTP head is not the same as the file
1943        // carrying one. DeepSeek-V4's config announces a next-token predictor
1944        // whose weights the converter does not map (they are spelled `mtp.N.*`
1945        // and have none of the canonical projections), so demanding
1946        // `model.mtp.layers.0.self_attn.q_proj.weight` failed a model that is
1947        // otherwise complete. Presence in the directory decides.
1948        let mtp_present = model
1949            .tensor("model.mtp.layers.0.self_attn.q_proj.weight")
1950            .is_some()
1951            || model.tensor("model.mtp.eh_proj.weight").is_some();
1952        // DeepSeek-V4 writes its own stack under `model.mtp.N.*` — three full
1953        // layers, not a V3-style single block — so it cannot go through the
1954        // path below and is loaded by the dsv4 arm instead. Saying the file
1955        // "carries none" was a false negative worth six gigabytes.
1956        let dsv4_mtp = model.tensor("model.mtp.0.main_proj.weight").is_some();
1957        if arch.mtp.is_some() && !mtp_present && !dsv4_mtp {
1958            tracing::info!(
1959                "header declares an MTP head but the file carries none — \
1960                 loading without it"
1961            );
1962        }
1963        // MiMo-V2 carries its own three-layer stack (sidecar or main file),
1964        // loaded by `mimo_mtp::load_for` below — never this single block.
1965        let mtp = if let Some(cfg) = arch
1966            .mtp
1967            .as_ref()
1968            .filter(|_| mtp_present && arch.arch_name != "mimo_v2")
1969        {
1970            if cfg.num_layers != 1 {
1971                return Err(CmfError::Parse(format!(
1972                    "MTP with {} blocks not supported yet (only 1)",
1973                    cfg.num_layers
1974                )));
1975            }
1976            let p = "model.mtp.";
1977            let attn = load_full_attn("model.mtp.layers.0.", None)?;
1978            // The MTP MLP may be physically narrower than the trunk after
1979            // draft-only compaction. `build_ffn_at` establishes the local
1980            // tensor triple geometry; the optional header declaration is a
1981            // checked assertion, never a replacement for those dimensions.
1982            let ffn = build_ffn_at(model, &arch, &format!("{p}layers.0."), false, ov)?;
1983            validate_generic_mtp_ffn_width(cfg, &ffn)?;
1984            Some(MtpModule {
1985                enorm: load_f32(model, &format!("{p}enorm.weight"), ov).map_err(err)?,
1986                hnorm: load_f32(model, &format!("{p}hnorm.weight"), ov).map_err(err)?,
1987                eh_proj: load_matrix(model, &format!("{p}eh_proj.weight"), false, ov)?,
1988                layer: LayerWeights {
1989                    attn_out_norm: None,
1990                    ffn_out_norm: None,
1991                    layer_scale: None,
1992                    input_norm: load_f32(model, &format!("{p}layers.0.input_layernorm.weight"), ov)
1993                        .map_err(err)?,
1994                    post_norm: load_f32(
1995                        model,
1996                        &format!("{p}layers.0.post_attention_layernorm.weight"),
1997                        ov,
1998                    )
1999                    .map_err(err)?,
2000                    // Whatever the block actually carries: DeepSeek's MTP
2001                    // layer is dense, Qwen3.6's is a full MoE (router + 256
2002                    // experts + shared). Same builder as a backbone layer.
2003                    ffn,
2004                    attn,
2005                },
2006                final_norm: load_f32(model, &format!("{p}norm.weight"), ov).map_err(err)?,
2007                kv: LayerKvCache::new(arch.num_kv_heads, arch.head_dim),
2008            })
2009        } else {
2010            None
2011        };
2012
2013        tracing::info!(
2014            "Pipeline loaded: {} | {}L ({} linear) | {:.2}B params | storage: {} | MTP: {}",
2015            arch.arch_name,
2016            arch.num_layers,
2017            arch.layer_types
2018                .iter()
2019                .filter(|t| matches!(t, LayerType::LinearAttention))
2020                .count(),
2021            model.total_param_count() as f64 / 1e9,
2022            if force_f32 {
2023                "f32 (masked)"
2024            } else {
2025                "quantized mmap"
2026            },
2027            if mtp.is_some() { "yes" } else { "no" }
2028        );
2029
2030        // KV window: the descriptor's max, capped for dev-box safety;
2031        // CMF_MAX_SEQ overrides the cap (long-context runs).
2032        // 8192 was the silent quality cliff of the Qwen3.8 bring-up: at
2033        // the cap the wgpu token graph declines, the host evicts half the
2034        // KV, and a GDN hybrid's recurrent state goes stale — the model
2035        // stays fluent and loses its mind (Django internals, a Turkish
2036        // essay, an em-dash loop; one failure, three costumes). 32768
2037        // covers every long-form run we actually ship while keeping the
2038        // graph's device KV mirror affordable beside the weights;
2039        // CMF_MAX_SEQ still overrides in either direction.
2040        let cap = std::env::var("CMF_MAX_SEQ")
2041            .ok()
2042            .and_then(|v| v.parse::<usize>().ok())
2043            // A turbo file's rows past the seal take no device memory.
2044            .unwrap_or(if model.header.provenance.as_ref().is_some_and(|p| p.get("o1_turbo").is_some()) {
2045                usize::MAX
2046            } else {
2047                32_768
2048            });
2049        let max_seq_len = arch.max_position_embeddings.min(cap);
2050
2051        // Looped Transformer: total virtual layers = physical × num_loops.
2052        // SenseNova-Loop: [0, s) + [s, e) × count + [e, n), one virtual
2053        // layer (and cache) per visit.
2054        let sensenova = crate::sensenova::settings(model).map_err(CmfError::Parse)?;
2055        let layer_map = sensenova
2056            .map(|(span, _)| crate::sensenova::execution_plan(arch.num_layers, span));
2057        let total_layers = layer_map
2058            .as_ref()
2059            .map_or(arch.num_layers * arch.num_loops, Vec::len);
2060
2061        let mut pipeline = Pipeline::new(
2062            tokenizer,
2063            PipelineWeights {
2064                embed_tokens,
2065                layers,
2066                lm_head,
2067                final_norm,
2068            },
2069            arch.hidden_size,
2070            arch.intermediate_size,
2071            arch.num_attention_heads,
2072            arch.num_kv_heads,
2073            arch.head_dim,
2074            total_layers,
2075            arch.num_layers, // physical layers in weights
2076            arch.loop_final_norm,
2077            arch.vocab_size,
2078            arch.rms_norm_eps,
2079            arch.rope_theta as f32,
2080            arch.norm_style,
2081            max_seq_len,
2082            sampler_config,
2083        );
2084        // Unlimited-OCR: the DASH router and its page state.
2085        if arch.arch_name == crate::uocr::ARCH {
2086            pipeline.dash = Some(Box::new(crate::uocr::Dash::from_model(model).map_err(CmfError::Parse)?));
2087        }
2088        if let Some((_, mhc)) = sensenova {
2089            pipeline.layer_map = layer_map;
2090            if let Some(ms) = mhc {
2091                pipeline.mhc = Some(Box::new(
2092                    crate::sensenova::Mhc::from_model(model, ms, arch.num_layers, arch.hidden_size)
2093                        .map_err(CmfError::Parse)?,
2094                ));
2095            }
2096            pipeline.mrope_sections = model
2097                .header
2098                .provenance
2099                .as_ref()
2100                .and_then(|p| p.pointer("/sensenova_loop/config/text_config/rope_parameters/mrope_section"))
2101                .and_then(|v| v.as_array())
2102                .filter(|a| a.len() == 3)
2103                .map(|a| {
2104                    let g = |i: usize| a[i].as_u64().unwrap_or(0) as usize;
2105                    [g(0), g(1), g(2)]
2106                });
2107        }
2108        let rotary = ((arch.head_dim as f32 * arch.partial_rotary_factor) as usize).max(2);
2109        pipeline.set_rotary(rotary, arch.rope_theta as f32);
2110        pipeline.attention_heads_per_layer = arch.attention_heads_per_layer.clone();
2111        if let Some(yarn) = &arch.yarn {
2112            pipeline.inv_freq = std::sync::Arc::new(crate::attention::yarn_inv_freq(
2113                rotary,
2114                arch.rope_theta as f32,
2115                yarn.factor,
2116                yarn.original_max_position_embeddings,
2117                yarn.beta_fast,
2118                yarn.beta_slow,
2119            ));
2120            pipeline.rope_scale = yarn.attention_factor;
2121        }
2122        // Gemma-family extras: embedding scale, attention-scale
2123        // override, and (Gemma-3) sliding-window layers with their own
2124        // local RoPE base.
2125        pipeline.embed_multiplier = arch.embed_multiplier;
2126        pipeline.logit_multiplier = arch.logit_multiplier;
2127        if let Some(qpas) = arch.query_pre_attn_scalar {
2128            pipeline.attn_scale = 1.0 / (qpas as f32).sqrt();
2129        }
2130        if let (Some(w), Some(p)) = (arch.sliding_window, arch.sliding_window_pattern) {
2131            pipeline.swa = Some((w, p));
2132            if let Some(base) = arch.rope_local_base_freq {
2133                pipeline.inv_freq_local = Some(std::sync::Arc::new(
2134                    crate::attention::rope_inv_freq(rotary, base as f32),
2135                ));
2136            }
2137        }
2138        let explicit_sliding: Vec<bool> = arch
2139            .layer_types
2140            .iter()
2141            .map(|t| matches!(t, cortiq_core::LayerType::SlidingAttention))
2142            .collect();
2143        if explicit_sliding.iter().any(|&v| v) {
2144            pipeline.sliding_layers = Some(explicit_sliding);
2145            if let Some(w) = arch.sliding_window {
2146                pipeline.swa = Some((w, usize::MAX));
2147            }
2148            let local_rotary = ((arch.head_dim as f32
2149                * arch
2150                    .local_partial_rotary_factor
2151                    .unwrap_or(arch.partial_rotary_factor))
2152                as usize)
2153                .max(2);
2154            pipeline.rotary_dim_local = Some(local_rotary);
2155            if let Some(base) = arch.rope_local_base_freq {
2156                pipeline.inv_freq_local = Some(std::sync::Arc::new(
2157                    crate::attention::rope_inv_freq(local_rotary, base as f32),
2158                ));
2159            }
2160        }
2161        // Gemma-4: global layers run their own geometry (MQA at
2162        // global_head_dim) with a proportional RoPE — the first
2163        // factor·head_dim dims rotate, the zero-padded tail is identity.
2164        if let (Some(ghd), Some(gkv)) = (arch.global_head_dim, arch.num_global_kv_heads) {
2165            pipeline.global_attn = Some((ghd, gkv));
2166            let prf = arch.global_partial_rotary_factor.unwrap_or(1.0);
2167            let half = ghd / 2;
2168            let ra = (((prf * ghd as f32) as usize) / 2).min(half);
2169            let mut f = vec![0.0f32; half];
2170            for (i, slot) in f.iter_mut().enumerate().take(ra) {
2171                *slot = 1.0 / (arch.rope_theta as f32).powf(2.0 * i as f32 / ghd as f32);
2172            }
2173            pipeline.inv_freq_global = Some(std::sync::Arc::new(f));
2174            // Re-shape the global layers' KV storage to their geometry.
2175            // An explicit layer_types map wins over the numeric pattern
2176            // (explicit tags set swa's pattern to usize::MAX, which
2177            // would otherwise leave every global cache mis-shaped).
2178            let global_at = |li: usize| -> bool {
2179                match &pipeline.sliding_layers {
2180                    Some(map) => !map.get(li).copied().unwrap_or(false),
2181                    None => pipeline
2182                        .swa
2183                        .map(|(_, p)| p > 0 && p != usize::MAX && (li + 1) % p == 0)
2184                        .unwrap_or(false),
2185                }
2186            };
2187            for li in 0..arch.num_layers {
2188                if global_at(li) {
2189                    pipeline.kv_cache.layers[li] = crate::kv_cache::LayerKvCache::new(gkv, ghd);
2190                }
2191            }
2192        }
2193        // The same proportional RoPE on full-attention layers that keep the
2194        // model's head geometry (LFM3): the whole head rotates (header
2195        // factor 1.0) with the full-head frequency progression, and the
2196        // frequencies past `factor·head_dim/2` are zero (identity pairs).
2197        if let (Some(prf), None) = (arch.global_partial_rotary_factor, arch.global_head_dim) {
2198            if arch.yarn.is_some() || pipeline.rotary_dim != arch.head_dim {
2199                return Err(CmfError::Parse(format!(
2200                    "global_partial_rotary_factor {prf} needs partial_rotary_factor 1.0 and no \
2201                     YaRN profile (rotary width {} of head {})",
2202                    pipeline.rotary_dim, arch.head_dim
2203                )));
2204            }
2205            let mut f = crate::attention::rope_inv_freq(arch.head_dim, arch.rope_theta as f32);
2206            let ra = (((prf * arch.head_dim as f32) as usize) / 2).min(f.len());
2207            for slot in f.iter_mut().skip(ra) {
2208                *slot = 0.0;
2209            }
2210            pipeline.inv_freq = std::sync::Arc::new(f);
2211        }
2212        // MLA (DeepSeek-V2): the expand-to-MHA cache holds nh heads of
2213        // rope+nope dims; rotary covers the rope prefix.
2214        if let Some(mla) = arch.mla.as_ref() {
2215            let hd = mla.qk_rope_head_dim + mla.qk_nope_head_dim;
2216            pipeline.head_dim = hd;
2217            pipeline.num_kv_heads = arch.num_attention_heads;
2218            pipeline.rotary_dim = mla.qk_rope_head_dim;
2219            let half = mla.qk_rope_head_dim / 2;
2220            let mut f = vec![0.0f32; half];
2221            for (i, slot) in f.iter_mut().enumerate() {
2222                *slot = 1.0
2223                    / (arch.rope_theta as f32).powf(2.0 * i as f32 / mla.qk_rope_head_dim as f32);
2224            }
2225            pipeline.inv_freq = std::sync::Arc::new(f);
2226            for li in 0..arch.num_layers {
2227                pipeline.kv_cache.layers[li] =
2228                    crate::kv_cache::LayerKvCache::new(arch.num_attention_heads, hd);
2229            }
2230        }
2231        // Per-layer KV geometry (MiMo-V2): KV heads per layer and V heads
2232        // narrower than Q/K. The per-layer shapes were checked against the
2233        // header in load_full_attn; this installs the geometry and gives
2234        // every layer whose KV head count differs its own cache shape.
2235        if !owns_its_layers {
2236            pipeline
2237                .set_attn_geometry(arch.kv_heads_per_layer.clone(), arch.v_head_dim)
2238                .map_err(|e| CmfError::Parse(format!("attention geometry: {e}")))?;
2239        } else if arch.kv_heads_per_layer.is_some() || arch.v_head_dim.is_some() {
2240            return Err(CmfError::Parse(format!(
2241                "{}: kv_heads_per_layer / v_head_dim are not supported by its own layer stack",
2242                arch.arch_name
2243            )));
2244        }
2245        // Learned attention sinks (gpt-oss / MiMo-V2 SWA layers), by tensor
2246        // presence: `model.layers.N.self_attn.sinks`, one f32 logit per Q
2247        // head (`attention_sink_bias` is the HF spelling, accepted too).
2248        // They fold into the grouped softmax; every attention path that
2249        // cannot carry them (chunk GEMM attend, O(1), the GPU graphs)
2250        // refuses the layer.
2251        if !owns_its_layers {
2252            for li in 0..arch.num_layers {
2253                let name = [
2254                    format!("model.layers.{li}.self_attn.sinks"),
2255                    format!("model.layers.{li}.self_attn.attention_sink_bias"),
2256                    // Recursive Flint spells the same thing `softmax_offset`:
2257                    // one learned logit per Q head, added to the attention
2258                    // logits before the softmax.
2259                    format!("model.layers.{li}.self_attn.softmax_offset"),
2260                ]
2261                .into_iter()
2262                .find(|n| model.tensor(n).is_some());
2263                if let Some(name) = name {
2264                    let sinks = load_f32(model, &name, ov).map_err(err)?;
2265                    pipeline
2266                        .set_layer_sinks(li, sinks)
2267                        .map_err(|e| CmfError::Parse(format!("{name}: {e}")))?;
2268                }
2269            }
2270        }
2271        // Flint serializes the no-RoPE schedule explicitly.  Do not infer it
2272        // from a layer class: a later variant may combine a full window with
2273        // RoPE, and changing it changes every attention score.
2274        if arch.arch_name == "flint" || arch.arch_name == "ricursive" {
2275            pipeline.no_rope_layers = arch.no_rope_layers.clone();
2276        }
2277        // Ripple's value residual, by tensor presence: one scalar a layer,
2278        // `model.layers.N.self_attn.value_res_lambda`; V reads
2279        // `lerp(embedding, normed, sigmoid(lambda))`. A layer without one reads the normed
2280        // input (blend 1).
2281        if !owns_its_layers {
2282            let mut blend = vec![1.0f32; arch.num_layers];
2283            let mut any = false;
2284            for (li, b) in blend.iter_mut().enumerate() {
2285                let name = format!("model.layers.{li}.self_attn.value_res_lambda");
2286                if model.tensor(&name).is_some() {
2287                    let lam = load_f32(model, &name, ov).map_err(err)?;
2288                    if lam.len() != 1 {
2289                        return Err(CmfError::Parse(format!("{name}: one scalar expected, got {}", lam.len())));
2290                    }
2291                    *b = 1.0 / (1.0 + (-lam[0]).exp());
2292                    any = true;
2293                }
2294            }
2295            if any {
2296                pipeline.value_blend = Some(blend);
2297            }
2298        }
2299        if pipeline.kv_heads_per_layer.is_some()
2300            || pipeline.v_head_dim.is_some()
2301            || pipeline.kv_cache.layers.iter().any(|l| l.sinks.is_some())
2302        {
2303            let per_token: usize = pipeline
2304                .kv_cache
2305                .layers
2306                .iter()
2307                .map(|l| 2 * l.num_kv_heads * l.head_dim * std::mem::size_of::<f32>())
2308                .sum();
2309            tracing::info!(
2310                "attention geometry: kv heads per layer {:?}, v_head_dim {:?}, {} sink layer(s); \
2311                 f32 KV {} B/token (V padded to head_dim), cap {} tokens",
2312                pipeline.kv_heads_per_layer,
2313                pipeline.v_head_dim,
2314                pipeline
2315                    .kv_cache
2316                    .layers
2317                    .iter()
2318                    .filter(|l| l.sinks.is_some())
2319                    .count(),
2320                per_token,
2321                pipeline.kv_cache.max_seq_len
2322            );
2323        }
2324        // Per-frequency rope divisors (MiniCPM3 longrope short_factor):
2325        // served at the native window with the trained per-dim factors.
2326        // Applied after every inv_freq build (plain, YaRN, MLA).
2327        if let Some(fac) = &arch.rope_freq_factors {
2328            let mut f = pipeline.inv_freq.as_ref().clone();
2329            for (i, v) in f.iter_mut().enumerate() {
2330                if let Some(&d) = fac.get(i) {
2331                    *v /= d as f32;
2332                }
2333            }
2334            pipeline.inv_freq = std::sync::Arc::new(f);
2335        }
2336        if let Some(selected) = &phase_delta_layers {
2337            for &li in selected {
2338                pipeline.kv_cache.layers[li].set_linear_wire_allowed(false);
2339            }
2340        }
2341        pipeline.attn_v_norm = arch.attn_v_norm;
2342        pipeline.qk_norm_after_rope = arch.qk_norm_after_rope;
2343        // One sigmoid gate per head from its own projection: Spark-X2.5's
2344        // `g_proj`, LFM3's `gate_proj` (renamed at convert time).
2345        pipeline.proj_gate_sigmoid = arch.arch_name == "spark2_5" || arch.arch_name == "lfm3";
2346        pipeline.final_softcap = arch.final_logit_softcapping.map(|c| c as f32);
2347        // Cortiq Embryo hierarchical head: cluster matrix → two-level log-probs.
2348        if let Some(ncl) = arch.head_clusters {
2349            let cm = load_f32(model, "lm_head.clusters.weight", ov).map_err(err)?;
2350            if cm.len() != ncl * arch.hidden_size {
2351                return Err(CmfError::Parse(format!(
2352                    "lm_head.clusters.weight: {} != {ncl}×{}",
2353                    cm.len(),
2354                    arch.hidden_size
2355                )));
2356            }
2357            pipeline.head_clusters = Some(std::sync::Arc::new(cm));
2358        }
2359        pipeline.attn_softcap = arch.attn_logit_softcapping.unwrap_or(0.0) as f32;
2360        pipeline.vmf_cfg = vmf_cfg;
2361        pipeline.gdn_cfg = gdn_cfg;
2362        pipeline.kda_cfg = kda_cfg;
2363        if arch.block_diffusion.is_some() {
2364            let c = crate::pipeline::clover::load(model, &arch, gdn_cfg.as_ref(), ov)?;
2365            pipeline.clover = Some(std::sync::Arc::new(c));
2366        }
2367        if arch.qwen4_exp.is_some() {
2368            let (globals, layers, cfg, state) = crate::qwen4_exp::load(model, &arch)?;
2369            pipeline.qwen4_exp = Some(Box::new((globals, layers, cfg, state)));
2370        }
2371        // Gemma-4 E-series (E4B): the E block rides in `g3n` — altup/
2372        // laurel are zeroed for gemma4 — but the layer body is the
2373        // gemma4 stack (dual geometry, proportional RoPE, PLE, shared
2374        // KV), so it loads into its own runtime stack instead.
2375        if arch.g3n.is_some() && arch.arch_name.starts_with("gemma4") {
2376            use crate::g4e::{G4eGlobals, G4eLayer};
2377            let gc = arch.g3n.as_ref().expect("checked above");
2378            let t = |name: &str| load_matrix(model, name, force_f32, ov);
2379            let f = |name: &str| load_f32(model, name, ov).map_err(err);
2380            let first_shared = arch.num_layers.saturating_sub(gc.num_kv_shared_layers);
2381            let sliding_of = |li: usize| {
2382                matches!(
2383                    arch.layer_types.get(li),
2384                    Some(cortiq_core::LayerType::SlidingAttention)
2385                )
2386            };
2387            let hd_g = arch.global_head_dim.unwrap_or(arch.head_dim);
2388            let mut g4e_layers = Vec::with_capacity(arch.num_layers);
2389            for li in 0..arch.num_layers {
2390                let pfx = format!("model.layers.{li}.");
2391                let shared = li >= first_shared && first_shared > 0;
2392                // Same sharing rule as transformers/llama.cpp/gemma-3n:
2393                // a tail layer reuses the KV of the LAST non-shared
2394                // layer of its own attention type.
2395                let share_src = if shared {
2396                    let want = sliding_of(li);
2397                    (0..first_shared).rev().find(|&j| sliding_of(j) == want)
2398                } else {
2399                    None
2400                };
2401                let sliding = sliding_of(li);
2402                let scalar_name = format!("{pfx}layer_scalar");
2403                g4e_layers.push(G4eLayer {
2404                    input_norm: f(&format!("{pfx}input_layernorm.weight"))?,
2405                    attn_out_norm: f(&format!("{pfx}post_attention_layernorm.weight"))?,
2406                    pre_ffn_norm: f(&format!("{pfx}pre_feedforward_layernorm.weight"))?,
2407                    post_ffw_norm: f(&format!("{pfx}post_feedforward_layernorm.weight"))?,
2408                    wq: t(&format!("{pfx}self_attn.q_proj.weight"))?,
2409                    wk: if shared {
2410                        None
2411                    } else {
2412                        Some(t(&format!("{pfx}self_attn.k_proj.weight"))?)
2413                    },
2414                    wv: if shared {
2415                        None
2416                    } else {
2417                        Some(t(&format!("{pfx}self_attn.v_proj.weight"))?)
2418                    },
2419                    wo: t(&format!("{pfx}self_attn.o_proj.weight"))?,
2420                    q_norm: f(&format!("{pfx}self_attn.q_norm.weight"))?,
2421                    k_norm: if shared {
2422                        None
2423                    } else {
2424                        Some(f(&format!("{pfx}self_attn.k_norm.weight"))?)
2425                    },
2426                    kv_share_src: share_src,
2427                    sliding,
2428                    hd: if sliding { arch.head_dim } else { hd_g },
2429                    gate: t(&format!("{pfx}mlp.gate_proj.weight"))?,
2430                    up: t(&format!("{pfx}mlp.up_proj.weight"))?,
2431                    down: t(&format!("{pfx}mlp.down_proj.weight"))?,
2432                    ple_gate: t(&format!("{pfx}per_layer_input_gate.weight"))?,
2433                    ple_proj: t(&format!("{pfx}per_layer_projection.weight"))?,
2434                    post_ple_norm: f(&format!("{pfx}post_per_layer_input_norm.weight"))?,
2435                    layer_scalar: if model.tensor(&scalar_name).is_some() {
2436                        f(&scalar_name)?.first().copied()
2437                    } else {
2438                        None
2439                    },
2440                });
2441            }
2442            // Proportional RoPE for the full layers — the same
2443            // construction the generic loader installs for dense
2444            // gemma4: the first prf·ghd dims rotate (exponent over
2445            // ghd), the zero tail is identity under rope_rotate_scaled.
2446            let ghd = hd_g;
2447            let prf = arch.global_partial_rotary_factor.unwrap_or(1.0);
2448            let half = ghd / 2;
2449            let ra = (((prf * ghd as f32) as usize) / 2).min(half);
2450            let mut inv_freq_global = vec![0.0f32; half];
2451            for (i, slot) in inv_freq_global.iter_mut().enumerate().take(ra) {
2452                *slot = 1.0 / (arch.rope_theta as f32).powf(2.0 * i as f32 / ghd as f32);
2453            }
2454            let globals = G4eGlobals {
2455                ple_embed: t("model.embed_tokens_per_layer.weight")?,
2456                ple_model_proj: t("model.per_layer_model_projection.weight")?,
2457                ple_norm: f("model.per_layer_projection_norm.weight")?,
2458                ple_vocab: gc.ple_vocab,
2459                ple_dim: gc.ple_dim,
2460                num_layers: arch.num_layers,
2461                hidden: arch.hidden_size,
2462                rms_eps: arch.rms_norm_eps,
2463                inv_freq_local: crate::attention::rope_inv_freq(
2464                    arch.head_dim,
2465                    arch.rope_local_base_freq.unwrap_or(10_000.0) as f32,
2466                ),
2467                inv_freq_global,
2468                window: arch.sliding_window.unwrap_or(512),
2469                nh: arch.num_attention_heads,
2470                nkv: arch.num_kv_heads,
2471            };
2472            pipeline.g4e = Some(Box::new((globals, g4e_layers)));
2473        }
2474        if let Some(gc) = arch
2475            .g3n
2476            .as_ref()
2477            .filter(|_| !arch.arch_name.starts_with("gemma4"))
2478        {
2479            use crate::g3n::{G3nAltUp, G3nGlobals, G3nLaurel, G3nLayer};
2480            anyhow_like(gc.altup_num_inputs == crate::g3n::ALTUP_N).map_err(|_| {
2481                CmfError::Parse(format!(
2482                    "g3n: altup_num_inputs {} != supported {}",
2483                    gc.altup_num_inputs,
2484                    crate::g3n::ALTUP_N
2485                ))
2486            })?;
2487            let t = |name: &str| load_matrix(model, name, force_f32, ov);
2488            let f = |name: &str| load_f32(model, name, ov).map_err(err);
2489            let mut altup_proj = Vec::new();
2490            let mut altup_unembed = Vec::new();
2491            for i in 0..crate::g3n::ALTUP_N - 1 {
2492                altup_proj.push(t(&format!("model.altup_projections.{i}.weight"))?);
2493                altup_unembed.push(t(&format!("model.altup_unembed_projections.{i}.weight"))?);
2494            }
2495            let first_shared = arch.num_layers.saturating_sub(gc.num_kv_shared_layers);
2496            let sliding_of = |li: usize| {
2497                matches!(
2498                    arch.layer_types.get(li),
2499                    Some(cortiq_core::LayerType::SlidingAttention)
2500                )
2501            };
2502            let mut g3n_layers = Vec::with_capacity(arch.num_layers);
2503            for li in 0..arch.num_layers {
2504                let pfx = format!("model.layers.{li}.");
2505                let shared = li >= first_shared && first_shared > 0;
2506                let share_src = if shared {
2507                    let want = sliding_of(li);
2508                    (0..first_shared).rev().find(|&j| sliding_of(j) == want)
2509                } else {
2510                    None
2511                };
2512                g3n_layers.push(G3nLayer {
2513                    altup: G3nAltUp {
2514                        router_norm: f(&format!("{pfx}altup.router_norm.weight"))?,
2515                        modality_router: t(&format!("{pfx}altup.modality_router.weight"))?,
2516                        prediction_coefs: t(&format!("{pfx}altup.prediction_coefs.weight"))?,
2517                        correction_coefs: t(&format!("{pfx}altup.correction_coefs.weight"))?,
2518                        correct_output_scale: f(&format!("{pfx}altup.correct_output_scale"))?,
2519                    },
2520                    laurel: G3nLaurel {
2521                        left: t(&format!("{pfx}laurel.linear_left.weight"))?,
2522                        right: t(&format!("{pfx}laurel.linear_right.weight"))?,
2523                        post_norm: f(&format!("{pfx}laurel.post_laurel_norm.weight"))?,
2524                    },
2525                    input_norm: f(&format!("{pfx}input_layernorm.weight"))?,
2526                    post_attn_norm: f(&format!("{pfx}post_attention_layernorm.weight"))?,
2527                    pre_ffw_norm: f(&format!("{pfx}pre_feedforward_layernorm.weight"))?,
2528                    post_ffw_norm: f(&format!("{pfx}post_feedforward_layernorm.weight"))?,
2529                    wq: t(&format!("{pfx}self_attn.q_proj.weight"))?,
2530                    wk: if shared {
2531                        None
2532                    } else {
2533                        Some(t(&format!("{pfx}self_attn.k_proj.weight"))?)
2534                    },
2535                    wv: if shared {
2536                        None
2537                    } else {
2538                        Some(t(&format!("{pfx}self_attn.v_proj.weight"))?)
2539                    },
2540                    wo: t(&format!("{pfx}self_attn.o_proj.weight"))?,
2541                    q_norm: f(&format!("{pfx}self_attn.q_norm.weight"))?,
2542                    k_norm: if shared {
2543                        None
2544                    } else {
2545                        Some(f(&format!("{pfx}self_attn.k_norm.weight"))?)
2546                    },
2547                    kv_share_src: share_src,
2548                    sliding: sliding_of(li),
2549                    gate: t(&format!("{pfx}mlp.gate_proj.weight"))?,
2550                    up: t(&format!("{pfx}mlp.up_proj.weight"))?,
2551                    down: t(&format!("{pfx}mlp.down_proj.weight"))?,
2552                    sparsity: gc.activation_sparsity.get(li).copied().unwrap_or(0.0),
2553                    ple_gate: t(&format!("{pfx}per_layer_input_gate.weight"))?,
2554                    ple_proj: t(&format!("{pfx}per_layer_projection.weight"))?,
2555                    post_ple_norm: f(&format!("{pfx}post_per_layer_input_norm.weight"))?,
2556                });
2557            }
2558            let hd = arch.head_dim;
2559            let globals = G3nGlobals {
2560                altup_proj,
2561                altup_unembed,
2562                ple_embed: t("model.embed_tokens_per_layer.weight")?,
2563                ple_model_proj: t("model.per_layer_model_projection.weight")?,
2564                ple_norm: f("model.per_layer_projection_norm.weight")?,
2565                ple_vocab: gc.ple_vocab,
2566                ple_dim: gc.ple_dim,
2567                num_layers: arch.num_layers,
2568                hidden: arch.hidden_size,
2569                rms_eps: arch.rms_norm_eps,
2570                inv_freq_local: crate::attention::rope_inv_freq(
2571                    hd,
2572                    arch.rope_local_base_freq.unwrap_or(10_000.0) as f32,
2573                ),
2574                inv_freq_global: crate::attention::rope_inv_freq(hd, arch.rope_theta as f32),
2575                window: arch.sliding_window.unwrap_or(512),
2576            };
2577            pipeline.g3n = Some(Box::new((globals, g3n_layers)));
2578        }
2579        // Dory: its own stack (`dory`), selected by the arch record.
2580        if arch.dory.is_some() {
2581            let m = crate::dory::Dory::from_model(model).map_err(CmfError::Parse)?;
2582            pipeline.dory = Some(Box::new((m, crate::dory::DoryState::default())));
2583        }
2584        // DeepSeek-V4.1: its own stack, selected by the preserved source
2585        // configuration. The generic layer loop cannot represent shared
2586        // CED/CSA2 state or native Engram tables, so loading failure is
2587        // fatal instead of falling back to an unrelated attention layout.
2588        if arch.arch_name == "deepseek_v41" {
2589            let source = arch.deepseek_v41.as_ref().ok_or_else(|| {
2590                CmfError::Parse("deepseek_v41: missing preserved source config".into())
2591            })?;
2592            let (cfg, n_layers) = crate::dsv41::Dsv41Cfg::from_source(source, &arch)
2593                .map_err(|e| CmfError::Parse(format!("deepseek_v41: {e}")))?;
2594            let token_map = crate::dsv41::token_map_from_model(model, cfg.vocab);
2595            let (g, dl, hash) = crate::dsv41::load(model, &cfg, n_layers, token_map)
2596                .map_err(|e| CmfError::Parse(format!("deepseek_v41: {e}")))?;
2597            let st = crate::dsv41::Dsv41State::new(&cfg, hash);
2598            // Vision tensors are optional in text-only exports, but when
2599            // present they stay mmap-backed through the dedicated tower.
2600            // Do not make a text-only CMF fail merely because its source
2601            // config still carries the multimodal section.
2602            if let Ok(vision_cfg) = crate::dsv41_vision::VisionConfig::from_source(source) {
2603                if vision_cfg.vision_enabled()
2604                    && model.tensor("vision.patch_embed.proj.weight").is_some()
2605                {
2606                    pipeline.dsv41_vision = Some(
2607                        crate::dsv41_vision::VisionModel::from_model(model, vision_cfg)
2608                            .map_err(|e| CmfError::Parse(format!("deepseek_v41 vision: {e}")))?,
2609                    );
2610                }
2611            }
2612            tracing::info!(
2613                "deepseek_v41: loaded {} layers, {} KV sources, {} index sources, {} Engram layers; experts remain mmap-backed",
2614                dl.len(),
2615                cfg.kv_sources.len(),
2616                cfg.index_sources.len(),
2617                cfg.engram_layers.len()
2618            );
2619            pipeline.dsv41 = Some(Box::new((g, dl, cfg, st)));
2620        }
2621        // DeepSeek-V4: its own stack, selected by the arch name the
2622        // converter wrote. Loading failure is fatal rather than a silent
2623        // fallback — the generic loop cannot represent this model at all,
2624        // so a fallback would decode noise.
2625        if arch.arch_name == "deepseek_v4" {
2626            let moe = arch
2627                .moe
2628                .as_ref()
2629                .ok_or_else(|| CmfError::Parse("deepseek_v4: no moe config".into()))?;
2630            let cfg = crate::dsv4::Dsv4Cfg {
2631                dim: arch.hidden_size,
2632                n_heads: arch.num_attention_heads,
2633                head_dim: arch.head_dim,
2634                // The rope tail: `partial_rotary_factor` carries it when the
2635                // conversion recorded it (rd/head_dim), which the tensors
2636                // cannot reveal. Files converted before that carry 1.0,
2637                // meaning "unset" here rather than "rotate everything" —
2638                // for those the release's 64 stands in, which is what they
2639                // were converted from.
2640                rope_head_dim: if arch.partial_rotary_factor < 1.0 {
2641                    (((arch.head_dim as f32 * arch.partial_rotary_factor) as usize) & !1)
2642                        .clamp(2, arch.head_dim)
2643                } else {
2644                    64.min(arch.head_dim)
2645                },
2646                // The LoRA ranks and the group count ARE visible in the
2647                // weights, and reading them there means a re-tuned
2648                // checkpoint loads without touching this code.
2649                q_lora_rank: 0,
2650                o_lora_rank: 0,
2651                // Derived below from wo_a's shape — the attention output is
2652                // n_heads*head_dim wide and wo_a takes one group of it per
2653                // row block, so groups = width / wo_a.cols(). A pinned 8 is
2654                // right for the release and wrong for anything else, which
2655                // is exactly what made a toy checkpoint impossible to
2656                // compare against the reference.
2657                o_groups: 8,
2658                hc_mult: 4,
2659                hc_sinkhorn_iters: 20,
2660                hc_eps: 1e-6,
2661                norm_eps: arch.rms_norm_eps as f32,
2662                n_routed_experts: moe.num_experts,
2663                top_k: moe.top_k,
2664                moe_inter: moe.moe_intermediate_size,
2665                route_scale: moe.routed_scaling_factor.unwrap_or(1.0),
2666                // config.json's `swiglu_limit`, which the header has no
2667                // field for. The release ships 10.0; a checkpoint that
2668                // retunes it would need this read from the config, so it
2669                // sits next to the other pinned constants rather than
2670                // hiding inside the expert.
2671                swiglu_limit: 10.0,
2672                window: arch.sliding_window.unwrap_or(128),
2673                index_topk: 512,
2674                vocab: arch.vocab_size,
2675            };
2676            let (g, dl) = crate::dsv4::load(model, &cfg, arch.num_layers)
2677                .map_err(|e| CmfError::Parse(format!("deepseek_v4: {e}")))?;
2678            // Read the ranks off the weights that define them: wq_a's
2679            // rows ARE q_lora_rank, and wo_b's columns are groups x
2680            // o_lora_rank. A header field could disagree with the file;
2681            // these cannot.
2682            let mut cfg = cfg;
2683            if let Some(l0) = dl.first() {
2684                cfg.q_lora_rank = l0.wq_a.rows();
2685                let attn_width = arch.num_attention_heads * arch.head_dim;
2686                if l0.wo_a.cols() > 0 && attn_width % l0.wo_a.cols() == 0 {
2687                    cfg.o_groups = (attn_width / l0.wo_a.cols()).max(1);
2688                }
2689                cfg.o_lora_rank = l0.wo_b.cols() / cfg.o_groups.max(1);
2690                cfg.hc_mult = (l0.hc_attn_fn.len() / l0.hc_attn_base.len().max(1)) / cfg.dim.max(1);
2691                if cfg.hc_mult == 0 {
2692                    cfg.hc_mult = 4;
2693                }
2694            }
2695            // RoPE rides only the last `rope_head_dim` of each head, and the
2696            // reference builds its frequencies over THAT width — not over
2697            // head_dim, which is 512 here. The generic path above sized them
2698            // by head_dim, giving 1/base^(2i/512) where 1/base^(2i/64) is
2699            // wanted: every position rotated by the wrong angle.
2700            //
2701            // YaRN is applied unconditionally by the reference (its guard is
2702            // `original_seq_len > 0`, not the sequence length), so it belongs
2703            // in these frequencies too. Older configs spell the key `type`
2704            // rather than `rope_type`; when the header carries no profile the
2705            // release's own numbers stand in, which is better than silently
2706            // decoding with unscaled frequencies.
2707            let (yf, yo, ybf, ybs) = match &arch.yarn {
2708                Some(y) => (
2709                    y.factor,
2710                    y.original_max_position_embeddings,
2711                    y.beta_fast,
2712                    y.beta_slow,
2713                ),
2714                None => {
2715                    tracing::warn!(
2716                        "deepseek_v4: the header carries no YaRN profile — \
2717                         falling back to the release's (factor 16, original \
2718                         65536, beta 32/1). Re-converting with a build that \
2719                         reads rope_scaling.type would make this exact."
2720                    );
2721                    (16.0, 65536, 32.0, 1.0)
2722                }
2723            };
2724            pipeline.inv_freq = std::sync::Arc::new(crate::attention::yarn_inv_freq(
2725                cfg.rope_head_dim,
2726                arch.rope_theta as f32,
2727                yf,
2728                yo,
2729                ybf,
2730                ybs,
2731            ));
2732            // Keep the working set resident. Everything but the routed
2733            // experts is touched by every token, and of the experts only the
2734            // ones the task actually routes to — the page cache cannot know
2735            // that and evicts by age instead.
2736            if let Ok(stats) = std::env::var("CMF_MOE_PIN") {
2737                let cover = std::env::var("CMF_MOE_PIN_COVER")
2738                    .ok()
2739                    .and_then(|v| v.parse::<f64>().ok())
2740                    .filter(|&c| c > 0.0 && c <= 1.0)
2741                    .unwrap_or(0.95);
2742                let hot = crate::pin::hot_experts(&stats, cover);
2743                let mut names: Vec<String> = Vec::new();
2744                for e in &model.tensors {
2745                    let is_expert = e.name.contains(".mlp.experts.");
2746                    if !is_expert {
2747                        names.push(e.name.clone()); // skeleton: always hot
2748                    }
2749                }
2750                let mut kept_experts = 0usize;
2751                if let Some(hot) = &hot {
2752                    for (li, experts) in hot {
2753                        for e in experts {
2754                            for w in ["gate_proj", "up_proj", "down_proj"] {
2755                                names.push(format!("model.layers.{li}.mlp.experts.{e}.{w}.weight"));
2756                            }
2757                            kept_experts += 1;
2758                        }
2759                    }
2760                }
2761                let r = crate::pin::pin_tensors(model, &names);
2762                tracing::info!(
2763                    "pinned {:.1} GB ({} tensors, hot experts {kept_experts},                      coverage {cover}); limit {}",
2764                    r.bytes as f64 / 1e9,
2765                    r.tensors,
2766                    r.limit
2767                        .map(|l| format!("{:.1} GB", l as f64 / 1e9))
2768                        .unwrap_or_else(|| "unknown".into())
2769                );
2770                if r.skipped > 0 {
2771                    tracing::warn!("tensors left unpinned: {}", r.skipped);
2772                }
2773            }
2774            let st = crate::dsv4::Dsv4State::new(arch.num_layers);
2775            // The speculation stack, if the file carries one. Reading it is
2776            // metadata only — the expert weights stay in the mapping until a
2777            // draft actually runs — so it costs nothing to know it is there.
2778            let depth = std::env::var("CMF_DSV4_MTP_DEPTH")
2779                .ok()
2780                .and_then(|v| v.parse::<usize>().ok())
2781                .unwrap_or(3);
2782            pipeline.dsv4_mtp = crate::dsv4::load_mtp(model, &cfg, depth);
2783            // Before any trunk pack is built: leave the draft its VRAM.
2784            crate::dsv4::dspark_reserve_note(&pipeline.dsv4_mtp, &cfg, &dl);
2785            pipeline.dsv4 = Some(Box::new((g, dl, cfg, st)));
2786        }
2787        pipeline.short_conv_cfg = short_conv_cfg;
2788        pipeline.mtp = mtp;
2789        // A DFlash block drafter beside the file drafts the rounds when asked to.
2790        if std::env::var("CMF_DFLASH").as_deref() == Ok("1") {
2791            match crate::dflash::Drafter::for_target(model) {
2792                Some(Ok(d)) => {
2793                    tracing::info!("DFlash drafter: {} layers on the trunk's layers {:?}, blocks of {}", d.g.layers, d.g.taps, d.g.block);
2794                    #[cfg(feature = "gpu")]
2795                    let _ = d.dev_ready();
2796                    pipeline.dflash = Some(Box::new(d));
2797                    pipeline.dflash_solo = pipeline.mtp.is_none();
2798                }
2799                Some(Err(e)) => tracing::warn!("DFlash sidecar ignored: {e}"),
2800                None => tracing::warn!("CMF_DFLASH=1, and {} is not there", crate::dflash::sidecar_path(&model.path).display()),
2801            }
2802        }
2803        if arch.arch_name == "mimo_v2" {
2804            pipeline.mimo_mtp = crate::pipeline::mimo_mtp::load_for(model, &arch)?;
2805        }
2806        // Spark-X2.5's sliding layers (27 of the 4B's 36, window 512) and
2807        // LFM3's (5 of 11 attention layers, window 256) keep only the rows
2808        // their window can still read: 64 rows of rollback slack, the cut
2809        // on a 64-row grid so the Metal chunk GEMMs keep their K-tile
2810        // partition (see `LayerKvCache::trim_window`). Other windowed
2811        // architectures keep every row until one is measured.
2812        // Off with a speculation head (its verify paths read row counts as
2813        // positions) and under CMF_ATTN_DUMP (the dump header assumes row
2814        // = position). CMF_SWA_TRIM=0 turns it off for an A/B.
2815        pipeline.swa_trim = (matches!(arch.arch_name.as_str(), "spark2_5" | "lfm3")
2816            && pipeline.swa.is_some()
2817            && pipeline.mtp.is_none()
2818            && pipeline.mimo_mtp.is_none()
2819            && pipeline.dsv4_mtp.is_empty()
2820            && std::env::var_os("CMF_ATTN_DUMP").is_none()
2821            && std::env::var("CMF_SWA_TRIM").as_deref() != Ok("0"))
2822            .then_some((64, 64));
2823        // Spark-X2.6's KV mirrors in f16 on Metal: at 14 000 tokens a token read 1.03 GB of f32
2824        // rows on the M4 (`CMF_METAL_KV_F16=0` keeps f32).
2825        #[cfg(target_os = "macos")]
2826        if arch.arch_name == "spark2_5" {
2827            crate::gpu_metal::set_kv_f16_default(true);
2828        }
2829        // Spark-X2.6-4B q8_2f on the M4: an 8..31-token prompt prefills in
2830        // ~105 ms on the chunk graph against 0.5-1.2 s on the host layer walk
2831        // (shorter prompts keep their faster per-position path).
2832        // CMF_CHUNK_MIN_B overrides for every model.
2833        pipeline.chunk_min_rows = std::env::var("CMF_CHUNK_MIN_B")
2834            .ok()
2835            .and_then(|v| v.parse().ok())
2836            .unwrap_or(if arch.arch_name == "spark2_5" { 8 } else { 32 });
2837        pipeline.install_dynamic_routing(model, false);
2838        // Record the load-time overlay so a later set_active_skill(None)
2839        // correctly reverts it (the union-diff assumes dyn_active mirrors
2840        // the live overlay). Blend loads have no single index to revert.
2841        match ov {
2842            Overlay::One(sid) => {
2843                pipeline.dyn_active = model.header.skills.iter().position(|s| &s.id == sid);
2844            }
2845            Overlay::Blend(_) => pipeline.dyn_blend_loaded = true,
2846            Overlay::None => {}
2847        }
2848        // B1: apply the measured confidence-calibration temperature, if the
2849        // file carries one (softmax(logits / T) for reported confidence).
2850        if let Some(c) = &model.header.calibration {
2851            pipeline.set_calib_temp(c.temperature);
2852        }
2853        // Versioned state wire: every layer carries the operator identity
2854        // so a peer holding another operator is refused, not guessed at.
2855        let identity = arch
2856            .linear_core_identity()
2857            .and_then(|v| serde_json::to_vec(&v).ok())
2858            .map(|b| cortiq_core::hash64(&b))
2859            .unwrap_or(0);
2860        pipeline.install_wire_identity(identity);
2861        // Natively bounded anchor: the file's operator, installed from the
2862        // header (rings sized once, not per prompt). The file governs —
2863        // a post-hoc O(1) knob on such a file is an error, not a warning.
2864        if let Some(ac) = &arch.anchor_core {
2865            pipeline.install_bounded(ac).map_err(CmfError::Parse)?;
2866            let why = pipeline.o1_refusal().unwrap_or_default();
2867            let mut knobs: Vec<String> = std::env::vars()
2868                .filter(|(k, v)| {
2869                    (k == "CMF_O1" && !(v == "off" || v == "0")) || k.starts_with("CMF_O1_")
2870                })
2871                .map(|(k, _)| k)
2872                .collect();
2873            knobs.sort();
2874            if !knobs.is_empty() {
2875                return Err(CmfError::Parse(format!("{why} (set: {})", knobs.join(", "))));
2876            }
2877            if model
2878                .header
2879                .provenance
2880                .as_ref()
2881                .and_then(|p| p.get("o1_attn"))
2882                .is_some()
2883            {
2884                return Err(CmfError::Parse(format!(
2885                    "{why} (the header carries a provenance.o1_attn hint)"
2886                )));
2887            }
2888            return Ok(pipeline);
2889        }
2890        // O(1) Nyström attention (runtime-level, no format change):
2891        // env CMF_O1 decides; unset falls through to the converter hint
2892        // in header.provenance.o1_attn (`cortiq convert --o1`), and
2893        // CMF_O1=off force-disables even the hint. CLI flags override
2894        // later via set_o1().
2895        // A genome's attention operator is its arch (hashed into the
2896        // trunk); a provenance hint is not part of the genome and must not
2897        // switch the backbone to Nyström (NF-6 — core refuses the hint on
2898        // a GENOME file at open; this keeps the loader fail-closed too).
2899        let genome_hint = model.header.genome.is_some()
2900            && model
2901                .header
2902                .provenance
2903                .as_ref()
2904                .and_then(|p| p.get("o1_attn"))
2905                .is_some();
2906        if genome_hint {
2907            return Err(CmfError::Parse(
2908                "genome file with a provenance.o1_attn hint: the trunk's attention operator is \
2909                 set by the genome's arch only — refusing"
2910                    .into(),
2911            ));
2912        }
2913        let o1_env = crate::nystrom::o1_from_env();
2914        // A turbo file: the far field comes on for long prompts only, so nothing is set now.
2915        // The Flash-Next device path reads the header itself (`qwen4_o1`): the generic seal
2916        // has no layers of its own there.
2917        if matches!(o1_env, crate::nystrom::O1Env::Unset) && pipeline.qwen4_exp.is_none() {
2918            let hint = model.header.provenance.as_ref().and_then(|p| p.get("o1_turbo"));
2919            if let Some(h) = hint {
2920                let field = |k: &str| h.get(k).and_then(|v| v.as_u64()).map(|v| v as usize);
2921                let weights = load_f32(model, "o1.exact.weights", &Overlay::None).unwrap_or_default();
2922                if let (Some(cfg), Some(seal), Some(rows)) = (crate::nystrom::O1Cfg::from_json(h), field("seal"), field("exact_rows")) {
2923                    pipeline.o1_turbo = Some(crate::pipeline::O1Turbo {
2924                        cfg,
2925                        seal: crate::pipeline::o1_seal_for_card(seal, model.tensors.iter().map(|e| e.nbytes).sum()),
2926                        exact: crate::dory::ExactRows { weights: std::sync::Arc::new(weights), budget: rows },
2927                    });
2928                }
2929            }
2930        }
2931        let o1 = match o1_env {
2932            crate::nystrom::O1Env::Off => None,
2933            crate::nystrom::O1Env::On(cfg) => Some(cfg),
2934            crate::nystrom::O1Env::Unset => model
2935                .header
2936                .provenance
2937                .as_ref()
2938                .and_then(|p| p.get("o1_attn"))
2939                .and_then(crate::nystrom::O1Cfg::from_json),
2940        };
2941        if o1.is_some() {
2942            if pipeline.attn_softcap > 0.0 {
2943                return Err(CmfError::Parse(
2944                    "--o1 with attention-logit soft-capping (Gemma-2) is not supported: \
2945                     the streaming operator has no capped-score form"
2946                        .into(),
2947                ));
2948            }
2949            pipeline.set_o1(o1);
2950        }
2951        Ok(pipeline)
2952    }
2953
2954    /// Record per-skill dynamic-routing metadata: which FFN layers each
2955    /// skill actually replaces (derived from the tensors present, not
2956    /// the meta `layers` field), and whether the skill is eligible for
2957    /// cheap dynamic switching (FFN-only). Called once at load.
2958    pub(crate) fn install_dynamic_routing(&mut self, model: &Arc<CmfModel>, force_f32: bool) {
2959        self.model = Some(model.clone());
2960        self.dyn_force_f32 = force_f32;
2961        let mut per_skill = Vec::with_capacity(model.header.skills.len());
2962        for sk in &model.header.skills {
2963            // A lookup record replaces nothing: its tensors are the key →
2964            // card table (u64/u32/u8), never weights. No lane, no switch.
2965            if sk.kind.as_deref() == Some(cortiq_core::knowledge::skill_kind::LOOKUP) {
2966                per_skill.push(None);
2967                continue;
2968            }
2969            let mut ffn_layers = std::collections::BTreeSet::new();
2970            let mut non_ffn = false;
2971            let prefix = format!("skill.{}.", sk.id);
2972            for t in model.skill_tensors(&sk.id) {
2973                let rel = &t.name[prefix.len()..]; // e.g. model.layers.20.mlp.down_proj.weight
2974                let toks: Vec<&str> = rel.split('.').collect();
2975                if toks.len() >= 5 && toks[0] == "model" && toks[1] == "layers" && toks[3] == "mlp"
2976                {
2977                    if let Ok(li) = toks[2].parse::<usize>() {
2978                        ffn_layers.insert(li);
2979                        continue;
2980                    }
2981                }
2982                non_ffn = true; // replaces attention / embed / lm_head
2983            }
2984            if non_ffn {
2985                tracing::warn!(
2986                    "skill '{}' replaces non-FFN tensors — excluded from dynamic \
2987                     routing (static overlay still works)",
2988                    sk.id
2989                );
2990                per_skill.push(None);
2991            } else {
2992                per_skill.push(Some(ffn_layers.into_iter().collect::<Vec<_>>()));
2993            }
2994        }
2995        self.dyn_skill_layers = per_skill;
2996    }
2997
2998    /// Switch the overlaid skill for subsequent forwards (dynamic
2999    /// routing). `idx` = index into model.header.skills; None = backbone.
3000    /// Rebuilds the FFN of the union of the old and new skill's touched
3001    /// layers with the new overlay — tensor-source indirection made
3002    /// dynamic. Cheap: Mapped tensors are re-resolved mmap pointers.
3003    /// Result is bit-identical to loading the pipeline with that skill.
3004    ///
3005    /// Asking for the skill that is already active is a true no-op: the
3006    /// weights do not change, so the sequence state (KV, rings, recurrent
3007    /// state, the prefix-reuse key) stays — clearing it here used to wipe
3008    /// a live conversation on every idempotent call. A real change
3009    /// rebuilds the touched FFNs first (all or nothing: on an error the
3010    /// old overlay and state are untouched), then invalidates every state
3011    /// the old weights produced, including `kv_prefix`.
3012    pub fn set_active_skill(&mut self, idx: Option<usize>) -> Result<(), CmfError> {
3013        if self.dyn_active == idx {
3014            return Ok(());
3015        }
3016        let model = self.model.clone().ok_or_else(|| {
3017            CmfError::Parse("dynamic routing needs a model-backed pipeline".into())
3018        })?;
3019        let mut union: std::collections::BTreeSet<usize> = std::collections::BTreeSet::new();
3020        if let Some(old) = self.dyn_active {
3021            if let Some(Some(ls)) = self.dyn_skill_layers.get(old) {
3022                union.extend(ls.iter().copied());
3023            }
3024        }
3025        let new_id: Option<String> = match idx {
3026            Some(n) => match self.dyn_skill_layers.get(n) {
3027                Some(Some(ls)) => {
3028                    union.extend(ls.iter().copied());
3029                    Some(model.header.skills[n].id.clone())
3030                }
3031                _ => {
3032                    return Err(CmfError::Parse(format!(
3033                        "skill index {n} not dynamic-eligible"
3034                    )));
3035                }
3036            },
3037            None => None,
3038        };
3039        let ov = match &new_id {
3040            Some(s) => Overlay::One(s),
3041            None => Overlay::None,
3042        };
3043        let arch = model.arch();
3044        let mut rebuilt = Vec::with_capacity(union.len());
3045        for li in union {
3046            rebuilt.push((
3047                li,
3048                build_layer_ffn(&model, arch, li, self.dyn_force_f32, &ov)?,
3049            ));
3050        }
3051        for (li, ffn) in rebuilt {
3052            self.weights.layers[li].ffn = ffn;
3053        }
3054        // Overlay swap changed weights → every cached state is stale.
3055        self.invalidate_for_weight_change();
3056        self.dyn_active = idx;
3057        Ok(())
3058    }
3059}
3060
3061/// Fixed per-sequence state a file declares, from its header alone (no
3062/// weights loaded): bytes of bounded-anchor rings, bytes of recurrent
3063/// vectors (S + conv rings), and how many layers still hold a growing
3064/// per-position KV. A strictly-O(1) file has `growing_layers == 0`.
3065#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
3066pub struct PerSequenceState {
3067    pub bounded_bytes: usize,
3068    pub recurrent_bytes: usize,
3069    pub growing_layers: usize,
3070}
3071
3072pub fn per_sequence_state_bytes(model: &CmfModel) -> Result<PerSequenceState, String> {
3073    let arch = model.arch();
3074    let f = std::mem::size_of::<f32>();
3075    let mut st = PerSequenceState::default();
3076    let need = |v: Option<usize>, name: &str| {
3077        v.ok_or_else(|| format!("linear core needs arch.{name}"))
3078    };
3079    for li in 0..arch.num_layers {
3080        match arch.layer_types.get(li) {
3081            Some(LayerType::BoundedAttention) => {
3082                let ac = arch
3083                    .anchor_core
3084                    .as_ref()
3085                    .ok_or("BoundedAttention layer without anchor_core")?;
3086                st.bounded_bytes += ac.ring_state_elems(arch.num_kv_heads, arch.head_dim) * f;
3087            }
3088            Some(LayerType::LinearAttention) => {
3089                let lc = arch
3090                    .linear_core
3091                    .as_ref()
3092                    .ok_or("LinearAttention layer without linear_core")?;
3093                let elems = match lc.kind.as_str() {
3094                    "gated_delta_net" => GdnCfg {
3095                        num_v_heads: lc.num_heads,
3096                        num_k_heads: need(arch.linear_num_key_heads, "linear_num_key_heads")?,
3097                        key_head_dim: need(arch.linear_key_head_dim, "linear_key_head_dim")?,
3098                        value_head_dim: lc.value_head_dim,
3099                        conv_kernel: need(arch.linear_conv_kernel_dim, "linear_conv_kernel_dim")?,
3100                        hidden_size: arch.hidden_size,
3101                        rms_eps: arch.rms_norm_eps,
3102                        output_gate_sigmoid: false,
3103                    }
3104                    .state_len(),
3105                    _ => {
3106                        let nphase = need(lc.nphase, "linear_core.nphase")?;
3107                        let mut n = lc.num_heads * 2 * nphase * lc.value_head_dim;
3108                        if let Some(c) = model.tensor(&format!("model.layers.{li}.vmf_attn.conv1d.weight")) {
3109                            if c.shape.len() == 3 && c.shape[2] >= 2 {
3110                                n += (c.shape[2] - 1) * arch.hidden_size;
3111                            }
3112                        }
3113                        n
3114                    }
3115                };
3116                st.recurrent_bytes += elems * f;
3117            }
3118            Some(LayerType::ShortConv) => {
3119                let k = need(arch.linear_conv_kernel_dim, "linear_conv_kernel_dim")?;
3120                st.recurrent_bytes += ShortConvCfg {
3121                    hidden_size: arch.hidden_size,
3122                    kernel: k,
3123                }
3124                .state_len()
3125                    * f;
3126            }
3127            Some(LayerType::Kda) => {
3128                st.recurrent_bytes += crate::linear_core::KdaCfg {
3129                    num_heads: need(arch.linear_num_key_heads, "linear_num_key_heads")?,
3130                    head_k_dim: need(arch.linear_key_head_dim, "linear_key_head_dim")?,
3131                    head_v_dim: need(arch.linear_value_head_dim, "linear_value_head_dim")?,
3132                    conv_kernel: need(arch.linear_conv_kernel_dim, "linear_conv_kernel_dim")?,
3133                    hidden_size: arch.hidden_size,
3134                    rms_eps: arch.rms_norm_eps,
3135                }
3136                .state_len()
3137                    * f;
3138            }
3139            _ => st.growing_layers += 1,
3140        }
3141    }
3142    Ok(st)
3143}
3144
3145#[cfg(test)]
3146mod tests {
3147    use super::*;
3148
3149    fn dense_mtp_ffn(width: usize) -> FfnKind {
3150        const HIDDEN: usize = 4;
3151        let matrix = |rows, cols| QTensor::from_f32(vec![0.0; rows * cols], rows, cols);
3152        FfnKind::Dense(DenseFfn {
3153            gate_proj: matrix(width, HIDDEN),
3154            up_proj: matrix(width, HIDDEN),
3155            down_proj: matrix(HIDDEN, width),
3156            act: crate::pipeline::Act::Silu,
3157            down_t: None,
3158            segs: Vec::new(),
3159        })
3160    }
3161
3162    fn mtp_config(widths: Vec<usize>) -> cortiq_core::MtpConfig {
3163        cortiq_core::MtpConfig {
3164            num_layers: 1,
3165            ffn_intermediate_sizes: Some(widths),
3166            share_lm_head: true,
3167            share_embed: true,
3168        }
3169    }
3170
3171    #[test]
3172    fn generic_mtp_declared_width_is_checked_against_its_local_ffn() {
3173        assert!(validate_generic_mtp_ffn_width(&mtp_config(vec![6]), &dense_mtp_ffn(6)).is_ok());
3174
3175        let err = validate_generic_mtp_ffn_width(&mtp_config(vec![5]), &dense_mtp_ffn(6))
3176            .unwrap_err()
3177            .to_string();
3178        assert!(err.contains("ffn_intermediate_sizes[0]=5"), "{err}");
3179        assert!(err.contains("has 6 rows"), "{err}");
3180
3181        let err = validate_generic_mtp_ffn_width(&mtp_config(vec![6, 6]), &dense_mtp_ffn(6))
3182            .unwrap_err()
3183            .to_string();
3184        assert!(err.contains("has 2 entries, expected 1"), "{err}");
3185    }
3186}