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/// Tensor source selector (spec §9): backbone, one skill's overlay, or
29/// a soft superposition of top-m skills (claim 14 working tensors).
30pub enum Overlay<'a> {
31    None,
32    One(&'a str),
33    /// (skill_id, weight); weights sum to 1 (softmax(−E/T) upstream).
34    Blend(&'a [(String, f32)]),
35}
36
37impl Overlay<'_> {
38    fn blend_touches(&self, model: &CmfModel, name: &str) -> bool {
39        match self {
40            Overlay::Blend(list) => list
41                .iter()
42                .any(|(sid, _)| model.tensor(&format!("skill.{sid}.{name}")).is_some()),
43            _ => false,
44        }
45    }
46}
47
48fn dequant_by_name(model: &CmfModel, name: &str) -> Result<Vec<f32>, String> {
49    let entry = model
50        .tensor(name)
51        .ok_or_else(|| format!("tensor '{name}' not found in CMF directory"))?;
52    let mut out = vec![0.0f32; entry.n_elems()];
53    dequant_tensor(entry, model.entry_bytes(entry), &mut out)?;
54    Ok(out)
55}
56
57/// Weighted working tensor (claim 14): Σ wᵢ·Tᵢ, where Tᵢ is the
58/// skill's replacement when present, else the backbone tensor.
59fn blend_f32(model: &CmfModel, name: &str, list: &[(String, f32)]) -> Result<Vec<f32>, String> {
60    let mut acc: Option<Vec<f32>> = None;
61    for (sid, w) in list {
62        let sname = format!("skill.{sid}.{name}");
63        let src = if model.tensor(&sname).is_some() {
64            &sname
65        } else {
66            name
67        };
68        let t = dequant_by_name(model, src)?;
69        match &mut acc {
70            None => {
71                let mut t = t;
72                for v in t.iter_mut() {
73                    *v *= w;
74                }
75                acc = Some(t);
76            }
77            Some(a) => {
78                for (av, tv) in a.iter_mut().zip(&t) {
79                    *av += w * tv;
80                }
81            }
82        }
83    }
84    acc.ok_or_else(|| "empty blend".into())
85}
86
87/// Dequantize a tensor fully into f32 (norms, masked models).
88pub(crate) fn load_f32(model: &CmfModel, name: &str, ov: &Overlay) -> Result<Vec<f32>, String> {
89    if ov.blend_touches(model, name) {
90        if let Overlay::Blend(list) = ov {
91            return blend_f32(model, name, list);
92        }
93    }
94    let skill = match ov {
95        Overlay::One(s) => Some(*s),
96        _ => None,
97    };
98    let entry = model
99        .resolve_tensor(name, skill)
100        .ok_or_else(|| format!("tensor '{name}' not found in CMF directory"))?;
101    let bytes = model.entry_bytes(entry);
102    let mut out = vec![0.0f32; entry.n_elems()];
103    dequant_tensor(entry, bytes, &mut out)?;
104    Ok(out)
105}
106
107/// Build one layer's FFN (dense or MoE) under a given overlay. Shared
108/// by the static loader AND dynamic per-token skill switching
109/// (`Pipeline::set_active_skill`): switching skills = rebuilding the
110/// FFN of the touched layers, cheap because Mapped tensors are just
111/// re-resolved mmap pointers (no dequant, no copy).
112pub(crate) fn build_layer_ffn(
113    model: &Arc<CmfModel>,
114    arch: &ModelArch,
115    li: usize,
116    force_f32: bool,
117    ov: &Overlay,
118) -> Result<FfnKind, CmfError> {
119    build_ffn_at(model, arch, &format!("model.layers.{li}."), force_f32, ov)
120}
121
122/// The FFN under an arbitrary prefix. Split out of `build_layer_ffn` so the
123/// MTP block can reuse it: Qwen3.6's MTP layer carries a full MoE mlp
124/// (router + 256 experts + shared expert), not the dense one the head was
125/// first written against.
126pub(crate) fn build_ffn_at(
127    model: &Arc<CmfModel>,
128    arch: &ModelArch,
129    prefix: &str,
130    force_f32: bool,
131    ov: &Overlay,
132) -> Result<FfnKind, CmfError> {
133    let prefix = prefix.to_string();
134    let load_dense = |p: &str| -> Result<DenseFfn, CmfError> {
135        let gate_proj = load_matrix(model, &format!("{p}gate_proj.weight"), force_f32, ov)?;
136        let up_proj = load_matrix(model, &format!("{p}up_proj.weight"), force_f32, ov)?;
137        let down_proj = load_matrix(model, &format!("{p}down_proj.weight"), force_f32, ov)?;
138        // FFN triple invariant (holds for dense and each MoE expert;
139        // enforced loudly so a malformed defrag/repack — spec §11 — fails
140        // at load instead of silently mis-computing). inter' is per-layer.
141        let inter = gate_proj.rows();
142        if up_proj.rows() != inter || down_proj.cols() != inter {
143            return Err(CmfError::Parse(format!(
144                "{p}: FFN dims disagree (gate.rows={inter}, up.rows={}, \
145                 down.cols={}); all three must equal inter'",
146                up_proj.rows(),
147                down_proj.cols()
148            )));
149        }
150        if down_proj.rows() != arch.hidden_size {
151            return Err(CmfError::Parse(format!(
152                "{p}: down_proj.rows={} != hidden_size={}",
153                down_proj.rows(),
154                arch.hidden_size
155            )));
156        }
157        // The transposed down, when the file carries one: the per-token
158        // sparse path needs a neuron's down weights contiguous.
159        let dt_name = format!("{p}down_proj.t.weight");
160        let down_t = match model.tensor(&dt_name) {
161            Some(_) => Some(load_matrix(model, &dt_name, force_f32, ov)?),
162            None => None,
163        };
164        if let Some(t) = &down_t
165            && (t.rows() != inter || t.cols() != arch.hidden_size)
166        {
167            return Err(CmfError::Parse(format!(
168                "{p}down_proj.t: [{}, {}] != [{inter}, {}]",
169                t.rows(),
170                t.cols(),
171                arch.hidden_size
172            )));
173        }
174        // Task tubes (`…gate_proj.tube1.weight`, …): the neurons only
175        // some tasks compute, each stored as its own triple so every
176        // kernel runs it unchanged and an inactive tube's bytes are
177        // never touched. Numbering is dense from 1; the first gap ends
178        // the tube list.
179        let mut segs = Vec::new();
180        let mut start = inter;
181        for k in 1.. {
182            let gn = format!("{p}gate_proj.tube{k}.weight");
183            if model.tensor(&gn).is_none() {
184                break;
185            }
186            let gate = load_matrix(model, &gn, force_f32, ov)?;
187            let up = load_matrix(model, &format!("{p}up_proj.tube{k}.weight"), force_f32, ov)?;
188            let down = load_matrix(
189                model,
190                &format!("{p}down_proj.tube{k}.weight"),
191                force_f32,
192                ov,
193            )?;
194            let width = gate.rows();
195            if up.rows() != width || down.cols() != width || down.rows() != arch.hidden_size {
196                return Err(CmfError::Parse(format!(
197                    "{p}tube{k}: dims disagree (gate.rows={width}, up.rows={}, \
198                     down=[{}, {}], hidden={})",
199                    up.rows(),
200                    down.rows(),
201                    down.cols(),
202                    arch.hidden_size
203                )));
204            }
205            segs.push(crate::pipeline::FfnSeg {
206                gate,
207                up,
208                down,
209                start,
210                width,
211            });
212            start += width;
213        }
214        Ok(DenseFfn {
215            gate_proj,
216            up_proj,
217            down_proj,
218            act: crate::pipeline::Act::from_arch_full(arch),
219            down_t,
220            segs,
221        })
222    };
223    let router_name = format!("{prefix}mlp.gate.weight");
224    // Cortiq Embryo: resonance-routed experts carry NO gate tensor — the
225    // MoE is keyed on the first expert + the arch flag (a grown genome
226    // appends `mlp.experts.{E}.*` records without rewriting anything).
227    let resonance_moe = model.tensor(&router_name).is_none()
228        && arch.moe.as_ref().is_some_and(|m| m.router_resonance)
229        && model
230            .tensor(&format!("{prefix}mlp.experts.0.gate_proj.weight"))
231            .is_some();
232    if model.tensor(&router_name).is_none() && !resonance_moe {
233        return Ok(FfnKind::Dense(load_dense(&format!("{prefix}mlp."))?));
234    }
235    let cfg = arch.moe.as_ref().ok_or_else(|| {
236        CmfError::Parse(format!(
237            "{router_name} present but header has no arch.moe block"
238        ))
239    })?;
240    // Experts enumerate by TENSOR PRESENCE up to the header count — a
241    // moe-defrag'd specialist keeps a per-layer contiguous prefix of
242    // renumbered experts (fewer than arch.moe.num_experts), with the
243    // router rows sliced to match.
244    let mut experts = Vec::new();
245    for e in 0..cfg.num_experts {
246        if model
247            .tensor(&format!("{prefix}mlp.experts.{e}.gate_proj.weight"))
248            .is_none()
249        {
250            break;
251        }
252        experts.push(load_dense(&format!("{prefix}mlp.experts.{e}."))?);
253    }
254    if experts.is_empty() {
255        return Err(CmfError::Parse(format!(
256            "{prefix}: router present but no expert tensors"
257        )));
258    }
259    let shared = if model
260        .tensor(&format!("{prefix}mlp.shared_expert.gate_proj.weight"))
261        .is_some()
262    {
263        let gate_name = format!("{prefix}mlp.shared_expert_gate.weight");
264        Some((
265            load_dense(&format!("{prefix}mlp.shared_expert."))?,
266            if model.tensor(&gate_name).is_some() {
267                Some(load_matrix(model, &gate_name, force_f32, ov)?)
268            } else {
269                None
270            },
271        ))
272    } else {
273        None
274    };
275    // LFM2-MoE selection bias (`mlp.expert_bias`): present iff the model
276    // routes with a bias; loaded by tensor presence.
277    let bias_name = format!("{prefix}mlp.expert_bias");
278    let expert_bias = if model.tensor(&bias_name).is_some() {
279        Some(load_f32(model, &bias_name, ov).map_err(CmfError::Parse)?)
280    } else {
281        None
282    };
283    // CMF_MOE_TOPK=N (opt-in): route to fewer experts than the header
284    // asks. MoE decode is memory-bound — every selected expert streams
285    // its three matrices per token — so halving k halves that traffic;
286    // the renormalized top-k keeps the mixture a proper average.
287    // Quality is the experiment — measure ppl before trusting.
288    let top_k = std::env::var("CMF_MOE_TOPK")
289        .ok()
290        .and_then(|v| v.parse::<usize>().ok())
291        .filter(|&k| k >= 1 && k <= cfg.top_k)
292        .inspect(|k| tracing::info!("MoE top_k override: {} (header {})", k, cfg.top_k))
293        .unwrap_or(cfg.top_k);
294    // CMF_MOE_TAU=0.x (opt-in): adaptive routing — see MoeFfn::route_tau.
295    let route_tau = std::env::var("CMF_MOE_TAU")
296        .ok()
297        .and_then(|v| v.parse::<f32>().ok())
298        .filter(|&t| t > 0.0 && t < 1.0)
299        .inspect(|t| tracing::info!("MoE adaptive routing: tau {t}"));
300    let mask = moe_task_mask(model, &prefix, experts.len());
301    let router = if resonance_moe {
302        // never read (selection is by descriptors); zero placeholder in RAM
303        QTensor::from_f32(
304            vec![0.0; experts.len() * arch.hidden_size],
305            experts.len(),
306            arch.hidden_size,
307        )
308    } else {
309        load_matrix(model, &router_name, force_f32, ov)?
310    };
311    if router.rows() != experts.len() {
312        return Err(CmfError::Parse(format!(
313            "{router_name}: {} rows != {} experts",
314            router.rows(),
315            experts.len()
316        )));
317    }
318    let top_k = top_k.min(experts.len());
319    // Gemma-4: per-expert weight scale after the top-k renorm; its
320    // presence also marks the scale-less-rms router input (the folded
321    // router gain — see the converter).
322    let pes_name = format!("{prefix}mlp.per_expert_scale");
323    let per_expert_scale = if model.tensor(&pes_name).is_some() {
324        Some(load_f32(model, &pes_name, ov).map_err(CmfError::Parse)?)
325    } else {
326        None
327    };
328    let router_input_norm = per_expert_scale.is_some();
329    // Cortiq Embryo resonance descriptors: per-expert records
330    // `mlp.experts.{e}.desc.{mu,u,bias}` (append-only growth) or the legacy
331    // per-layer `mlp.desc.{mu,u,bias}` [E, ...]. Present → the router is a
332    // placeholder and selection is by reconstruction error.
333    let per_expert = model
334        .tensor(&format!("{prefix}mlp.experts.0.desc.mu"))
335        .is_some();
336    let resonance = if per_expert {
337        let ne_d = experts.len();
338        let hidden = arch.hidden_size;
339        let mut mu = Vec::with_capacity(ne_d * hidden);
340        let mut u = Vec::new();
341        let mut bias = Vec::with_capacity(ne_d);
342        let mut k = 0usize;
343        for e in 0..ne_d {
344            let m = load_f32(model, &format!("{prefix}mlp.experts.{e}.desc.mu"), ov)
345                .map_err(CmfError::Parse)?;
346            if m.len() != hidden {
347                return Err(CmfError::Parse(format!(
348                    "{prefix}mlp.experts.{e}.desc.mu: {} != {hidden}",
349                    m.len()
350                )));
351            }
352            mu.extend_from_slice(&m);
353            let un = format!("{prefix}mlp.experts.{e}.desc.u");
354            if model.tensor(&un).is_some() {
355                let ue = load_f32(model, &un, ov).map_err(CmfError::Parse)?;
356                let ke = ue.len() / hidden.max(1);
357                if e == 0 {
358                    k = ke;
359                }
360                if ke != k {
361                    return Err(CmfError::Parse(format!("{un}: rank {ke} != {k}")));
362                }
363                u.extend_from_slice(&ue);
364            }
365            let bn = format!("{prefix}mlp.experts.{e}.desc.bias");
366            bias.push(if model.tensor(&bn).is_some() {
367                load_f32(model, &bn, ov)
368                    .map_err(CmfError::Parse)?
369                    .first()
370                    .copied()
371                    .unwrap_or(0.0)
372            } else {
373                0.0
374            });
375        }
376        Some(crate::pipeline::Resonance { mu, u, k, bias })
377    } else if model.tensor(&format!("{prefix}mlp.desc.mu")).is_some() {
378        let mu = load_f32(model, &format!("{prefix}mlp.desc.mu"), ov).map_err(CmfError::Parse)?;
379        let ne_d = experts.len();
380        let hidden = arch.hidden_size;
381        if mu.len() != ne_d * hidden {
382            return Err(CmfError::Parse(format!(
383                "{prefix}mlp.desc.mu: {} != {ne_d}×{hidden}",
384                mu.len()
385            )));
386        }
387        let u_name = format!("{prefix}mlp.desc.u");
388        let (u, k) = if model.tensor(&u_name).is_some() {
389            let u = load_f32(model, &u_name, ov).map_err(CmfError::Parse)?;
390            let k = u.len() / (ne_d * hidden).max(1);
391            (u, k)
392        } else {
393            (Vec::new(), 0)
394        };
395        let b_name = format!("{prefix}mlp.desc.bias");
396        let bias = if model.tensor(&b_name).is_some() {
397            load_f32(model, &b_name, ov).map_err(CmfError::Parse)?
398        } else {
399            vec![0.0; ne_d]
400        };
401        Some(crate::pipeline::Resonance { mu, u, k, bias })
402    } else {
403        None
404    };
405    let moe = MoeFfn {
406        router,
407        experts,
408        top_k,
409        route_tau,
410        norm_topk_prob: cfg.norm_topk_prob,
411        router_sigmoid: cfg.router_sigmoid,
412        expert_bias,
413        routed_scaling: cfg.routed_scaling_factor.unwrap_or(1.0),
414        shared,
415        stats: std::cell::RefCell::new(Vec::new()),
416        act_sq: std::cell::RefCell::new(Vec::new()),
417        act_rows: std::cell::RefCell::new(Vec::new()),
418        mask,
419        per_expert_scale,
420        router_input_norm,
421        resonance,
422    };
423    // Gemma-4 dual-branch layer: a dense MLP coexists with the routed
424    // experts, each branch inside its own norm sandwich.
425    if model
426        .tensor(&format!("{prefix}mlp.gate_proj.weight"))
427        .is_some()
428    {
429        let norm = |suffix: &str| -> Result<Vec<f32>, CmfError> {
430            load_f32(model, &format!("{prefix}{suffix}.weight"), ov).map_err(CmfError::Parse)
431        };
432        return Ok(FfnKind::DenseMoe(Box::new(crate::pipeline::DenseMoeFfn {
433            dense: load_dense(&format!("{prefix}mlp."))?,
434            moe,
435            post_norm_1: norm("post_feedforward_layernorm_1")?,
436            pre_norm_2: norm("pre_feedforward_layernorm_2")?,
437            post_norm_2: norm("post_feedforward_layernorm_2")?,
438        })));
439    }
440    Ok(FfnKind::Moe(moe))
441}
442
443/// Task mask over routed experts: DTG-MA applied to MoE.
444///
445/// This is deliberately diagnostic-only. A route-mass sidecar can look good
446/// on a short perplexity window and still collapse during a long
447/// autoregressive generation: excluding a low-mass expert changes the model,
448/// and the changed prefix changes every later route. Consequently a nearby
449/// `<model>.moe-mass.json` is NEVER adopted implicitly. `CMF_MOE_MASK=...`
450/// remains an explicit experiment and accepts both weighted and legacy count
451/// files; production acceleration must preserve the full router and treat a
452/// non-resident winner as an exact cold completion.
453pub(crate) fn moe_task_mask(
454    _model: &std::sync::Arc<CmfModel>,
455    prefix: &str,
456    ne: usize,
457) -> Option<Vec<bool>> {
458    use std::sync::OnceLock;
459    static CFG: OnceLock<Option<(std::collections::HashMap<usize, Vec<u64>>, f64)>> =
460        OnceLock::new();
461    let cfg = CFG.get_or_init(|| {
462        let path = std::path::PathBuf::from(std::env::var("CMF_MOE_MASK").ok()?);
463        let shown = path.display();
464        let text = std::fs::read_to_string(&path)
465            .map_err(|e| tracing::warn!("CMF_MOE_MASK: cannot read {shown}: {e}"))
466            .ok()?;
467        let map: std::collections::HashMap<String, Vec<u64>> = serde_json::from_str(&text)
468            .map_err(|e| tracing::warn!("CMF_MOE_MASK: bad JSON in {shown}: {e}"))
469            .ok()?;
470        // Weighted dumps store normalized route mass in fixed-point units
471        // and therefore have per-layer totals many orders above the old
472        // top-k vote counts. The magnitude distinguishes the two explicit
473        // diagnostic formats without relying on a special filename.
474        let weighted = map
475            .values()
476            .any(|row| row.iter().copied().sum::<u64>() >= 1_000_000);
477        let cover = std::env::var("CMF_MOE_MASK_COVER")
478            .ok()
479            .and_then(|v| v.parse::<f64>().ok())
480            .filter(|&c| c > 0.0 && c <= 1.0)
481            .unwrap_or(if weighted { 0.925 } else { 0.9 });
482        tracing::info!("MoE task mask: {shown}, cover {cover}");
483        Some((
484            map.into_iter()
485                .filter_map(|(k, v)| Some((k.parse::<usize>().ok()?, v)))
486                .collect(),
487            cover,
488        ))
489    });
490    let (stats, cover) = cfg.as_ref()?;
491    // The layer index rides in the tensor prefix ("model.layers.N.").
492    let li: usize = prefix
493        .split("layers.")
494        .nth(1)?
495        .split('.')
496        .next()?
497        .parse()
498        .ok()?;
499    let counts = stats.get(&li)?;
500    if counts.len() != ne {
501        tracing::warn!(
502            "CMF_MOE_MASK: layer {li} has {} counts, model has {ne} experts — skipped",
503            counts.len()
504        );
505        return None;
506    }
507    let total: u64 = counts.iter().sum();
508    if total == 0 {
509        return None;
510    }
511    let mut order: Vec<usize> = (0..ne).collect();
512    order.sort_unstable_by_key(|&e| std::cmp::Reverse(counts[e]));
513    let mut mask = vec![false; ne];
514    let mut acc = 0u64;
515    let mut kept = 0usize;
516    for &e in &order {
517        mask[e] = true;
518        acc += counts[e];
519        kept += 1;
520        if (acc as f64) >= cover * (total as f64) {
521            break;
522        }
523    }
524    tracing::info!(
525        "MoE task mask L{li}: {kept}/{ne} experts for {:.0}% mass",
526        cover * 100.0
527    );
528    Some(mask)
529}
530
531pub(crate) fn load_matrix(
532    model: &Arc<CmfModel>,
533    name: &str,
534    force_f32: bool,
535    ov: &Overlay,
536) -> Result<QTensor, CmfError> {
537    // Claim 14: a blended working tensor is materialized in f32 and
538    // held resident (the overlay-cache slot); single skills stay
539    // zero-copy pointers into the mmap.
540    if ov.blend_touches(model, name) {
541        if let Overlay::Blend(list) = ov {
542            let entry = model
543                .tensor(name)
544                .ok_or_else(|| CmfError::MissingTensor(name.to_string()))?;
545            let data =
546                blend_f32(model, name, list).map_err(|e| CmfError::Parse(format!("blend: {e}")))?;
547            return Ok(QTensor::from_f32(data, entry.shape[0], entry.shape[1]));
548        }
549    }
550    let skill = match ov {
551        Overlay::One(s) => Some(*s),
552        _ => None,
553    };
554    // Tensor-source indirection (spec §9): the skill's replacement is
555    // read in place of the backbone tensor — either/or, never a sum.
556    let name: &str = &match skill {
557        Some(sid) if model.tensor(&format!("skill.{sid}.{name}")).is_some() => {
558            format!("skill.{sid}.{name}")
559        }
560        _ => name.to_string(),
561    };
562    let err = |e: String| CmfError::Parse(format!("weight loading: {e}"));
563    if force_f32 {
564        let entry = model
565            .tensor(name)
566            .ok_or_else(|| CmfError::MissingTensor(name.to_string()))?;
567        if entry.shape.len() != 2 {
568            return Err(err(format!("'{name}' is not 2-D")));
569        }
570        let data = load_f32(model, name, &Overlay::None).map_err(err)?;
571        Ok(QTensor::from_f32(data, entry.shape[0], entry.shape[1]))
572    } else {
573        QTensor::from_model(model, name).map_err(err)
574    }
575}
576
577impl Pipeline {
578    /// Build a runnable pipeline from an opened CMF model.
579    pub fn from_model(
580        model: &Arc<CmfModel>,
581        sampler_config: SamplerConfig,
582    ) -> Result<Self, CmfError> {
583        Self::from_model_with_skill(model, sampler_config, None)
584    }
585
586    /// Same, with a skill overlaid (spec §9): every layer tensor is
587    /// resolved through tensor-source indirection — the skill's
588    /// full-shape replacement is read in place of the backbone tensor.
589    /// No per-skill model is ever assembled: Mapped tensors are
590    /// pointers into the one shared mmap.
591    pub fn from_model_with_skill(
592        model: &Arc<CmfModel>,
593        sampler_config: SamplerConfig,
594        skill: Option<&str>,
595    ) -> Result<Self, CmfError> {
596        match skill {
597            Some(s) => Self::from_model_with_overlay(model, sampler_config, &Overlay::One(s)),
598            None => Self::from_model_with_overlay(model, sampler_config, &Overlay::None),
599        }
600    }
601
602    /// Soft superposition (claim 14): working tensors accumulated from
603    /// the given (skill, weight) list — softmax(−E/T) upstream.
604    pub fn from_model_with_blend(
605        model: &Arc<CmfModel>,
606        sampler_config: SamplerConfig,
607        blend: &[(String, f32)],
608    ) -> Result<Self, CmfError> {
609        Self::from_model_with_overlay(model, sampler_config, &Overlay::Blend(blend))
610    }
611
612    fn skill_file_guard(model: &CmfModel) -> Result<(), CmfError> {
613        // A standalone skill file carries a PARTIAL tensor set cut against
614        // a base; running it would be half a network answering questions.
615        if model.required_features & cortiq_core::format::features::SKILL_FILE != 0 {
616            return Err(CmfError::Parse(
617                "this file is a standalone SKILL, not a runnable model — attach it: \
618                 cortiq skill apply <base.cmf> <this file> -o specialist.cmf"
619                    .into(),
620            ));
621        }
622        Ok(())
623    }
624
625    fn from_model_with_overlay(
626        model: &Arc<CmfModel>,
627        sampler_config: SamplerConfig,
628        ov: &Overlay,
629    ) -> Result<Self, CmfError> {
630        // Small device caches (probe verdicts, compiled pipelines) go
631        // beside the model: it is a directory the caller demonstrably
632        // writes to, which `std::env::temp_dir()` is not inside an
633        // Android app sandbox.
634        if let Some(dir) = model.path.parent() {
635            crate::gpu::set_cache_dir(dir.to_path_buf());
636        }
637        // A new model gets a fresh verdict on whether the token graph can
638        // be built: the refusal is remembered per model, not per process.
639        crate::gpu::graph_unsupported_reset();
640        Self::skill_file_guard(model)?;
641        let skill = match ov {
642            Overlay::One(s) => Some(*s),
643            _ => None,
644        };
645        if let Some(sid) = skill {
646            let known = model.header.skills.iter().any(|s| s.id == sid)
647                || model.skill_tensors(sid).next().is_some();
648            if !known {
649                return Err(CmfError::Parse(format!(
650                    "skill '{sid}' not in this container (header.skills: {:?})",
651                    model
652                        .header
653                        .skills
654                        .iter()
655                        .map(|s| &s.id)
656                        .collect::<Vec<_>>()
657                )));
658            }
659            tracing::info!(
660                "skill '{sid}': {} replacement tensors overlaid",
661                model.skill_tensors(sid).count()
662            );
663        }
664        let arch = model.arch().clone();
665        let err = |e: String| CmfError::Parse(format!("weight loading: {e}"));
666        if let Some(heads) = &arch.attention_heads_per_layer {
667            if heads.len() != arch.num_layers {
668                return Err(CmfError::Parse(format!(
669                    "arch.attention_heads_per_layer has {} entries, expected {}",
670                    heads.len(),
671                    arch.num_layers
672                )));
673            }
674            if let Some((li, &nh)) = heads
675                .iter()
676                .enumerate()
677                .find(|(_, nh)| **nh == 0 || **nh % arch.num_kv_heads != 0)
678            {
679                return Err(CmfError::Parse(format!(
680                    "layer {li} has {nh} Q heads, which must be nonzero and divisible by {} KV heads",
681                    arch.num_kv_heads
682                )));
683            }
684        }
685        if arch
686            .layer_types
687            .iter()
688            .any(|t| matches!(t, LayerType::SlidingAttention))
689            && arch.sliding_window.is_none()
690        {
691            return Err(CmfError::Parse(
692                "model has SlidingAttention layers but no arch.sliding_window".into(),
693            ));
694        }
695
696        // Masks × quantized mmap: only the HEAD-mask path needs f32
697        // slices, so f32 is forced only when some mask actually restricts
698        // attention heads. FFN masks run sparse directly on the quant
699        // bytes (sparse_ffn_quant), and embed/lm_head are never masked.
700        // The old condition forced f32 for ANY mask: a 4.17 B file whose
701        // mask touched only the FFN dequantized to 16.7 GB at load and
702        // ran the bare-f32 GEMMs — 0.0 tok/s on a laptop that swapped,
703        // and a 30× crawl on a 48-core server. A mask with no head rows
704        // costs nothing now.
705        let heads_masked = model.masks.masks.iter().any(|m| {
706            m.head_masks.iter().any(|row| {
707                let mut bits = 0usize;
708                for &b in row.iter() {
709                    bits += b.count_ones() as usize;
710                }
711                !row.is_empty() && bits < arch.num_attention_heads
712            })
713        });
714        let force_f32 = heads_masked; // attention only (head masks)
715
716        // ── Tokenizer: embedded → sidecar → byte-level fallback ──
717        let mut tokenizer = if let Some(vocab_bytes) = &model.vocab {
718            Tokenizer::from_bytes(vocab_bytes)
719                .map_err(|e| CmfError::Parse(format!("embedded tokenizer: {e}")))?
720        } else {
721            let sidecar = model.path.with_file_name("tokenizer.json");
722            if sidecar.exists() {
723                Tokenizer::from_file(&sidecar)
724                    .map_err(|e| CmfError::Parse(format!("sidecar tokenizer: {e}")))?
725            } else {
726                tracing::warn!("no tokenizer in file or sidecar — using byte-level fallback");
727                Tokenizer::byte_level()
728            }
729        };
730        // Chat/eos bundle (spec §6.1): the FILE defines chat behavior.
731        if let Some(tc) = &model.header.tokenizer_config {
732            tokenizer.chat_template = tc.chat_template.clone();
733            tokenizer.extra_eos.extend(tc.eos_token_ids.iter().copied());
734            if tokenizer.bos_token_id.is_none() {
735                tokenizer.bos_token_id = tc.bos_token_id;
736            }
737            tracing::info!(
738                "chat bundle: template {} chars, {} stop ids",
739                tc.chat_template.as_deref().map(str::len).unwrap_or(0),
740                tc.eos_token_ids.len()
741            );
742        }
743        // Gemma's contract requires <bos> at sequence start, but its
744        // tokenizer.json post-processor does not add it (the chat
745        // template does). Raw prompts need it too — word salad without.
746        if arch.arch_name.to_lowercase().contains("gemma") && tokenizer.bos_token_id.is_some() {
747            tokenizer.add_bos = true;
748        }
749
750        // ── Top-level weights (never masked → always quantized) ──
751        let embed_tokens = load_matrix(model, "model.embed_tokens.weight", false, ov)?;
752        let final_norm = if arch.qwen4_exp.is_some() {
753            // qwen4_exp folds its four streams through a learned global
754            // hyper mixer and has no conventional final RMSNorm.
755            vec![0.0; arch.hidden_size]
756        } else {
757            load_f32(model, "model.norm.weight", ov).map_err(err)?
758        };
759        let lm_head = if model.tensor("lm_head.weight").is_some() {
760            load_matrix(model, "lm_head.weight", false, ov)?
761        } else if arch.tie_word_embeddings {
762            // Tied: reuse the embedding matrix (re-open, cheap for Mapped).
763            load_matrix(model, "model.embed_tokens.weight", false, ov)?
764        } else {
765            return Err(CmfError::MissingTensor(
766                "lm_head.weight (and tie_word_embeddings is false)".into(),
767            ));
768        };
769
770        // ── Linear-core geometry (required if any linear layer exists) ──
771        let has_linear = arch
772            .layer_types
773            .iter()
774            .any(|t| matches!(t, LayerType::LinearAttention));
775        let mut vmf_cfg = None;
776        let mut gdn_cfg = None;
777        if has_linear {
778            let lc = arch.linear_core.as_ref().ok_or_else(|| {
779                CmfError::Parse(
780                    "model has LinearAttention layers but no arch.linear_core — \
781                     reconvert with the current converter"
782                        .into(),
783                )
784            })?;
785            let need = |v: Option<usize>, name: &str| {
786                v.ok_or_else(|| CmfError::Parse(format!("linear core needs arch.{name}")))
787            };
788            match lc.kind.as_str() {
789                "vmf_phase" => {
790                    vmf_cfg = Some(VmfPhaseCfg {
791                        num_heads: lc.num_heads,
792                        nphase: need(lc.nphase, "linear_core.nphase")?,
793                        value_head_dim: lc.value_head_dim,
794                        hidden_size: arch.hidden_size,
795                        // Phase-mass correction: default 0 (disabled); CMF_PHASE_MASS
796                        // widens the phase kernel for folded-unhealed models.
797                        phase_mass: std::env::var("CMF_PHASE_MASS")
798                            .ok()
799                            .and_then(|v| v.parse().ok())
800                            .unwrap_or(0.0),
801                    });
802                }
803                "gated_delta_net" => {
804                    gdn_cfg = Some(GdnCfg {
805                        num_v_heads: lc.num_heads,
806                        num_k_heads: need(arch.linear_num_key_heads, "linear_num_key_heads")?,
807                        key_head_dim: need(arch.linear_key_head_dim, "linear_key_head_dim")?,
808                        value_head_dim: lc.value_head_dim,
809                        conv_kernel: need(arch.linear_conv_kernel_dim, "linear_conv_kernel_dim")?,
810                        hidden_size: arch.hidden_size,
811                        rms_eps: arch.rms_norm_eps,
812                        output_gate_sigmoid: false,
813                    });
814                }
815                other => {
816                    return Err(CmfError::Parse(format!(
817                        "unknown linear core '{other}' (this runtime executes: \
818                         gated_delta_net, vmf_phase)"
819                    )));
820                }
821            }
822        }
823
824        // ── KDA geometry (Kimi Linear / Kimi-K3 delta-attention layers) ──
825        let has_kda = arch.layer_types.iter().any(|t| matches!(t, LayerType::Kda));
826        let kda_cfg = if has_kda {
827            let need = |v: Option<usize>, name: &str| {
828                v.ok_or_else(|| CmfError::Parse(format!("KDA core needs arch.{name}")))
829            };
830            Some(crate::linear_core::KdaCfg {
831                num_heads: need(arch.linear_num_key_heads, "linear_num_key_heads")?,
832                head_k_dim: need(arch.linear_key_head_dim, "linear_key_head_dim")?,
833                head_v_dim: need(arch.linear_value_head_dim, "linear_value_head_dim")?,
834                conv_kernel: need(arch.linear_conv_kernel_dim, "linear_conv_kernel_dim")?,
835                hidden_size: arch.hidden_size,
836                rms_eps: arch.rms_norm_eps,
837            })
838        } else {
839            None
840        };
841
842        // ── Short-convolution geometry (LFM2 conv mixer layers) ──
843        let has_short_conv = arch
844            .layer_types
845            .iter()
846            .any(|t| matches!(t, LayerType::ShortConv));
847        let short_conv_cfg = if has_short_conv {
848            Some(ShortConvCfg {
849                hidden_size: arch.hidden_size,
850                kernel: arch.linear_conv_kernel_dim.ok_or_else(|| {
851                    CmfError::Parse(
852                        "model has ShortConv layers but no arch.linear_conv_kernel_dim — \
853                         reconvert with the current converter"
854                            .into(),
855                    )
856                })?,
857            })
858        } else {
859            None
860        };
861
862        // ── Layers ──
863        let load_full_attn = |prefix: &str, layer: Option<usize>| -> Result<AttnKind, CmfError> {
864            let t = |suffix: &str| load_matrix(model, &format!("{prefix}{suffix}"), force_f32, ov);
865            let n = |suffix: &str| -> Option<Vec<f32>> {
866                model
867                    .tensor(&format!("{prefix}{suffix}"))
868                    .and_then(|_| load_f32(model, &format!("{prefix}{suffix}"), ov).ok())
869            };
870            // DeepSeek-V2 MLA: the latent projections replace the k/v pair.
871            if let Some(mla) = arch.mla.as_ref() {
872                // Compressed q (K3/V3): q_a → rms → q_b; direct otherwise.
873                let (q_proj, q_a, q_a_norm) = if mla.q_lora_rank.is_some() {
874                    (
875                        t("self_attn.q_b_proj.weight")?,
876                        Some(t("self_attn.q_a_proj.weight")?),
877                        Some(n("self_attn.q_a_layernorm.weight").ok_or_else(|| {
878                            CmfError::Parse(format!("{prefix}: MLA needs q_a_layernorm"))
879                        })?),
880                    )
881                } else {
882                    (t("self_attn.q_proj.weight")?, None, None)
883                };
884                let hd = mla.qk_rope_head_dim + mla.qk_nope_head_dim;
885                let nh = q_proj.rows() / hd;
886                // YaRN mscale²: DeepSeek corrects the softmax scale by
887                // (0.1·mscale_all_dim·ln(factor)+1)².
888                let mut scale = 1.0 / (hd as f32).sqrt();
889                if let Some(y) = arch.yarn.as_ref() {
890                    if let Some(m) = y.mscale_all_dim.filter(|&m| m > 0.0) {
891                        let ms = 0.1 * m * y.factor.ln() + 1.0;
892                        scale *= ms * ms;
893                    }
894                }
895                return Ok(AttnKind::Mla(Box::new(crate::pipeline::MlaWeights {
896                    q_proj,
897                    q_a,
898                    q_a_norm,
899                    kv_a: t("self_attn.kv_a_proj_with_mqa.weight")?,
900                    kv_a_norm: n("self_attn.kv_a_layernorm.weight").ok_or_else(|| {
901                        CmfError::Parse(format!("{prefix}: MLA needs kv_a_layernorm"))
902                    })?,
903                    kv_b: t("self_attn.kv_b_proj.weight")?,
904                    o_proj: t("self_attn.o_proj.weight")?,
905                    nh,
906                    qk_rope: mla.qk_rope_head_dim,
907                    qk_nope: mla.qk_nope_head_dim,
908                    v_dim: mla.v_head_dim,
909                    lora: mla.kv_lora_rank,
910                    scale,
911                    nope: mla.nope,
912                })));
913            }
914            let wq = t("self_attn.q_proj.weight")?;
915            let nh = layer
916                .and_then(|li| {
917                    arch.attention_heads_per_layer
918                        .as_ref()
919                        .and_then(|v| v.get(li).copied())
920                })
921                .unwrap_or(arch.num_attention_heads);
922            // Qwen3.5 output gate: q_proj rows = 2·nh·hd (per-head [q; gate]).
923            // Gemma-4 global layers legitimately have nh·global_head_dim
924            // rows (which can equal 2·nh·hd) — never gated.
925            let output_gate = arch.global_head_dim.is_none() && wq.rows() == 2 * nh * arch.head_dim;
926            // Gemma-4 global layers run MQA at global_head_dim — their
927            // q_proj legitimately carries nh·ghd rows.
928            let is_global_layer = arch.global_head_dim.is_some()
929                && layer.is_some_and(|li| {
930                    arch.sliding_window_pattern
931                        .is_some_and(|p| p > 0 && (li + 1) % p == 0)
932                });
933            let expect = if is_global_layer {
934                nh * arch.global_head_dim.unwrap_or(arch.head_dim)
935            } else {
936                nh * arch.head_dim
937            };
938            if !output_gate && wq.rows() != expect {
939                return Err(CmfError::Parse(format!(
940                    "{prefix}self_attn.q_proj.weight rows={} != heads({nh}) * head_dim({})",
941                    wq.rows(),
942                    expect / nh.max(1)
943                )));
944            }
945            let gate_name = format!("{prefix}self_attn.g_proj.weight");
946            let softplus_gate = if model.tensor(&gate_name).is_some() {
947                let gate = load_matrix(model, &gate_name, force_f32, ov)?;
948                if gate.cols() != arch.hidden_size {
949                    return Err(CmfError::Parse(format!(
950                        "{gate_name} cols={} != hidden_size ({})",
951                        gate.cols(),
952                        arch.hidden_size
953                    )));
954                }
955                let per_head = if gate.rows() == nh {
956                    true
957                } else if gate.rows() == nh * arch.head_dim {
958                    false
959                } else {
960                    return Err(CmfError::Parse(format!(
961                        "{gate_name} rows={} must equal heads ({nh}) or heads*head_dim ({})",
962                        gate.rows(),
963                        nh * arch.head_dim
964                    )));
965                };
966                Some((gate, per_head))
967            } else {
968                None
969            };
970            // Qwen2-family projection biases (by tensor presence).
971            let bias = match (
972                n("self_attn.q_proj.bias"),
973                n("self_attn.k_proj.bias"),
974                n("self_attn.v_proj.bias"),
975            ) {
976                (Some(a), Some(b), Some(c)) => Some((a, b, c)),
977                _ => None,
978            };
979            Ok(AttnKind::Full {
980                wq,
981                wk: t("self_attn.k_proj.weight")?,
982                wv: t("self_attn.v_proj.weight")?,
983                wo: t("self_attn.o_proj.weight")?,
984                q_norm: n("self_attn.q_norm.weight"),
985                k_norm: n("self_attn.k_norm.weight"),
986                output_gate,
987                softplus_gate,
988                bias,
989            })
990        };
991
992        let load_linear_attn = |prefix: &str| -> Result<AttnKind, CmfError> {
993            if gdn_cfg.is_some() {
994                // Faithful vendor operator: tensor names 1:1 with the source.
995                let t = |suffix: &str| {
996                    load_matrix(
997                        model,
998                        &format!("{prefix}linear_attn.{suffix}"),
999                        force_f32,
1000                        ov,
1001                    )
1002                };
1003                let f = |suffix: &str| {
1004                    load_f32(model, &format!("{prefix}linear_attn.{suffix}"), ov).map_err(err)
1005                };
1006                return Ok(AttnKind::LinearGdn(GdnWeights {
1007                    in_proj_qkv: t("in_proj_qkv.weight")?,
1008                    in_proj_z: t("in_proj_z.weight")?,
1009                    in_proj_a: t("in_proj_a.weight")?,
1010                    in_proj_b: t("in_proj_b.weight")?,
1011                    conv1d: f("conv1d.weight")?,
1012                    a_log: f("A_log")?,
1013                    dt_bias: f("dt_bias")?,
1014                    norm: f("norm.weight")?,
1015                    out_proj: t("out_proj.weight")?,
1016                }));
1017            }
1018            let t = |suffix: &str| {
1019                load_matrix(model, &format!("{prefix}vmf_attn.{suffix}"), force_f32, ov)
1020            };
1021            let a_log = load_f32(model, &format!("{prefix}vmf_attn.A_log"), ov).map_err(err)?;
1022            // Selective-write gate κ (hybrid_k core): optional by tensor
1023            // presence — files without it run the classic phase kernel
1024            // bit-identically.
1025            let k_gate = if model
1026                .tensor(&format!("{prefix}vmf_attn.k_gate.weight"))
1027                .is_some()
1028            {
1029                Some((
1030                    t("k_gate.weight")?,
1031                    load_f32(model, &format!("{prefix}vmf_attn.k_gate.bias"), ov).map_err(err)?,
1032                ))
1033            } else {
1034                None
1035            };
1036            // Optional short causal conv (embryo genomes born with
1037            // --conv-k): `[hidden, 1, k]` taps, flattened.
1038            let conv = if model
1039                .tensor(&format!("{prefix}vmf_attn.conv1d.weight"))
1040                .is_some()
1041            {
1042                Some(load_f32(model, &format!("{prefix}vmf_attn.conv1d.weight"), ov).map_err(err)?)
1043            } else {
1044                None
1045            };
1046            Ok(AttnKind::Linear(VmfPhaseWeights {
1047                thq: t("thq.weight")?,
1048                conv,
1049                thk: t("thk.weight")?,
1050                v_proj: t("v_proj.weight")?,
1051                out_proj: t("out_proj.weight")?,
1052                decay: a_log.iter().map(|&a| (-(a as f64).exp()).exp()).collect(),
1053                k_gate,
1054            }))
1055        };
1056
1057        // LFM2 short-conv mixer: in_proj [3·hidden, hidden], a depthwise
1058        // conv (stored f16 as `[hidden, 1, kernel]` → flattened taps), and
1059        // out_proj [hidden, hidden]. Names canonicalized at convert time.
1060        let load_short_conv = |prefix: &str| -> Result<AttnKind, CmfError> {
1061            let t = |suffix: &str| {
1062                load_matrix(
1063                    model,
1064                    &format!("{prefix}short_conv.{suffix}"),
1065                    force_f32,
1066                    ov,
1067                )
1068            };
1069            Ok(AttnKind::ShortConv(ShortConvWeights {
1070                in_proj: t("in_proj.weight")?,
1071                conv: load_f32(model, &format!("{prefix}short_conv.conv.weight"), ov)
1072                    .map_err(err)?,
1073                out_proj: t("out_proj.weight")?,
1074            }))
1075        };
1076
1077        // KDA layer (Kimi Linear / Kimi-K3): faithful vendor tensors under
1078        // the `kda_attn.` canonical prefix. The output gate is full-rank
1079        // (g_proj, K3) or low-rank (g_a/g_b, Kimi-Linear-48B) by presence.
1080        let load_kda = |prefix: &str| -> Result<AttnKind, CmfError> {
1081            let t = |suffix: &str| {
1082                load_matrix(model, &format!("{prefix}kda_attn.{suffix}"), force_f32, ov)
1083            };
1084            let f = |suffix: &str| {
1085                load_f32(model, &format!("{prefix}kda_attn.{suffix}"), ov).map_err(err)
1086            };
1087            let gate = if model
1088                .tensor(&format!("{prefix}kda_attn.g_proj.weight"))
1089                .is_some()
1090            {
1091                crate::linear_core::KdaOutGate::Full(t("g_proj.weight")?)
1092            } else {
1093                crate::linear_core::KdaOutGate::LowRank(
1094                    t("g_a_proj.weight")?,
1095                    t("g_b_proj.weight")?,
1096                )
1097            };
1098            Ok(AttnKind::Kda(Box::new(crate::linear_core::KdaWeights {
1099                q_proj: t("q_proj.weight")?,
1100                k_proj: t("k_proj.weight")?,
1101                v_proj: t("v_proj.weight")?,
1102                conv_q: f("q_conv1d.weight")?,
1103                conv_k: f("k_conv1d.weight")?,
1104                conv_v: f("v_conv1d.weight")?,
1105                f_a: t("f_a_proj.weight")?,
1106                f_b: t("f_b_proj.weight")?,
1107                dt_bias: f("dt_bias")?,
1108                a_log: f("A_log")?,
1109                b_proj: t("b_proj.weight")?,
1110                gate,
1111                o_norm: f("o_norm.weight")?,
1112                o_proj: t("o_proj.weight")?,
1113                gate_lower_bound: arch.kda_gate_lower_bound.map(|v| v as f32),
1114            })))
1115        };
1116
1117        fn anyhow_like(ok: bool) -> Result<(), ()> {
1118            if ok { Ok(()) } else { Err(()) }
1119        }
1120        let mut layers = Vec::with_capacity(arch.num_layers);
1121        let is_g3n = arch.g3n.is_some();
1122        // Architectures that load their own layer stack below. DeepSeek-V4
1123        // has none of the canonical projections — no q/k/v/o_proj, no
1124        // per-layer gate_proj — so the generic loop would demand
1125        // `self_attn.q_proj.weight` and fail before its own loader ever ran.
1126        let owns_its_layers = is_g3n
1127            || arch.arch_name == "deepseek_v4"
1128            || arch.arch_name == "deepseek_v41"
1129            || arch.qwen4_exp.is_some();
1130        for li in 0..(if owns_its_layers { 0 } else { arch.num_layers }) {
1131            let prefix = format!("model.layers.{li}.");
1132            let attn = match arch.layer_types.get(li) {
1133                Some(LayerType::LinearAttention) => load_linear_attn(&prefix)?,
1134                Some(LayerType::Kda) => load_kda(&prefix)?,
1135                Some(LayerType::ShortConv) => load_short_conv(&prefix)?,
1136                _ => load_full_attn(&prefix, Some(li))?,
1137            };
1138            // Gemma-2/3 sandwich: `pre_feedforward_layernorm` present →
1139            // it is the pre-FFN norm, and post_attention/post_feedforward
1140            // норms apply to the branch OUTPUTS before their residuals.
1141            let pre_ffn = format!("{prefix}pre_feedforward_layernorm.weight");
1142            let sandwich = model.tensor(&pre_ffn).is_some();
1143            layers.push(LayerWeights {
1144                input_norm: load_f32(model, &format!("{prefix}input_layernorm.weight"), ov)
1145                    .map_err(err)?,
1146                post_norm: if sandwich {
1147                    load_f32(model, &pre_ffn, ov).map_err(err)?
1148                } else {
1149                    load_f32(
1150                        model,
1151                        &format!("{prefix}post_attention_layernorm.weight"),
1152                        ov,
1153                    )
1154                    .map_err(err)?
1155                },
1156                attn_out_norm: if sandwich {
1157                    Some(
1158                        load_f32(
1159                            model,
1160                            &format!("{prefix}post_attention_layernorm.weight"),
1161                            ov,
1162                        )
1163                        .map_err(err)?,
1164                    )
1165                } else {
1166                    None
1167                },
1168                ffn_out_norm: if sandwich {
1169                    Some(
1170                        load_f32(
1171                            model,
1172                            &format!("{prefix}post_feedforward_layernorm.weight"),
1173                            ov,
1174                        )
1175                        .map_err(err)?,
1176                    )
1177                } else {
1178                    None
1179                },
1180                // Gemma-4: learned scalar multiplying the layer output.
1181                layer_scale: model
1182                    .tensor(&format!("{prefix}layer_scalar"))
1183                    .and_then(|_| {
1184                        load_f32(model, &format!("{prefix}layer_scalar"), ov)
1185                            .ok()
1186                            .and_then(|v| v.first().copied())
1187                    }),
1188                // FFN always quantized — masks run sparse on quant bytes.
1189                ffn: build_layer_ffn(model, &arch, li, false, ov)?,
1190                attn,
1191            });
1192        }
1193
1194        // ── MTP head (optional, spec §2.1) ──
1195        //
1196        // The header declaring an MTP head is not the same as the file
1197        // carrying one. DeepSeek-V4's config announces a next-token predictor
1198        // whose weights the converter does not map (they are spelled `mtp.N.*`
1199        // and have none of the canonical projections), so demanding
1200        // `model.mtp.layers.0.self_attn.q_proj.weight` failed a model that is
1201        // otherwise complete. Presence in the directory decides.
1202        let mtp_present = model
1203            .tensor("model.mtp.layers.0.self_attn.q_proj.weight")
1204            .is_some()
1205            || model.tensor("model.mtp.eh_proj.weight").is_some();
1206        // DeepSeek-V4 writes its own stack under `model.mtp.N.*` — three full
1207        // layers, not a V3-style single block — so it cannot go through the
1208        // path below and is loaded by the dsv4 arm instead. Saying the file
1209        // "carries none" was a false negative worth six gigabytes.
1210        let dsv4_mtp = model.tensor("model.mtp.0.main_proj.weight").is_some();
1211        if arch.mtp.is_some() && !mtp_present && !dsv4_mtp {
1212            tracing::info!(
1213                "header declares an MTP head but the file carries none — \
1214                 loading without it"
1215            );
1216        }
1217        let mtp = if let Some(cfg) = arch.mtp.as_ref().filter(|_| mtp_present) {
1218            if cfg.num_layers != 1 {
1219                return Err(CmfError::Parse(format!(
1220                    "MTP with {} blocks not supported yet (only 1)",
1221                    cfg.num_layers
1222                )));
1223            }
1224            let p = "model.mtp.";
1225            let attn = load_full_attn("model.mtp.layers.0.", None)?;
1226            Some(MtpModule {
1227                enorm: load_f32(model, &format!("{p}enorm.weight"), ov).map_err(err)?,
1228                hnorm: load_f32(model, &format!("{p}hnorm.weight"), ov).map_err(err)?,
1229                eh_proj: load_matrix(model, &format!("{p}eh_proj.weight"), false, ov)?,
1230                layer: LayerWeights {
1231                    attn_out_norm: None,
1232                    ffn_out_norm: None,
1233                    layer_scale: None,
1234                    input_norm: load_f32(model, &format!("{p}layers.0.input_layernorm.weight"), ov)
1235                        .map_err(err)?,
1236                    post_norm: load_f32(
1237                        model,
1238                        &format!("{p}layers.0.post_attention_layernorm.weight"),
1239                        ov,
1240                    )
1241                    .map_err(err)?,
1242                    // Whatever the block actually carries: DeepSeek's MTP
1243                    // layer is dense, Qwen3.6's is a full MoE (router + 256
1244                    // experts + shared). Same builder as a backbone layer.
1245                    ffn: build_ffn_at(model, &arch, &format!("{p}layers.0."), false, ov)?,
1246                    attn,
1247                },
1248                final_norm: load_f32(model, &format!("{p}norm.weight"), ov).map_err(err)?,
1249                kv: LayerKvCache::new(arch.num_kv_heads, arch.head_dim),
1250            })
1251        } else {
1252            None
1253        };
1254
1255        tracing::info!(
1256            "Pipeline loaded: {} | {}L ({} linear) | {:.2}B params | storage: {} | MTP: {}",
1257            arch.arch_name,
1258            arch.num_layers,
1259            arch.layer_types
1260                .iter()
1261                .filter(|t| matches!(t, LayerType::LinearAttention))
1262                .count(),
1263            model.total_param_count() as f64 / 1e9,
1264            if force_f32 {
1265                "f32 (masked)"
1266            } else {
1267                "quantized mmap"
1268            },
1269            if mtp.is_some() { "yes" } else { "no" }
1270        );
1271
1272        // KV window: the descriptor's max, capped for dev-box safety;
1273        // CMF_MAX_SEQ overrides the cap (long-context runs).
1274        // 8192 was the silent quality cliff of the Qwen3.8 bring-up: at
1275        // the cap the wgpu token graph declines, the host evicts half the
1276        // KV, and a GDN hybrid's recurrent state goes stale — the model
1277        // stays fluent and loses its mind (Django internals, a Turkish
1278        // essay, an em-dash loop; one failure, three costumes). 32768
1279        // covers every long-form run we actually ship while keeping the
1280        // graph's device KV mirror affordable beside the weights;
1281        // CMF_MAX_SEQ still overrides in either direction.
1282        let cap = std::env::var("CMF_MAX_SEQ")
1283            .ok()
1284            .and_then(|v| v.parse::<usize>().ok())
1285            .unwrap_or(32_768);
1286        let max_seq_len = arch.max_position_embeddings.min(cap);
1287
1288        // Looped Transformer: total virtual layers = physical × num_loops.
1289        let total_layers = arch.num_layers * arch.num_loops;
1290
1291        let mut pipeline = Pipeline::new(
1292            tokenizer,
1293            PipelineWeights {
1294                embed_tokens,
1295                layers,
1296                lm_head,
1297                final_norm,
1298            },
1299            arch.hidden_size,
1300            arch.intermediate_size,
1301            arch.num_attention_heads,
1302            arch.num_kv_heads,
1303            arch.head_dim,
1304            total_layers,
1305            arch.num_layers, // physical layers in weights
1306            arch.loop_final_norm,
1307            arch.vocab_size,
1308            arch.rms_norm_eps,
1309            arch.rope_theta as f32,
1310            arch.norm_style,
1311            max_seq_len,
1312            sampler_config,
1313        );
1314        let rotary = ((arch.head_dim as f32 * arch.partial_rotary_factor) as usize).max(2);
1315        pipeline.set_rotary(rotary, arch.rope_theta as f32);
1316        pipeline.attention_heads_per_layer = arch.attention_heads_per_layer.clone();
1317        if let Some(yarn) = &arch.yarn {
1318            pipeline.inv_freq = std::sync::Arc::new(crate::attention::yarn_inv_freq(
1319                rotary,
1320                arch.rope_theta as f32,
1321                yarn.factor,
1322                yarn.original_max_position_embeddings,
1323                yarn.beta_fast,
1324                yarn.beta_slow,
1325            ));
1326            pipeline.rope_scale = yarn.attention_factor;
1327        }
1328        // Gemma-family extras: embedding scale, attention-scale
1329        // override, and (Gemma-3) sliding-window layers with their own
1330        // local RoPE base.
1331        pipeline.embed_multiplier = arch.embed_multiplier;
1332        pipeline.logit_multiplier = arch.logit_multiplier;
1333        if let Some(qpas) = arch.query_pre_attn_scalar {
1334            pipeline.attn_scale = 1.0 / (qpas as f32).sqrt();
1335        }
1336        if let (Some(w), Some(p)) = (arch.sliding_window, arch.sliding_window_pattern) {
1337            pipeline.swa = Some((w, p));
1338            if let Some(base) = arch.rope_local_base_freq {
1339                pipeline.inv_freq_local = Some(std::sync::Arc::new(
1340                    crate::attention::rope_inv_freq(rotary, base as f32),
1341                ));
1342            }
1343        }
1344        let explicit_sliding: Vec<bool> = arch
1345            .layer_types
1346            .iter()
1347            .map(|t| matches!(t, cortiq_core::LayerType::SlidingAttention))
1348            .collect();
1349        if explicit_sliding.iter().any(|&v| v) {
1350            pipeline.sliding_layers = Some(explicit_sliding);
1351            if let Some(w) = arch.sliding_window {
1352                pipeline.swa = Some((w, usize::MAX));
1353            }
1354            let local_rotary = ((arch.head_dim as f32
1355                * arch
1356                    .local_partial_rotary_factor
1357                    .unwrap_or(arch.partial_rotary_factor))
1358                as usize)
1359                .max(2);
1360            pipeline.rotary_dim_local = Some(local_rotary);
1361            if let Some(base) = arch.rope_local_base_freq {
1362                pipeline.inv_freq_local = Some(std::sync::Arc::new(
1363                    crate::attention::rope_inv_freq(local_rotary, base as f32),
1364                ));
1365            }
1366        }
1367        // Gemma-4: global layers run their own geometry (MQA at
1368        // global_head_dim) with a proportional RoPE — the first
1369        // factor·head_dim dims rotate, the zero-padded tail is identity.
1370        if let (Some(ghd), Some(gkv)) = (arch.global_head_dim, arch.num_global_kv_heads) {
1371            pipeline.global_attn = Some((ghd, gkv));
1372            let prf = arch.global_partial_rotary_factor.unwrap_or(1.0);
1373            let half = ghd / 2;
1374            let ra = (((prf * ghd as f32) as usize) / 2).min(half);
1375            let mut f = vec![0.0f32; half];
1376            for (i, slot) in f.iter_mut().enumerate().take(ra) {
1377                *slot = 1.0 / (arch.rope_theta as f32).powf(2.0 * i as f32 / ghd as f32);
1378            }
1379            pipeline.inv_freq_global = Some(std::sync::Arc::new(f));
1380            // Re-shape the global layers' KV storage to their geometry.
1381            // An explicit layer_types map wins over the numeric pattern
1382            // (explicit tags set swa's pattern to usize::MAX, which
1383            // would otherwise leave every global cache mis-shaped).
1384            let global_at = |li: usize| -> bool {
1385                match &pipeline.sliding_layers {
1386                    Some(map) => !map.get(li).copied().unwrap_or(false),
1387                    None => pipeline
1388                        .swa
1389                        .map(|(_, p)| p > 0 && p != usize::MAX && (li + 1) % p == 0)
1390                        .unwrap_or(false),
1391                }
1392            };
1393            for li in 0..arch.num_layers {
1394                if global_at(li) {
1395                    pipeline.kv_cache.layers[li] = crate::kv_cache::LayerKvCache::new(gkv, ghd);
1396                }
1397            }
1398        }
1399        // MLA (DeepSeek-V2): the expand-to-MHA cache holds nh heads of
1400        // rope+nope dims; rotary covers the rope prefix.
1401        if let Some(mla) = arch.mla.as_ref() {
1402            let hd = mla.qk_rope_head_dim + mla.qk_nope_head_dim;
1403            pipeline.head_dim = hd;
1404            pipeline.num_kv_heads = arch.num_attention_heads;
1405            pipeline.rotary_dim = mla.qk_rope_head_dim;
1406            let half = mla.qk_rope_head_dim / 2;
1407            let mut f = vec![0.0f32; half];
1408            for (i, slot) in f.iter_mut().enumerate() {
1409                *slot = 1.0
1410                    / (arch.rope_theta as f32).powf(2.0 * i as f32 / mla.qk_rope_head_dim as f32);
1411            }
1412            pipeline.inv_freq = std::sync::Arc::new(f);
1413            for li in 0..arch.num_layers {
1414                pipeline.kv_cache.layers[li] =
1415                    crate::kv_cache::LayerKvCache::new(arch.num_attention_heads, hd);
1416            }
1417        }
1418        // Per-frequency rope divisors (MiniCPM3 longrope short_factor):
1419        // served at the native window with the trained per-dim factors.
1420        // Applied after every inv_freq build (plain, YaRN, MLA).
1421        if let Some(fac) = &arch.rope_freq_factors {
1422            let mut f = pipeline.inv_freq.as_ref().clone();
1423            for (i, v) in f.iter_mut().enumerate() {
1424                if let Some(&d) = fac.get(i) {
1425                    *v /= d as f32;
1426                }
1427            }
1428            pipeline.inv_freq = std::sync::Arc::new(f);
1429        }
1430        pipeline.attn_v_norm = arch.attn_v_norm;
1431        pipeline.final_softcap = arch.final_logit_softcapping.map(|c| c as f32);
1432        // Cortiq Embryo hierarchical head: cluster matrix → two-level log-probs.
1433        if let Some(ncl) = arch.head_clusters {
1434            let cm = load_f32(model, "lm_head.clusters.weight", ov).map_err(err)?;
1435            if cm.len() != ncl * arch.hidden_size {
1436                return Err(CmfError::Parse(format!(
1437                    "lm_head.clusters.weight: {} != {ncl}×{}",
1438                    cm.len(),
1439                    arch.hidden_size
1440                )));
1441            }
1442            pipeline.head_clusters = Some(std::sync::Arc::new(cm));
1443        }
1444        pipeline.attn_softcap = arch.attn_logit_softcapping.unwrap_or(0.0) as f32;
1445        pipeline.vmf_cfg = vmf_cfg;
1446        pipeline.gdn_cfg = gdn_cfg;
1447        pipeline.kda_cfg = kda_cfg;
1448        if arch.qwen4_exp.is_some() {
1449            let (globals, layers, cfg, state) = crate::qwen4_exp::load(model, &arch)?;
1450            pipeline.qwen4_exp = Some(Box::new((globals, layers, cfg, state)));
1451        }
1452        if let Some(gc) = arch.g3n.as_ref() {
1453            use crate::g3n::{G3nAltUp, G3nGlobals, G3nLaurel, G3nLayer};
1454            anyhow_like(gc.altup_num_inputs == crate::g3n::ALTUP_N).map_err(|_| {
1455                CmfError::Parse(format!(
1456                    "g3n: altup_num_inputs {} != supported {}",
1457                    gc.altup_num_inputs,
1458                    crate::g3n::ALTUP_N
1459                ))
1460            })?;
1461            let t = |name: &str| load_matrix(model, name, force_f32, ov);
1462            let f = |name: &str| load_f32(model, name, ov).map_err(err);
1463            let mut altup_proj = Vec::new();
1464            let mut altup_unembed = Vec::new();
1465            for i in 0..crate::g3n::ALTUP_N - 1 {
1466                altup_proj.push(t(&format!("model.altup_projections.{i}.weight"))?);
1467                altup_unembed.push(t(&format!("model.altup_unembed_projections.{i}.weight"))?);
1468            }
1469            let first_shared = arch.num_layers.saturating_sub(gc.num_kv_shared_layers);
1470            let sliding_of = |li: usize| {
1471                matches!(
1472                    arch.layer_types.get(li),
1473                    Some(cortiq_core::LayerType::SlidingAttention)
1474                )
1475            };
1476            let mut g3n_layers = Vec::with_capacity(arch.num_layers);
1477            for li in 0..arch.num_layers {
1478                let pfx = format!("model.layers.{li}.");
1479                let shared = li >= first_shared && first_shared > 0;
1480                let share_src = if shared {
1481                    let want = sliding_of(li);
1482                    (0..first_shared).rev().find(|&j| sliding_of(j) == want)
1483                } else {
1484                    None
1485                };
1486                g3n_layers.push(G3nLayer {
1487                    altup: G3nAltUp {
1488                        router_norm: f(&format!("{pfx}altup.router_norm.weight"))?,
1489                        modality_router: t(&format!("{pfx}altup.modality_router.weight"))?,
1490                        prediction_coefs: t(&format!("{pfx}altup.prediction_coefs.weight"))?,
1491                        correction_coefs: t(&format!("{pfx}altup.correction_coefs.weight"))?,
1492                        correct_output_scale: f(&format!("{pfx}altup.correct_output_scale"))?,
1493                    },
1494                    laurel: G3nLaurel {
1495                        left: t(&format!("{pfx}laurel.linear_left.weight"))?,
1496                        right: t(&format!("{pfx}laurel.linear_right.weight"))?,
1497                        post_norm: f(&format!("{pfx}laurel.post_laurel_norm.weight"))?,
1498                    },
1499                    input_norm: f(&format!("{pfx}input_layernorm.weight"))?,
1500                    post_attn_norm: f(&format!("{pfx}post_attention_layernorm.weight"))?,
1501                    pre_ffw_norm: f(&format!("{pfx}pre_feedforward_layernorm.weight"))?,
1502                    post_ffw_norm: f(&format!("{pfx}post_feedforward_layernorm.weight"))?,
1503                    wq: t(&format!("{pfx}self_attn.q_proj.weight"))?,
1504                    wk: if shared {
1505                        None
1506                    } else {
1507                        Some(t(&format!("{pfx}self_attn.k_proj.weight"))?)
1508                    },
1509                    wv: if shared {
1510                        None
1511                    } else {
1512                        Some(t(&format!("{pfx}self_attn.v_proj.weight"))?)
1513                    },
1514                    wo: t(&format!("{pfx}self_attn.o_proj.weight"))?,
1515                    q_norm: f(&format!("{pfx}self_attn.q_norm.weight"))?,
1516                    k_norm: if shared {
1517                        None
1518                    } else {
1519                        Some(f(&format!("{pfx}self_attn.k_norm.weight"))?)
1520                    },
1521                    kv_share_src: share_src,
1522                    sliding: sliding_of(li),
1523                    gate: t(&format!("{pfx}mlp.gate_proj.weight"))?,
1524                    up: t(&format!("{pfx}mlp.up_proj.weight"))?,
1525                    down: t(&format!("{pfx}mlp.down_proj.weight"))?,
1526                    sparsity: gc.activation_sparsity.get(li).copied().unwrap_or(0.0),
1527                    ple_gate: t(&format!("{pfx}per_layer_input_gate.weight"))?,
1528                    ple_proj: t(&format!("{pfx}per_layer_projection.weight"))?,
1529                    post_ple_norm: f(&format!("{pfx}post_per_layer_input_norm.weight"))?,
1530                });
1531            }
1532            let hd = arch.head_dim;
1533            let globals = G3nGlobals {
1534                altup_proj,
1535                altup_unembed,
1536                ple_embed: t("model.embed_tokens_per_layer.weight")?,
1537                ple_model_proj: t("model.per_layer_model_projection.weight")?,
1538                ple_norm: f("model.per_layer_projection_norm.weight")?,
1539                ple_vocab: gc.ple_vocab,
1540                ple_dim: gc.ple_dim,
1541                num_layers: arch.num_layers,
1542                hidden: arch.hidden_size,
1543                rms_eps: arch.rms_norm_eps,
1544                inv_freq_local: crate::attention::rope_inv_freq(
1545                    hd,
1546                    arch.rope_local_base_freq.unwrap_or(10_000.0) as f32,
1547                ),
1548                inv_freq_global: crate::attention::rope_inv_freq(hd, arch.rope_theta as f32),
1549                window: arch.sliding_window.unwrap_or(512),
1550            };
1551            pipeline.g3n = Some(Box::new((globals, g3n_layers)));
1552        }
1553        // DeepSeek-V4.1: its own stack, selected by the preserved source
1554        // configuration. The generic layer loop cannot represent shared
1555        // CED/CSA2 state or native Engram tables, so loading failure is
1556        // fatal instead of falling back to an unrelated attention layout.
1557        if arch.arch_name == "deepseek_v41" {
1558            let source = arch.deepseek_v41.as_ref().ok_or_else(|| {
1559                CmfError::Parse("deepseek_v41: missing preserved source config".into())
1560            })?;
1561            let tc = source.get("text_config").unwrap_or(source);
1562            let usize_of = |key: &str, fallback: usize| {
1563                tc.get(key)
1564                    .and_then(|v| v.as_u64())
1565                    .map(|v| v as usize)
1566                    .unwrap_or(fallback)
1567            };
1568            let f32_of = |key: &str, fallback: f32| {
1569                tc.get(key)
1570                    .and_then(|v| v.as_f64())
1571                    .map(|v| v as f32)
1572                    .unwrap_or(fallback)
1573            };
1574            let usize_any = |keys: &[&str], fallback: usize| {
1575                keys.iter()
1576                    .find_map(|key| tc.get(key).and_then(|v| v.as_u64()))
1577                    .map(|v| v as usize)
1578                    .unwrap_or(fallback)
1579            };
1580            let f32_any = |keys: &[&str], fallback: f32| {
1581                keys.iter()
1582                    .find_map(|key| tc.get(key).and_then(|v| v.as_f64()))
1583                    .map(|v| v as f32)
1584                    .unwrap_or(fallback)
1585            };
1586            let bool_of = |key: &str, fallback: bool| {
1587                tc.get(key).and_then(|v| v.as_bool()).unwrap_or(fallback)
1588            };
1589            let array_of = |key: &str| -> Vec<usize> {
1590                tc.get(key)
1591                    .and_then(|v| v.as_array())
1592                    .map(|a| {
1593                        a.iter()
1594                            .filter_map(|v| v.as_u64().map(|x| x as usize))
1595                            .collect()
1596                    })
1597                    .unwrap_or_default()
1598            };
1599            let array_alias = |keys: &[&str]| -> Vec<usize> {
1600                keys.iter()
1601                    .find_map(|key| {
1602                        let values = array_of(key);
1603                        (!values.is_empty()).then_some(values)
1604                    })
1605                    .unwrap_or_default()
1606            };
1607            let dim = usize_any(&["hidden_size", "dim"], arch.hidden_size);
1608            let n_layers = usize_any(&["num_hidden_layers", "n_layers"], arch.num_layers);
1609            let n_heads = usize_any(
1610                &["num_attention_heads", "n_heads"],
1611                arch.num_attention_heads,
1612            );
1613            let head_dim = usize_any(&["head_dim"], arch.head_dim);
1614            let rope_head_dim = usize_any(&["rope_head_dim", "qk_rope_head_dim"], 64.min(head_dim));
1615            let moe_inter = usize_any(
1616                &[
1617                    "moe_intermediate_size",
1618                    "moe_inter_dim",
1619                    "intermediate_size",
1620                ],
1621                arch.intermediate_size,
1622            );
1623            let n_experts = usize_any(
1624                &["n_routed_experts"],
1625                arch.moe.as_ref().map(|m| m.num_experts).unwrap_or(384),
1626            );
1627            let top_k = usize_any(
1628                &["num_experts_per_tok", "n_activated_experts"],
1629                arch.moe.as_ref().map(|m| m.top_k).unwrap_or(6),
1630            );
1631            let mut ratios = array_of("compress_ratios");
1632            if ratios.len() >= n_layers {
1633                ratios.truncate(n_layers);
1634            } else {
1635                ratios = (0..n_layers)
1636                    .map(|li| {
1637                        if (2..20).contains(&li) {
1638                            2
1639                        } else if (20..40).contains(&li) {
1640                            1
1641                        } else {
1642                            0
1643                        }
1644                    })
1645                    .collect();
1646            }
1647            let kv_sources = {
1648                let a = array_alias(&["kv_source_layers", "kv_source_layer_ids"]);
1649                if a.is_empty() { vec![2, 8, 14, 20] } else { a }
1650            };
1651            let index_sources = {
1652                let a = array_alias(&["index_source_layers", "index_source_layer_ids"]);
1653                if a.is_empty() {
1654                    vec![2, 8, 14, 20, 24, 28, 32, 36]
1655                } else {
1656                    a
1657                }
1658            };
1659            let engram_layers = array_of("engram_layer_ids");
1660            let engram_embeddings = array_of("engram_num_embeddings");
1661            let cfg = crate::dsv41::Dsv41Cfg {
1662                dim,
1663                n_heads,
1664                head_dim,
1665                rope_head_dim: rope_head_dim.min(head_dim) & !1,
1666                q_lora_rank: usize_of("q_lora_rank", 1280),
1667                o_lora_rank: usize_of("o_lora_rank", 1024),
1668                o_groups: usize_of("o_groups", 8),
1669                hc_mult: usize_of("hc_mult", 4),
1670                hc_sinkhorn_iters: usize_of("hc_sinkhorn_iters", 20),
1671                hc_eps: f32_of("hc_eps", 1e-6),
1672                norm_eps: f32_any(&["norm_eps", "rms_norm_eps"], arch.rms_norm_eps as f32),
1673                n_routed_experts: n_experts,
1674                top_k,
1675                moe_inter,
1676                gate_temp: f32_of("gate_temp", 1.0),
1677                norm_topk_prob: bool_of("norm_topk_prob", true),
1678                route_scale: f32_any(
1679                    &["routed_scaling_factor", "route_scale"],
1680                    arch.moe
1681                        .as_ref()
1682                        .and_then(|m| m.routed_scaling_factor)
1683                        .unwrap_or(1.5),
1684                ),
1685                swiglu_limit: f32_of("swiglu_limit", 10.0),
1686                window: usize_any(
1687                    &["window_size", "sliding_window"],
1688                    arch.sliding_window.unwrap_or(128),
1689                ),
1690                rope_theta: f32_any(&["rope_theta"], arch.rope_theta as f32),
1691                compress_rope_theta: f32_any(&["compress_rope_theta"], 160_000.0),
1692                rope_factor: f32_any(
1693                    &["rope_factor"],
1694                    tc.get("rope_scaling")
1695                        .and_then(|v| v.get("factor"))
1696                        .and_then(|v| v.as_f64())
1697                        .map(|v| v as f32)
1698                        .unwrap_or(16.0),
1699                ),
1700                original_seq_len: usize_any(
1701                    &["original_seq_len", "original_max_position_embeddings"],
1702                    tc.get("rope_scaling")
1703                        .and_then(|v| v.get("original_max_position_embeddings"))
1704                        .and_then(|v| v.as_u64())
1705                        .map(|v| v as usize)
1706                        .unwrap_or(65_536),
1707                ),
1708                beta_fast: f32_any(
1709                    &["beta_fast"],
1710                    tc.get("rope_scaling")
1711                        .and_then(|v| v.get("beta_fast"))
1712                        .and_then(|v| v.as_f64())
1713                        .map(|v| v as f32)
1714                        .unwrap_or(32.0),
1715                ),
1716                beta_slow: f32_any(
1717                    &["beta_slow"],
1718                    tc.get("rope_scaling")
1719                        .and_then(|v| v.get("beta_slow"))
1720                        .and_then(|v| v.as_f64())
1721                        .map(|v| v as f32)
1722                        .unwrap_or(1.0),
1723                ),
1724                index_heads: usize_any(&["index_n_heads", "indexer_n_heads"], 32),
1725                index_head_dim: usize_any(&["index_head_dim", "indexer_head_dim"], 128),
1726                index_topk: usize_any(&["index_topk", "indexer_topk"], 512),
1727                candidate_source: usize_any(
1728                    &["candidate_source_layer", "candidate_source_layer_id"],
1729                    20,
1730                ),
1731                candidate_topk_blocks: usize_any(&["candidate_topk_blocks"], 2048),
1732                candidate_block_size: usize_any(&["candidate_block_size"], 8),
1733                kv_sources,
1734                index_sources,
1735                compress_ratios: ratios,
1736                engram_layers,
1737                engram_vocab: usize_any(&["engram_vocab_size"], 16_000_000),
1738                engram_embeddings,
1739                engram_max_ngram: usize_any(&["engram_max_ngram_size"], 4),
1740                engram_heads: usize_any(&["engram_n_heads"], 8),
1741                engram_head_dim: usize_any(&["engram_head_dim"], 256),
1742                engram_compressed_vocab: usize_any(&["engram_compressed_vocab_size"], 99_092),
1743                engram_pad_id: usize_any(&["engram_pad_id", "engram_pad_token_id"], 2),
1744                vocab: usize_any(&["vocab_size"], arch.vocab_size),
1745            };
1746            let token_map = crate::dsv41::token_map_from_model(model, cfg.vocab);
1747            let (g, dl, hash) = crate::dsv41::load(model, &cfg, n_layers, token_map)
1748                .map_err(|e| CmfError::Parse(format!("deepseek_v41: {e}")))?;
1749            let st = crate::dsv41::Dsv41State::new(&cfg, hash);
1750            // Vision tensors are optional in text-only exports, but when
1751            // present they stay mmap-backed through the dedicated tower.
1752            // Do not make a text-only CMF fail merely because its source
1753            // config still carries the multimodal section.
1754            if let Ok(vision_cfg) = crate::dsv41_vision::VisionConfig::from_source(source) {
1755                if vision_cfg.vision_enabled()
1756                    && model.tensor("vision.patch_embed.proj.weight").is_some()
1757                {
1758                    pipeline.dsv41_vision = Some(
1759                        crate::dsv41_vision::VisionModel::from_model(model, vision_cfg)
1760                            .map_err(|e| CmfError::Parse(format!("deepseek_v41 vision: {e}")))?,
1761                    );
1762                }
1763            }
1764            tracing::info!(
1765                "deepseek_v41: loaded {} layers, {} KV sources, {} index sources, {} Engram layers; experts remain mmap-backed",
1766                dl.len(),
1767                cfg.kv_sources.len(),
1768                cfg.index_sources.len(),
1769                cfg.engram_layers.len()
1770            );
1771            pipeline.dsv41 = Some(Box::new((g, dl, cfg, st)));
1772        }
1773        // DeepSeek-V4: its own stack, selected by the arch name the
1774        // converter wrote. Loading failure is fatal rather than a silent
1775        // fallback — the generic loop cannot represent this model at all,
1776        // so a fallback would decode noise.
1777        if arch.arch_name == "deepseek_v4" {
1778            let moe = arch
1779                .moe
1780                .as_ref()
1781                .ok_or_else(|| CmfError::Parse("deepseek_v4: no moe config".into()))?;
1782            let cfg = crate::dsv4::Dsv4Cfg {
1783                dim: arch.hidden_size,
1784                n_heads: arch.num_attention_heads,
1785                head_dim: arch.head_dim,
1786                // The rope tail: `partial_rotary_factor` carries it when the
1787                // conversion recorded it (rd/head_dim), which the tensors
1788                // cannot reveal. Files converted before that carry 1.0,
1789                // meaning "unset" here rather than "rotate everything" —
1790                // for those the release's 64 stands in, which is what they
1791                // were converted from.
1792                rope_head_dim: if arch.partial_rotary_factor < 1.0 {
1793                    (((arch.head_dim as f32 * arch.partial_rotary_factor) as usize) & !1)
1794                        .clamp(2, arch.head_dim)
1795                } else {
1796                    64.min(arch.head_dim)
1797                },
1798                // The LoRA ranks and the group count ARE visible in the
1799                // weights, and reading them there means a re-tuned
1800                // checkpoint loads without touching this code.
1801                q_lora_rank: 0,
1802                o_lora_rank: 0,
1803                // Derived below from wo_a's shape — the attention output is
1804                // n_heads*head_dim wide and wo_a takes one group of it per
1805                // row block, so groups = width / wo_a.cols(). A pinned 8 is
1806                // right for the release and wrong for anything else, which
1807                // is exactly what made a toy checkpoint impossible to
1808                // compare against the reference.
1809                o_groups: 8,
1810                hc_mult: 4,
1811                hc_sinkhorn_iters: 20,
1812                hc_eps: 1e-6,
1813                norm_eps: arch.rms_norm_eps as f32,
1814                n_routed_experts: moe.num_experts,
1815                top_k: moe.top_k,
1816                moe_inter: moe.moe_intermediate_size,
1817                route_scale: moe.routed_scaling_factor.unwrap_or(1.0),
1818                // config.json's `swiglu_limit`, which the header has no
1819                // field for. The release ships 10.0; a checkpoint that
1820                // retunes it would need this read from the config, so it
1821                // sits next to the other pinned constants rather than
1822                // hiding inside the expert.
1823                swiglu_limit: 10.0,
1824                window: arch.sliding_window.unwrap_or(128),
1825                index_topk: 512,
1826                vocab: arch.vocab_size,
1827            };
1828            let (g, dl) = crate::dsv4::load(model, &cfg, arch.num_layers)
1829                .map_err(|e| CmfError::Parse(format!("deepseek_v4: {e}")))?;
1830            // Read the ranks off the weights that define them: wq_a's
1831            // rows ARE q_lora_rank, and wo_b's columns are groups x
1832            // o_lora_rank. A header field could disagree with the file;
1833            // these cannot.
1834            let mut cfg = cfg;
1835            if let Some(l0) = dl.first() {
1836                cfg.q_lora_rank = l0.wq_a.rows();
1837                let attn_width = arch.num_attention_heads * arch.head_dim;
1838                if l0.wo_a.cols() > 0 && attn_width % l0.wo_a.cols() == 0 {
1839                    cfg.o_groups = (attn_width / l0.wo_a.cols()).max(1);
1840                }
1841                cfg.o_lora_rank = l0.wo_b.cols() / cfg.o_groups.max(1);
1842                cfg.hc_mult = (l0.hc_attn_fn.len() / l0.hc_attn_base.len().max(1)) / cfg.dim.max(1);
1843                if cfg.hc_mult == 0 {
1844                    cfg.hc_mult = 4;
1845                }
1846            }
1847            // RoPE rides only the last `rope_head_dim` of each head, and the
1848            // reference builds its frequencies over THAT width — not over
1849            // head_dim, which is 512 here. The generic path above sized them
1850            // by head_dim, giving 1/base^(2i/512) where 1/base^(2i/64) is
1851            // wanted: every position rotated by the wrong angle.
1852            //
1853            // YaRN is applied unconditionally by the reference (its guard is
1854            // `original_seq_len > 0`, not the sequence length), so it belongs
1855            // in these frequencies too. Older configs spell the key `type`
1856            // rather than `rope_type`; when the header carries no profile the
1857            // release's own numbers stand in, which is better than silently
1858            // decoding with unscaled frequencies.
1859            let (yf, yo, ybf, ybs) = match &arch.yarn {
1860                Some(y) => (
1861                    y.factor,
1862                    y.original_max_position_embeddings,
1863                    y.beta_fast,
1864                    y.beta_slow,
1865                ),
1866                None => {
1867                    tracing::warn!(
1868                        "deepseek_v4: the header carries no YaRN profile — \
1869                         falling back to the release's (factor 16, original \
1870                         65536, beta 32/1). Re-converting with a build that \
1871                         reads rope_scaling.type would make this exact."
1872                    );
1873                    (16.0, 65536, 32.0, 1.0)
1874                }
1875            };
1876            pipeline.inv_freq = std::sync::Arc::new(crate::attention::yarn_inv_freq(
1877                cfg.rope_head_dim,
1878                arch.rope_theta as f32,
1879                yf,
1880                yo,
1881                ybf,
1882                ybs,
1883            ));
1884            // Keep the working set resident. Everything but the routed
1885            // experts is touched by every token, and of the experts only the
1886            // ones the task actually routes to — the page cache cannot know
1887            // that and evicts by age instead.
1888            if let Ok(stats) = std::env::var("CMF_MOE_PIN") {
1889                let cover = std::env::var("CMF_MOE_PIN_COVER")
1890                    .ok()
1891                    .and_then(|v| v.parse::<f64>().ok())
1892                    .filter(|&c| c > 0.0 && c <= 1.0)
1893                    .unwrap_or(0.95);
1894                let hot = crate::pin::hot_experts(&stats, cover);
1895                let mut names: Vec<String> = Vec::new();
1896                for e in &model.tensors {
1897                    let is_expert = e.name.contains(".mlp.experts.");
1898                    if !is_expert {
1899                        names.push(e.name.clone()); // skeleton: always hot
1900                    }
1901                }
1902                let mut kept_experts = 0usize;
1903                if let Some(hot) = &hot {
1904                    for (li, experts) in hot {
1905                        for e in experts {
1906                            for w in ["gate_proj", "up_proj", "down_proj"] {
1907                                names.push(format!("model.layers.{li}.mlp.experts.{e}.{w}.weight"));
1908                            }
1909                            kept_experts += 1;
1910                        }
1911                    }
1912                }
1913                let r = crate::pin::pin_tensors(model, &names);
1914                tracing::info!(
1915                    "закреплено {:.1} ГБ ({} тензоров, горячих экспертов {kept_experts},                      покрытие {cover}); лимит {}",
1916                    r.bytes as f64 / 1e9,
1917                    r.tensors,
1918                    r.limit
1919                        .map(|l| format!("{:.1} ГБ", l as f64 / 1e9))
1920                        .unwrap_or_else(|| "неизвестен".into())
1921                );
1922                if r.skipped > 0 {
1923                    tracing::warn!("не закреплено тензоров: {}", r.skipped);
1924                }
1925            }
1926            let st = crate::dsv4::Dsv4State::new(arch.num_layers);
1927            // The speculation stack, if the file carries one. Reading it is
1928            // metadata only — the expert weights stay in the mapping until a
1929            // draft actually runs — so it costs nothing to know it is there.
1930            let depth = std::env::var("CMF_DSV4_MTP_DEPTH")
1931                .ok()
1932                .and_then(|v| v.parse::<usize>().ok())
1933                .unwrap_or(3);
1934            pipeline.dsv4_mtp = crate::dsv4::load_mtp(model, &cfg, depth);
1935            // Before any trunk pack is built: leave the draft its VRAM.
1936            crate::dsv4::dspark_reserve_note(&pipeline.dsv4_mtp, &cfg, &dl);
1937            pipeline.dsv4 = Some(Box::new((g, dl, cfg, st)));
1938        }
1939        pipeline.short_conv_cfg = short_conv_cfg;
1940        pipeline.mtp = mtp;
1941        pipeline.install_dynamic_routing(model, false);
1942        // Record the load-time overlay so a later set_active_skill(None)
1943        // correctly reverts it (the union-diff assumes dyn_active mirrors
1944        // the live overlay). Blend loads have no single index to revert.
1945        match ov {
1946            Overlay::One(sid) => {
1947                pipeline.dyn_active = model.header.skills.iter().position(|s| &s.id == sid);
1948            }
1949            Overlay::Blend(_) => pipeline.dyn_blend_loaded = true,
1950            Overlay::None => {}
1951        }
1952        // B1: apply the measured confidence-calibration temperature, if the
1953        // file carries one (softmax(logits / T) for reported confidence).
1954        if let Some(c) = &model.header.calibration {
1955            pipeline.set_calib_temp(c.temperature);
1956        }
1957        // O(1) Nyström attention (runtime-level, no format change):
1958        // env CMF_O1 decides; unset falls through to the converter hint
1959        // in header.provenance.o1_attn (`cortiq convert --o1`), and
1960        // CMF_O1=off force-disables even the hint. CLI flags override
1961        // later via set_o1().
1962        let o1 = match crate::nystrom::o1_from_env() {
1963            crate::nystrom::O1Env::Off => None,
1964            crate::nystrom::O1Env::On(cfg) => Some(cfg),
1965            crate::nystrom::O1Env::Unset => model
1966                .header
1967                .provenance
1968                .as_ref()
1969                .and_then(|p| p.get("o1_attn"))
1970                .and_then(crate::nystrom::O1Cfg::from_json),
1971        };
1972        if o1.is_some() {
1973            if pipeline.attn_softcap > 0.0 {
1974                return Err(CmfError::Parse(
1975                    "--o1 with attention-logit soft-capping (Gemma-2) is not supported: \
1976                     the streaming operator has no capped-score form"
1977                        .into(),
1978                ));
1979            }
1980            pipeline.set_o1(o1);
1981        }
1982        Ok(pipeline)
1983    }
1984
1985    /// Record per-skill dynamic-routing metadata: which FFN layers each
1986    /// skill actually replaces (derived from the tensors present, not
1987    /// the meta `layers` field), and whether the skill is eligible for
1988    /// cheap dynamic switching (FFN-only). Called once at load.
1989    pub(crate) fn install_dynamic_routing(&mut self, model: &Arc<CmfModel>, force_f32: bool) {
1990        self.model = Some(model.clone());
1991        self.dyn_force_f32 = force_f32;
1992        let mut per_skill = Vec::with_capacity(model.header.skills.len());
1993        for sk in &model.header.skills {
1994            let mut ffn_layers = std::collections::BTreeSet::new();
1995            let mut non_ffn = false;
1996            let prefix = format!("skill.{}.", sk.id);
1997            for t in model.skill_tensors(&sk.id) {
1998                let rel = &t.name[prefix.len()..]; // e.g. model.layers.20.mlp.down_proj.weight
1999                let toks: Vec<&str> = rel.split('.').collect();
2000                if toks.len() >= 5 && toks[0] == "model" && toks[1] == "layers" && toks[3] == "mlp"
2001                {
2002                    if let Ok(li) = toks[2].parse::<usize>() {
2003                        ffn_layers.insert(li);
2004                        continue;
2005                    }
2006                }
2007                non_ffn = true; // replaces attention / embed / lm_head
2008            }
2009            if non_ffn {
2010                tracing::warn!(
2011                    "skill '{}' replaces non-FFN tensors — excluded from dynamic \
2012                     routing (static overlay still works)",
2013                    sk.id
2014                );
2015                per_skill.push(None);
2016            } else {
2017                per_skill.push(Some(ffn_layers.into_iter().collect::<Vec<_>>()));
2018            }
2019        }
2020        self.dyn_skill_layers = per_skill;
2021    }
2022
2023    /// Switch the overlaid skill for subsequent forwards (dynamic
2024    /// routing). `idx` = index into model.header.skills; None = backbone.
2025    /// Rebuilds the FFN of the union of the old and new skill's touched
2026    /// layers with the new overlay — tensor-source indirection made
2027    /// dynamic. Cheap: Mapped tensors are re-resolved mmap pointers.
2028    /// Result is bit-identical to loading the pipeline with that skill.
2029    pub fn set_active_skill(&mut self, idx: Option<usize>) -> Result<(), CmfError> {
2030        // Overlay swap changes weights → every cached K/V is stale.
2031        // The wgpu graph owns a parallel recurrent/KV mirror keyed by the
2032        // pipeline id.  Overlay swaps are sequence boundaries too; the shared
2033        // reset clears it before the next token so dynamic routing cannot
2034        // read state produced with the prior skill.
2035        self.reset_session();
2036        if self.dyn_active == idx {
2037            return Ok(());
2038        }
2039        let model = self.model.clone().ok_or_else(|| {
2040            CmfError::Parse("dynamic routing needs a model-backed pipeline".into())
2041        })?;
2042        let mut union: std::collections::BTreeSet<usize> = std::collections::BTreeSet::new();
2043        if let Some(old) = self.dyn_active {
2044            if let Some(Some(ls)) = self.dyn_skill_layers.get(old) {
2045                union.extend(ls.iter().copied());
2046            }
2047        }
2048        let new_id: Option<String> = match idx {
2049            Some(n) => match self.dyn_skill_layers.get(n) {
2050                Some(Some(ls)) => {
2051                    union.extend(ls.iter().copied());
2052                    Some(model.header.skills[n].id.clone())
2053                }
2054                _ => {
2055                    return Err(CmfError::Parse(format!(
2056                        "skill index {n} not dynamic-eligible"
2057                    )));
2058                }
2059            },
2060            None => None,
2061        };
2062        let ov = match &new_id {
2063            Some(s) => Overlay::One(s),
2064            None => Overlay::None,
2065        };
2066        let arch = model.arch();
2067        for li in union {
2068            self.weights.layers[li].ffn =
2069                build_layer_ffn(&model, arch, li, self.dyn_force_f32, &ov)?;
2070        }
2071        self.dyn_active = idx;
2072        Ok(())
2073    }
2074}