Skip to main content

memra_engine/
tp.rs

1//! Tensor-parallel correctness runtime.
2//!
3//! This module is deliberately narrower than the serving runtime. It executes real rank-local
4//! E4M3 projections on distinct CUDA devices. Deterministic host-staged collectives remain the
5//! default exactness reference; an opt-in native-P2P path must reproduce the same canonical
6//! checkpoint-block program before it can advance. Neither path is product-throughput evidence.
7
8use crate::Engine;
9use crate::mmq_ffi::{DeviceExpertCsr, ExpertCsr, Fp8GroupedWorkspace};
10use crate::parallel::{PRODUCT_MAX_CARDS, STEP37_TRUNK_LAYERS};
11use cudarc::driver::{CudaEvent, CudaSlice, DeviceSlice};
12use std::ops::Range;
13
14/// Previous gate output per (rank, t), so the determ probe can report the SHAPE of a divergence
15/// (dense-ULP vs sparse-huge) and not merely that a checksum moved. Probe-only state.
16static DETERM_PREV: std::sync::OnceLock<
17    std::sync::Mutex<std::collections::HashMap<(usize, usize), Vec<f32>>>,
18> = std::sync::OnceLock::new();
19
20const FP8_BLOCK: usize = 128;
21const NATIVE_P2P_PROBE_WORDS: &[usize] = &[4096, 16_384, 262_144, 16_777_216];
22const STEP_GROUPED_FP8_EXPERTS: usize = 288;
23const STEP_GROUPED_FP8_TOP_K: usize = 8;
24const STEP_GROUPED_FP8_WIDTH: usize = 1280;
25
26fn validate_step_expert_activation_limit(limit: Option<f32>) -> Result<(), String> {
27    if let Some(limit) = limit {
28        if !limit.is_finite() || limit <= 0.0 {
29            return Err(format!(
30                "Step routed-expert activation limit must be positive and finite, got {limit}"
31            ));
32        }
33    }
34    Ok(())
35}
36
37/// Host-canonical Step routed-expert SwiGLU operation.
38///
39/// Step's final routed layers clamp the linear arm symmetrically and the SiLU arm only above.
40/// Keeping this scalar order explicit also defines the device-host-exact CUDA gate.
41/// Raw stream-ordered device copy for capture-safe cross-context seams (cudarc's slice-use
42/// tracking creates capture-illegal dependencies there). Pointers must be pre-cached with
43/// their owners' streams; bytes flow identically to the tracked copy.
44/// MEMRA_OPROJ_DIRECT=1 (o-proj direct join, default OFF until gated): peer ranks write
45/// their fused O partial OVER P2P into a root-resident buffer (UVA kernel stores), and the
46/// model engine adds the two partials itself — the root stream leaves the join entirely
47/// (no peer pull copy, no root add, no second event hop, no final 16KB ownership copy).
48/// Reduction order and kernel programs are unchanged, so the row is BIT-IDENTICAL.
49/// MEMRA_MOE_DIRECT=1 (moe direct join, default OFF until gated): the o-proj direct-join
50/// recipe on the expert combine — peer ranks' accumulators live root-side (the axpy twin
51/// register-accumulates and stores ONCE, so the P2P cost is a single 16KB store pass), and
52/// the model engine adds the two shard rows itself. Operand order matches root's add:
53/// BIT-IDENTICAL.
54/// MEMRA_ROUTES_PRESTAGE=1 (default OFF until gated): stage the shared layer input to
55/// every rank and quantize it BEFORE the router runs — neither depends on the selection,
56/// so the rank streams' pull+quantize overlaps dev0's router gemv+topk instead of chaining
57/// behind it (the router->quantize and axpy->add gap edges). Same copies, same quantize
58/// kernel, same operands: BIT-IDENTICAL.
59pub(crate) fn routes_prestage_on() -> bool {
60    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
61    *ON.get_or_init(|| std::env::var("MEMRA_ROUTES_PRESTAGE").as_deref() == Ok("1"))
62}
63
64/// MEMRA_FENCE_MEMOPS=1 (default OFF until gated): the moe direct join's two event
65/// fences become cuStreamWriteValue32/cuStreamWaitValue32 doorbells — hardware stream
66/// memops with lower signal->wake latency than cross-device cuStreamWaitEvent. Ordering:
67/// PCIe posted writes from one device arrive in order, so rank1's accumulator stores are
68/// visible before its flag write lands; e's GEQ wait then covers them. Falls back to
69/// events when the device rejects stream memops. Scheduling-only: BIT-IDENTICAL values.
70/// MEMRA_LEN_MIRROR_LAZY=1 (default OFF until gated): skip redundant per-layer 4B len
71/// htods — the local device mirror is unread in TP decode, and under FUSE_ROPE_APPEND the
72/// fused append's atomicInc owns the rank counters. Every one of those tiny copies is a
73/// compute->copy engine turnaround in the middle of the layer stream.
74/// MEMRA_RANK0_MERGE=1 (default OFF until gated): same-device rank0 rides e's stream via
75/// the runtime redirect — see decode_step_h.
76/// MEMRA_OPROJ_TAIL=1 (default OFF until gated): the o-proj direct-join add is DEFERRED —
77/// the finish arm keeps its waits, stores the two partial pointers here, and the residual
78/// add_rms_norm consumer composes mixed = a0+a1 in-register (join_add_rms_norm, verbatim
79/// program: BIT-IDENTICAL). The returned `mixed` buffer is UNWRITTEN in this mode; its
80/// only live consumer is the residual_norm_ffn seam, which takes the handoff.
81pub(crate) fn oproj_tail_on() -> bool {
82    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
83    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_TAIL").as_deref() == Ok("1"))
84}
85thread_local! {
86    static OPROJ_TAIL_PENDING: std::cell::Cell<Option<(u64, u64)>> =
87        const { std::cell::Cell::new(None) };
88}
89thread_local! {
90    /// The deferral is legal ONLY under callers whose walk flows into
91    /// residual_norm_ffn (decode_step_h / decode_step_chain arm this) — the verify
92    /// prefill reaches the same finish and would consume unwritten `mixed` otherwise
93    /// (M2-MISMATCH receipt: prefill argmax corrupted while decode stayed exact).
94    static OPROJ_TAIL_ELIGIBLE: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
95}
96/// RAII eligibility scope for the o-proj tail deferral.
97pub(crate) struct OprojTailScope(());
98pub(crate) fn oproj_tail_scope() -> OprojTailScope {
99    OPROJ_TAIL_ELIGIBLE.with(|c| c.set(true));
100    OprojTailScope(())
101}
102impl Drop for OprojTailScope {
103    fn drop(&mut self) {
104        OPROJ_TAIL_ELIGIBLE.with(|c| c.set(false));
105        // A leftover un-consumed handoff must never leak across calls.
106        OPROJ_TAIL_PENDING.with(|c| c.set(None));
107    }
108}
109thread_local! {
110    /// T-COLUMN verify select: the verify driver sets the column before each per-column
111    /// attention call; decode_v2_input_qkv takes it (once) and selects from the slabs.
112    static VERIFY_TCOL: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
113}
114pub(crate) fn set_verify_tcol(c: Option<usize>) {
115    VERIFY_TCOL.with(|x| x.set(c));
116}
117pub(crate) fn take_verify_tcol() -> Option<usize> {
118    VERIFY_TCOL.with(|x| x.take())
119}
120
121/// MEMRA_TCOL_OPROJ=1 (spec verify): defer each column's o_proj out of the per-column
122/// walk — the finish seam stashes the column's `gated` rows instead of running the
123/// per-column finish choreography (rank events, P2P join, engine handoff), and one
124/// weight-amortized b4_tcol per rank + one elementwise join produce every column's
125/// `mixed` afterwards. Bit-exact per column: the tcol kernel is the t=1 b4 program per
126/// column, and the slab join adds the same operand values elementwise.
127pub(crate) fn tcol_oproj_on() -> bool {
128    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
129    *ON.get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ").as_deref() == Ok("1"))
130}
131thread_local! {
132    /// The verify driver arms the column before each per-column attention call; the
133    /// finish seam takes it (once). Stashed=true reports the defer actually happened
134    /// (the seam falls back to the normal finish when the config is ineligible).
135    static TCOL_OPROJ_DEFER: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
136    static TCOL_OPROJ_STASHED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
137}
138pub(crate) fn set_tcol_oproj_defer(c: Option<usize>) {
139    TCOL_OPROJ_DEFER.with(|x| x.set(c));
140}
141pub(crate) fn take_tcol_oproj_defer() -> Option<usize> {
142    TCOL_OPROJ_DEFER.with(|x| x.take())
143}
144pub(crate) fn set_tcol_oproj_stashed() {
145    TCOL_OPROJ_STASHED.with(|x| x.set(true));
146}
147pub(crate) fn take_tcol_oproj_stashed() -> bool {
148    TCOL_OPROJ_STASHED.with(|x| x.replace(false))
149}
150
151pub(crate) fn oproj_tail_eligible() -> bool {
152    OPROJ_TAIL_ELIGIBLE.with(|c| c.get())
153}
154pub(crate) fn take_oproj_tail() -> Option<(u64, u64)> {
155    OPROJ_TAIL_PENDING.with(|c| c.take())
156}
157pub(crate) fn set_oproj_tail(v: (u64, u64)) {
158    OPROJ_TAIL_PENDING.with(|c| c.set(Some(v)));
159}
160
161pub(crate) fn rank0_merge_on() -> bool {
162    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
163    *ON.get_or_init(|| std::env::var("MEMRA_RANK0_MERGE").as_deref() == Ok("1"))
164}
165
166pub(crate) fn len_mirror_lazy_on() -> bool {
167    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
168    *ON.get_or_init(|| std::env::var("MEMRA_LEN_MIRROR_LAZY").as_deref() == Ok("1"))
169}
170
171pub(crate) fn fence_memops_on() -> bool {
172    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
173    *ON.get_or_init(|| std::env::var("MEMRA_FENCE_MEMOPS").as_deref() == Ok("1"))
174}
175
176pub(crate) fn moe_direct_on() -> bool {
177    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
178    *ON.get_or_init(|| std::env::var("MEMRA_MOE_DIRECT").as_deref() == Ok("1"))
179}
180
181/// MEMRA_SEL_MIRROR=1: the per-rank routed-selection pull runs as ONE `moe_sel_w_mirror`
182/// launch instead of two 32-byte D2D copies, and when every consuming rank shares e's device
183/// the intermediate e-context staging pair is skipped entirely (the caller's sel/route_w rows
184/// are process-persistent, so the ranks read them directly). Bit-identical: same bytes, one
185/// fewer hop. Refused under the graph door, whose captured copies need the fixed staging
186/// addresses. Default OFF until receipted.
187/// MEMRA_FENCE_RANK1=1: the peer rank rings a doorbell in ROOT memory with a kernel store
188/// (`memra_ring_flag`) and the model engine waits it with a SAME-DEVICE stream memop, instead
189/// of waiting a cross-device event. Completes the half the memops receipt left open (peer
190/// memops are rejected; peer kernel stores are the direct-join mechanism). Ordering only —
191/// values are untouched. Requires MEMRA_FENCE_MEMOPS=1 (it owns the flag allocation).
192pub(crate) fn fence_rank1_on() -> bool {
193    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
194    *ON.get_or_init(|| std::env::var("MEMRA_FENCE_RANK1").as_deref() == Ok("1"))
195}
196
197/// MEMRA_SPEC_FA2=1 (the DSpark verify lesson): the T=2 verify walk defers each column's
198/// ATTENTION CORE — the dcw arm appends the column's K/V and stashes its post-rope q and
199/// gate rows, then ONE fa_decode_dcw2 per rank walks the KV stream once for both columns
200/// (per-row causal bounds; bit-identical per row under the equal-partition guard), the
201/// per-row combine writes both gated rows, and the o_proj join runs on the TCOL slabs.
202/// ROW-TABLE RESTAGE (`MEMRA_ROWS_TAB_RESTAGE`, DEFAULT ON since this lane).
203///
204/// ON: `decode_v2_rope_fa_rows` builds the 6-word-per-row pointer table from the caller's
205/// freshly-read live cache pointers and stages it into a persistent per-rank slab before
206/// every launch. OFF (`=0`): the retired process-lifetime `rows_tabs` memo, keyed by a hash
207/// of (k pointer, base pointer, layer, t) that could not see the V or LEN pointers the
208/// entry also carried, and that nothing invalidated when a session's KV cache was dropped.
209///
210/// Default ON because the OFF arm is a proven use-after-free, not a slower correct path:
211/// on step37-flash with MEMRA_FUSE_ROPE_APPEND=1 it made speculative decoding unservable
212/// (whole non-finite verify rows, then CUDA_ERROR_ILLEGAL_ADDRESS). ON is value-neutral on
213/// every fresh lookup by construction: identical bytes reach the same kernels. Rollback
214/// seam: `MEMRA_ROWS_TAB_RESTAGE=0`.
215/// The 6-word-per-row launch table `{k, v, len, base, ctr, back}` the fused rope/append/fa
216/// kernels dereference. Pure so it can be tested: the words come from the caller's live
217/// per-row `[k, v, len, base]` pointers, `ctr` is this rank's counter slab (one shared cell
218/// for same-session rows, one cell per row otherwise) and `back` is the same-session causal
219/// step-back `t-1-r` (0 across sessions, where each row owns its own len).
220pub(crate) fn rows_tab_host(
221    parts_rank: &[[u64; 4]],
222    ctr_base: u64,
223    same_session: bool,
224    t: usize,
225) -> Vec<u64> {
226    let mut host = Vec::with_capacity(t * 6);
227    for (r, parts) in parts_rank.iter().enumerate().take(t) {
228        host.extend_from_slice(&[
229            parts[0],
230            parts[1],
231            parts[2],
232            parts[3],
233            if same_session {
234                ctr_base
235            } else {
236                ctr_base + (r as u64) * 4
237            },
238            if same_session {
239                (t - 1 - r) as u64
240            } else {
241                0u64
242            },
243        ]);
244    }
245    host
246}
247
248/// The RETIRED memo key, kept ONLY so a test can assert what it cannot see. Both historical
249/// call sites hashed a SUBSET of the pointers the table carries; this reproduces the verify
250/// site's formula verbatim.
251#[cfg(test)]
252pub(crate) fn retired_rows_tab_key(kp: u64, bp: u64, il: usize, t: usize) -> u64 {
253    kp.rotate_left(17)
254        .wrapping_add(bp)
255        .wrapping_add((il as u64) << 32)
256        .wrapping_add(t as u64)
257        .wrapping_add(1 << 63)
258}
259
260pub(crate) fn rows_tab_restage_on() -> bool {
261    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
262    *ON.get_or_init(|| std::env::var("MEMRA_ROWS_TAB_RESTAGE").as_deref() != Ok("0"))
263}
264
265/// STALE-HIT RECEIPT (`MEMRA_ROWS_TAB_STALE_SCAN`, DEFAULT OFF, diagnostic only).
266///
267/// Keeps a HOST shadow of the last table staged under each retired memo key and prints one
268/// line whenever the key repeats with different contents, naming the words that moved. It
269/// costs a host hash lookup and a small clone per rank per layer per verify round, so it is
270/// off in serving. `[rows-tab] engaged=` on the counter proves the path executes at all,
271/// which is what separates "the memo was innocent" from "the memo never ran".
272/// Rollback seam: unset it (or `=0`).
273pub(crate) fn rows_tab_stale_scan() -> bool {
274    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
275    *ON.get_or_init(|| std::env::var("MEMRA_ROWS_TAB_STALE_SCAN").as_deref() == Ok("1"))
276}
277
278pub(crate) static ROWS_TAB_ENGAGED: std::sync::atomic::AtomicU64 =
279    std::sync::atomic::AtomicU64::new(0);
280pub(crate) static ROWS_TAB_STALE: std::sync::atomic::AtomicU64 =
281    std::sync::atomic::AtomicU64::new(0);
282
283pub(crate) fn spec_fa2_on() -> bool {
284    static ENV: std::sync::OnceLock<Option<bool>> = std::sync::OnceLock::new();
285    crate::step37_door(&ENV, "MEMRA_SPEC_FA2")
286}
287thread_local! {
288    /// The verify driver arms the column before each per-column attention call; the dcw
289    /// arm takes it (once) and stashes q/gate instead of running fa+finish.
290    static SPEC_FA2_DEFER: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
291    static SPEC_FA2_STASHED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
292}
293pub(crate) fn set_spec_fa2_defer(c: Option<usize>) {
294    SPEC_FA2_DEFER.with(|x| x.set(c));
295}
296pub(crate) fn take_spec_fa2_defer() -> Option<usize> {
297    SPEC_FA2_DEFER.with(|x| x.take())
298}
299pub(crate) fn set_spec_fa2_stashed() {
300    SPEC_FA2_STASHED.with(|x| x.set(true));
301}
302pub(crate) fn take_spec_fa2_stashed() -> bool {
303    SPEC_FA2_STASHED.with(|x| x.replace(false))
304}
305
306pub(crate) fn sel_mirror_on() -> bool {
307    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
308    *ON.get_or_init(|| std::env::var("MEMRA_SEL_MIRROR").as_deref() == Ok("1"))
309}
310
311/// MEMRA_STEP_NVFP4_EP2=1: whole-expert (expert-parallel) NVFP4 banks at 2 ranks — expert e
312/// lives ENTIRE on rank (e & 1) at bank slot (e >> 1), replacing the TP column/row shards
313/// (same total VRAM; both sets cannot coexist). Decode rides owner-guarded full-width
314/// sweeps with per-rank slot-ordered partial sums; the cross-rank join is unchanged.
315/// NUMERIC-CLASS door (the slot chain regroups per rank): run-gen argmax gate + battery +
316/// fresh tape, the DEV_ROUTES acceptance class.
317pub(crate) fn step_nvfp4_ep2_on() -> bool {
318    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
319    *ON.get_or_init(|| std::env::var("MEMRA_STEP_NVFP4_EP2").as_deref() == Ok("1"))
320}
321
322pub(crate) fn oproj_direct_on() -> bool {
323    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
324    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_DIRECT").as_deref() == Ok("1"))
325}
326
327pub(crate) fn raw_copy_bytes(
328    dst: u64,
329    src: u64,
330    bytes: usize,
331    engine: &Engine,
332) -> Result<(), Box<dyn std::error::Error>> {
333    use cudarc::driver::sys;
334    let r = unsafe {
335        sys::cuMemcpyAsync(
336            dst as sys::CUdeviceptr,
337            src as sys::CUdeviceptr,
338            bytes,
339            engine.stream().cu_stream() as sys::CUstream,
340        )
341    };
342    if r == sys::CUresult::CUDA_SUCCESS {
343        Ok(())
344    } else {
345        // MEMRA_RAW_COPY_TRACE=1: a raw D2D failure carries no call site by itself, and
346        // every slab-width bug in the t-row family surfaces here. Operands + backtrace.
347        if std::env::var("MEMRA_RAW_COPY_TRACE").as_deref() == Ok("1") {
348            eprintln!(
349                "[raw-copy-fail] dst={dst:#x} src={src:#x} bytes={bytes} {r:?}\n{}",
350                std::backtrace::Backtrace::force_capture()
351            );
352        }
353        Err(format!("raw_copy_bytes: {r:?} bytes={bytes} dst={dst:#x} src={src:#x}").into())
354    }
355}
356
357pub fn step_expert_activation_host(gate: f32, up: f32, limit: Option<f32>) -> f32 {
358    let silu = gate / (1.0 + (-gate).exp());
359    match limit {
360        Some(limit) => silu.min(limit) * up.clamp(-limit, limit),
361        None => silu * up,
362    }
363}
364
365#[derive(Debug, Clone, PartialEq, Eq)]
366struct ExpertOwnerRoutes {
367    rank: usize,
368    selected: Vec<usize>,
369    token_rows: Vec<usize>,
370    global_pairs: Vec<usize>,
371}
372
373fn partition_expert_owner_routes(
374    expert_count: usize,
375    ranks: usize,
376    tokens: usize,
377    experts_per_token: usize,
378    selected: &[usize],
379) -> Result<Vec<ExpertOwnerRoutes>, String> {
380    if expert_count == 0
381        || ranks == 0
382        || tokens == 0
383        || experts_per_token == 0
384        || expert_count % ranks != 0
385    {
386        return Err(format!(
387            "invalid expert-owner route geometry experts={expert_count} ranks={ranks} \
388             tokens={tokens} experts_per_token={experts_per_token}"
389        ));
390    }
391    let pairs = tokens
392        .checked_mul(experts_per_token)
393        .ok_or("expert-owner route count overflow")?;
394    if selected.len() != pairs {
395        return Err(format!(
396            "expert-owner routes {} != {tokens}x{experts_per_token} ({pairs})",
397            selected.len()
398        ));
399    }
400    let per_rank = expert_count / ranks;
401    let mut owners = (0..ranks)
402        .map(|rank| ExpertOwnerRoutes {
403            rank,
404            selected: Vec::new(),
405            token_rows: Vec::new(),
406            global_pairs: Vec::new(),
407        })
408        .collect::<Vec<_>>();
409    for (pair, &expert) in selected.iter().enumerate() {
410        if expert >= expert_count {
411            return Err(format!(
412                "expert-owner route {pair} selects expert {expert} outside 0..{expert_count}"
413            ));
414        }
415        let rank = expert / per_rank;
416        owners[rank].selected.push(expert - rank * per_rank);
417        owners[rank].token_rows.push(pair / experts_per_token);
418        owners[rank].global_pairs.push(pair);
419    }
420    Ok(owners)
421}
422
423fn validate_step_grouped_owner_routes(
424    expert_count: usize,
425    tokens: usize,
426    selected: &[usize],
427) -> Result<usize, String> {
428    if expert_count != STEP_GROUPED_FP8_EXPERTS || tokens == 0 {
429        return Err(format!(
430            "official Step owner-grouped FP8 requires {} experts and nonzero tokens, got \
431             experts={expert_count} tokens={tokens}",
432            STEP_GROUPED_FP8_EXPERTS
433        ));
434    }
435    let pairs = tokens
436        .checked_mul(STEP_GROUPED_FP8_TOP_K)
437        .ok_or("official Step owner-grouped FP8 route count overflow")?;
438    if selected.len() != pairs {
439        return Err(format!(
440            "official Step owner-grouped FP8 routes {} != {tokens}x{} ({pairs})",
441            selected.len(),
442            STEP_GROUPED_FP8_TOP_K,
443        ));
444    }
445    for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
446        let mut unique = routes.to_vec();
447        unique.sort_unstable();
448        unique.dedup();
449        if unique.len() != STEP_GROUPED_FP8_TOP_K {
450            return Err(format!(
451                "official Step owner-grouped FP8 token {token} routes are not top-8 unique: \
452                 {routes:?}"
453            ));
454        }
455    }
456    Ok(pairs)
457}
458
459#[derive(Debug, Clone, Copy, PartialEq, Eq)]
460struct WeightedRouteCombineShape {
461    pairs: usize,
462    max_pairs: usize,
463}
464
465fn validate_weighted_route_combine(
466    width: usize,
467    experts_per_token: usize,
468    max_tokens: usize,
469    tokens: usize,
470    owner_global_pairs: &[&[usize]],
471    route_weights: &[f32],
472) -> Result<WeightedRouteCombineShape, String> {
473    if width == 0
474        || experts_per_token == 0
475        || max_tokens == 0
476        || tokens == 0
477        || tokens > max_tokens
478        || width > i32::MAX as usize
479        || experts_per_token > i32::MAX as usize
480        || tokens > i32::MAX as usize
481    {
482        return Err(format!(
483            "invalid weighted route combine geometry width={width} experts_per_token=\
484             {experts_per_token} tokens={tokens}/{max_tokens}"
485        ));
486    }
487    let pairs = tokens
488        .checked_mul(experts_per_token)
489        .ok_or("weighted route combine pair count overflow")?;
490    let max_pairs = max_tokens
491        .checked_mul(experts_per_token)
492        .ok_or("weighted route combine capacity overflow")?;
493    if route_weights.len() != pairs || !route_weights.iter().all(|weight| weight.is_finite()) {
494        return Err(format!(
495            "weighted route combine weights {} != pairs {pairs} or contain a non-finite value",
496            route_weights.len()
497        ));
498    }
499    let mut seen = vec![false; pairs];
500    let mut observed = 0usize;
501    for pairs_for_owner in owner_global_pairs {
502        observed = observed
503            .checked_add(pairs_for_owner.len())
504            .ok_or("weighted route combine observed pair count overflow")?;
505        for &pair in *pairs_for_owner {
506            if pair >= pairs || std::mem::replace(&mut seen[pair], true) {
507                return Err(format!(
508                    "weighted route combine pair {pair} is outside 0..{pairs} or duplicated"
509                ));
510            }
511        }
512    }
513    if observed != pairs || seen.iter().any(|present| !present) {
514        return Err(format!(
515            "weighted route combine owner schedules cover {observed} of {pairs} canonical pairs"
516        ));
517    }
518    Ok(WeightedRouteCombineShape { pairs, max_pairs })
519}
520
521fn cache_rank_rows(
522    rows: &[u8],
523    tokens: usize,
524    local_token_bytes: usize,
525    ranks: usize,
526    rank: usize,
527) -> Result<Vec<u8>, String> {
528    if ranks == 0 || rank >= ranks {
529        return Err(format!(
530            "TP cache rank {rank} is outside a {ranks}-rank layout"
531        ));
532    }
533    let global_token_bytes = local_token_bytes
534        .checked_mul(ranks)
535        .ok_or("TP cache global token-byte overflow")?;
536    let expected = tokens
537        .checked_mul(global_token_bytes)
538        .ok_or("TP cache row-byte overflow")?;
539    if rows.len() != expected {
540        return Err(format!(
541            "TP cache rows contain {} bytes, expected {tokens}x{global_token_bytes}={expected}",
542            rows.len()
543        ));
544    }
545    let mut shard = Vec::with_capacity(tokens * local_token_bytes);
546    for token in 0..tokens {
547        let start = token * global_token_bytes + rank * local_token_bytes;
548        shard.extend_from_slice(&rows[start..start + local_token_bytes]);
549    }
550    Ok(shard)
551}
552
553fn parse_step_tp_native_p2p(value: Option<&str>) -> Result<bool, String> {
554    match value {
555        None | Some("") | Some("0") => Ok(false),
556        Some("1") => Ok(true),
557        Some(value) => Err(format!(
558            "MEMRA_STEP_TP_NATIVE_P2P={value:?} is invalid; expected 0 or 1"
559        )),
560    }
561}
562
563pub fn step_tp_native_p2p_enabled() -> Result<bool, String> {
564    parse_step_tp_native_p2p(std::env::var("MEMRA_STEP_TP_NATIVE_P2P").ok().as_deref())
565}
566
567fn parse_step_tp_bulk_p2p(value: Option<&str>) -> Result<bool, String> {
568    match value {
569        None | Some("") | Some("0") => Ok(false),
570        Some("1") => Ok(true),
571        Some(value) => Err(format!(
572            "MEMRA_STEP_TP_BULK_P2P={value:?} is invalid; expected 0 or 1"
573        )),
574    }
575}
576
577pub fn step_tp_bulk_p2p_enabled() -> Result<bool, String> {
578    parse_step_tp_bulk_p2p(std::env::var("MEMRA_STEP_TP_BULK_P2P").ok().as_deref())
579}
580
581fn parse_step_ep_device_arithmetic(value: Option<&str>) -> Result<bool, String> {
582    match value {
583        None | Some("") | Some("0") => Ok(false),
584        Some("1") => Ok(true),
585        Some(value) => Err(format!(
586            "MEMRA_STEP_EP_DEVICE_ARITHMETIC={value:?} is invalid; expected 0 or 1"
587        )),
588    }
589}
590
591fn parse_step_nvfp4_dev_routes(value: Option<&str>) -> Result<bool, String> {
592    match value {
593        None | Some("") | Some("0") => Ok(false),
594        Some("1") => Ok(true),
595        Some(value) => Err(format!(
596            "MEMRA_STEP_NVFP4_DEV_ROUTES={value:?} is invalid; expected 0 or 1"
597        )),
598    }
599}
600
601/// Opt-in door for the device-resident NVFP4 TP routed-expert decode program. Default OFF; the
602/// host-canonical program remains the oracle until the device path carries its own gates.
603pub fn step_nvfp4_dev_routes_enabled() -> Result<bool, String> {
604    parse_step_nvfp4_dev_routes(std::env::var("MEMRA_STEP_NVFP4_DEV_ROUTES").ok().as_deref())
605}
606
607pub fn step_ep_device_arithmetic_enabled() -> Result<bool, String> {
608    parse_step_ep_device_arithmetic(
609        std::env::var("MEMRA_STEP_EP_DEVICE_ARITHMETIC")
610            .ok()
611            .as_deref(),
612    )
613}
614
615fn parse_step_tp_f32_mirror(value: Option<&str>) -> Result<bool, String> {
616    match value {
617        None | Some("") | Some("0") => Ok(false),
618        Some("1") => Ok(true),
619        Some(value) => Err(format!(
620            "MEMRA_STEP_TP_F32_MIRROR={value:?} is invalid; expected 0 or 1"
621        )),
622    }
623}
624
625pub fn step_tp_f32_mirror_enabled() -> Result<bool, String> {
626    parse_step_tp_f32_mirror(std::env::var("MEMRA_STEP_TP_F32_MIRROR").ok().as_deref())
627}
628
629fn parse_step_tp_decode_v2(value: Option<&str>) -> Result<bool, String> {
630    match value {
631        None | Some("") | Some("0") => Ok(false),
632        Some("1") => Ok(true),
633        Some(value) => Err(format!(
634            "MEMRA_STEP_TP_DECODE_V2={value:?} is invalid; expected 0 or 1"
635        )),
636    }
637}
638
639/// The v2 rank-local Step decode-attention driver: persistent workspaces, evented cross-stream
640/// ordering, and a root-device O reduction — same kernels, values, and canonical reduction order
641/// as the v1 driver (it requires the F32 mirror so no per-call weight expansion exists on either
642/// side of the comparison).
643pub fn step_tp_decode_v2_enabled() -> Result<bool, String> {
644    parse_step_tp_decode_v2(std::env::var("MEMRA_STEP_TP_DECODE_V2").ok().as_deref())
645}
646
647fn parse_step_tp_qkv_fused(value: Option<&str>) -> Result<bool, String> {
648    match value {
649        None | Some("") | Some("0") => Ok(false),
650        Some("1") => Ok(true),
651        Some(value) => Err(format!(
652            "MEMRA_STEP_TP_QKV_FUSED={value:?} is invalid; expected 0 or 1"
653        )),
654    }
655}
656
657fn parse_step_tp_dev_router(value: Option<&str>) -> Result<bool, String> {
658    match value {
659        None | Some("") | Some("0") => Ok(false),
660        Some("1") => Ok(true),
661        Some(value) => Err(format!(
662            "MEMRA_STEP_TP_DEV_ROUTER={value:?} is invalid; expected 0 or 1"
663        )),
664    }
665}
666
667/// Device-side sigmoid top-k routing for the TP device-IO expert program: the per-layer host
668/// logits readback (the last per-layer host sync) disappears. Selection tie-breaking may
669/// differ from the host router — NUMERIC-CLASS door, run-gen argmax gate + boot battery.
670pub fn step_tp_dev_router_enabled() -> Result<bool, String> {
671    parse_step_tp_dev_router(std::env::var("MEMRA_STEP_TP_DEV_ROUTER").ok().as_deref())
672}
673
674fn parse_step_tp_graph(value: Option<&str>) -> Result<bool, String> {
675    match value {
676        None | Some("") | Some("0") => Ok(false),
677        Some("1") => Ok(true),
678        Some(value) => Err(format!(
679            "MEMRA_STEP_TP_GRAPH={value:?} is invalid; expected 0 or 1"
680        )),
681    }
682}
683
684fn parse_step_tp_dcw(value: Option<&str>) -> Result<bool, String> {
685    match value {
686        None | Some("") | Some("0") => Ok(false),
687        Some("1") => Ok(true),
688        Some(value) => Err(format!(
689            "MEMRA_STEP_TP_DCW={value:?} is invalid; expected 0 or 1"
690        )),
691    }
692}
693
694/// Device-counter attention path (graph increment A run EAGERLY): append at len_d - base_d,
695/// inc_i32, fa over the counter-derived window — with bucket = the effective t_kv this is
696/// bit-identical to the host-row + kvmod path (the one-partition law), and it is the exact
697/// child content the capture wraps. Rebase tokens and sub-vec-floor contexts fall back.
698pub fn step_tp_dcw_enabled() -> Result<bool, String> {
699    parse_step_tp_dcw(std::env::var("MEMRA_STEP_TP_DCW").ok().as_deref())
700}
701
702/// CUDA-graph door for the shape-stable TP segments (first increment: the device-routed
703/// expert program — per-layer multi-device parents built from per-rank children, launched on
704/// the model engine's stream; zero per-token node updates). Mechanism proven by
705/// tp_graph_probe. VALUE-IDENTICAL: the graphs replay exactly the eager kernel/copy sequence.
706pub fn step_tp_graph_enabled() -> Result<bool, String> {
707    parse_step_tp_graph(std::env::var("MEMRA_STEP_TP_GRAPH").ok().as_deref())
708}
709
710/// Fused single-launch QKV projection inside the v2 decode driver — a NUMERIC-CLASS door
711/// (per-row deterministic tree reduce instead of the chunked cuBLASLt program), default OFF,
712/// gated by the run-gen argmax gate + boot battery like MEMRA_STEP_NVFP4_DEV_ROUTES.
713pub fn step_tp_qkv_fused_enabled() -> Result<bool, String> {
714    parse_step_tp_qkv_fused(std::env::var("MEMRA_STEP_TP_QKV_FUSED").ok().as_deref())
715}
716
717#[derive(Debug, Clone, PartialEq, Eq)]
718pub struct StepEpLayerSpec {
719    pub layer: usize,
720    pub devices: Vec<usize>,
721}
722
723pub type StepTpLayerSpec = StepEpLayerSpec;
724
725fn parse_step_layer_specs(
726    flag: &str,
727    value: Option<&str>,
728    allow_full_model: bool,
729) -> Result<Vec<StepEpLayerSpec>, String> {
730    let Some(value) = value else {
731        return Ok(Vec::new());
732    };
733    if value.is_empty() || value == "0" {
734        return Ok(Vec::new());
735    }
736
737    let mut specs = Vec::new();
738    for item in value.split(';') {
739        let (layers, devices) = item.split_once('@').ok_or_else(|| {
740            let layers = if allow_full_model {
741                "LAYER[-LAYER] or all"
742            } else {
743                "LAYER[-LAYER]"
744            };
745            format!("{flag} must be {layers}@DEVICE,DEVICE[;...]")
746        })?;
747        let (first, last) = if layers == "all" {
748            if !allow_full_model {
749                return Err(format!(
750                    "{flag} does not support the full-model shorthand; assign routed layers \
751                     explicitly"
752                ));
753            }
754            (0, STEP37_TRUNK_LAYERS - 1)
755        } else {
756            match layers.split_once('-') {
757                Some((first, last)) => {
758                    let first = first
759                        .parse::<usize>()
760                        .map_err(|_| format!("{flag} layer {first:?} is not an integer"))?;
761                    let last = last
762                        .parse::<usize>()
763                        .map_err(|_| format!("{flag} layer {last:?} is not an integer"))?;
764                    if first > last {
765                        return Err(format!("{flag} layer range {first}-{last} is reversed"));
766                    }
767                    if last - first + 1 > 128 {
768                        return Err(format!(
769                            "{flag} layer range {first}-{last} exceeds the 128-layer parser cap"
770                        ));
771                    }
772                    (first, last)
773                }
774                None => {
775                    let layer = layers
776                        .parse::<usize>()
777                        .map_err(|_| format!("{flag} layer {layers:?} is not an integer"))?;
778                    (layer, layer)
779                }
780            }
781        };
782        let devices = devices
783            .split(',')
784            .map(|device| {
785                device
786                    .parse::<usize>()
787                    .map_err(|_| format!("{flag} device {device:?} is not an integer"))
788            })
789            .collect::<Result<Vec<_>, _>>()?;
790        if !(2..=8).contains(&devices.len()) {
791            return Err(format!(
792                "{flag} requires 2..=8 devices, got {}",
793                devices.len()
794            ));
795        }
796        let mut unique = devices.clone();
797        unique.sort_unstable();
798        unique.dedup();
799        if unique.len() != devices.len() {
800            return Err(format!("{flag} devices must be distinct, got {devices:?}"));
801        }
802        for layer in first..=last {
803            if specs
804                .iter()
805                .any(|existing: &StepEpLayerSpec| existing.layer == layer)
806            {
807                return Err(format!("{flag} assigns layer {layer} more than once"));
808            }
809            specs.push(StepEpLayerSpec {
810                layer,
811                devices: devices.clone(),
812            });
813        }
814    }
815    Ok(specs)
816}
817
818pub fn parse_step_ep_layer_specs(value: Option<&str>) -> Result<Vec<StepEpLayerSpec>, String> {
819    parse_step_layer_specs("MEMRA_STEP_EP", value, false)
820}
821
822pub fn step_ep_layer_specs() -> Result<Vec<StepEpLayerSpec>, String> {
823    parse_step_ep_layer_specs(std::env::var("MEMRA_STEP_EP").ok().as_deref())
824}
825
826pub fn parse_step_tp_layer_specs(value: Option<&str>) -> Result<Vec<StepTpLayerSpec>, String> {
827    parse_step_layer_specs("MEMRA_STEP_TP", value, true)
828}
829
830pub fn step_tp_layer_specs() -> Result<Vec<StepTpLayerSpec>, String> {
831    parse_step_tp_layer_specs(std::env::var("MEMRA_STEP_TP").ok().as_deref())
832}
833
834#[derive(Clone, Copy)]
835pub struct E4m3BlockMatrix<'a> {
836    pub codes: &'a [u8],
837    pub scales: &'a [f32],
838    pub out_features: usize,
839    pub in_features: usize,
840}
841
842impl E4m3BlockMatrix<'_> {
843    fn validate(&self) -> Result<(), String> {
844        let code_count = self
845            .out_features
846            .checked_mul(self.in_features)
847            .ok_or_else(|| "E4M3 matrix size overflow".to_string())?;
848        if self.codes.len() != code_count {
849            return Err(format!(
850                "E4M3 code count {} != {}x{} ({code_count})",
851                self.codes.len(),
852                self.out_features,
853                self.in_features,
854            ));
855        }
856        let scale_count =
857            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
858        if self.scales.len() != scale_count {
859            return Err(format!(
860                "E4M3 scale count {} != {scale_count} for {}x{}",
861                self.scales.len(),
862                self.out_features,
863                self.in_features,
864            ));
865        }
866        if !self
867            .scales
868            .iter()
869            .all(|scale| scale.is_finite() && *scale > 0.0)
870        {
871            return Err("E4M3 scale grid contains a non-finite or non-positive value".to_string());
872        }
873        Ok(())
874    }
875}
876
877#[derive(Clone, Copy)]
878pub struct E4m3ExpertBank<'a> {
879    pub codes: &'a [u8],
880    pub scales: &'a [f32],
881    pub expert_count: usize,
882    pub out_features: usize,
883    pub in_features: usize,
884}
885
886impl E4m3ExpertBank<'_> {
887    fn validate(&self) -> Result<(), String> {
888        if self.expert_count == 0 {
889            return Err("E4M3 expert bank is empty".to_string());
890        }
891        let code_stride = self
892            .out_features
893            .checked_mul(self.in_features)
894            .ok_or_else(|| "E4M3 expert code stride overflow".to_string())?;
895        let code_count = self
896            .expert_count
897            .checked_mul(code_stride)
898            .ok_or_else(|| "E4M3 expert code count overflow".to_string())?;
899        if self.codes.len() != code_count {
900            return Err(format!(
901                "E4M3 expert code count {} != {}x{} ({code_count})",
902                self.codes.len(),
903                self.expert_count,
904                code_stride,
905            ));
906        }
907        let scale_stride =
908            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
909        let scale_count = self
910            .expert_count
911            .checked_mul(scale_stride)
912            .ok_or_else(|| "E4M3 expert scale count overflow".to_string())?;
913        if self.scales.len() != scale_count {
914            return Err(format!(
915                "E4M3 expert scale count {} != {}x{} ({scale_count})",
916                self.scales.len(),
917                self.expert_count,
918                scale_stride,
919            ));
920        }
921        if !self
922            .scales
923            .iter()
924            .all(|scale| scale.is_finite() && *scale > 0.0)
925        {
926            return Err(
927                "E4M3 expert scale grid contains a non-finite or non-positive value".to_string(),
928            );
929        }
930        Ok(())
931    }
932
933    pub fn expert(&self, expert: usize) -> Result<E4m3BlockMatrix<'_>, String> {
934        if expert >= self.expert_count {
935            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
936        }
937        let code_stride = self.out_features * self.in_features;
938        let scale_stride =
939            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
940        Ok(E4m3BlockMatrix {
941            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
942            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
943            out_features: self.out_features,
944            in_features: self.in_features,
945        })
946    }
947}
948
949pub struct ColumnParallelResult {
950    pub gathered: Vec<f32>,
951    pub rank_outputs: Vec<Vec<f32>>,
952}
953
954pub struct RowParallelResult {
955    pub reduced: Vec<f32>,
956    pub rank_partials: Vec<Vec<f32>>,
957}
958
959#[derive(Clone, Copy)]
960pub struct Bf16Matrix<'a> {
961    pub bytes: &'a [u8],
962    pub out_features: usize,
963    pub in_features: usize,
964}
965
966impl Bf16Matrix<'_> {
967    pub fn validate(&self) -> Result<(), String> {
968        if self.out_features == 0 || self.in_features == 0 {
969            return Err("BF16 matrix dimensions must be nonzero".into());
970        }
971        let expected = self
972            .out_features
973            .checked_mul(self.in_features)
974            .and_then(|values| values.checked_mul(2))
975            .ok_or("BF16 matrix byte count overflow")?;
976        if self.bytes.len() != expected {
977            return Err(format!(
978                "BF16 matrix bytes {} != {}x{}x2 ({expected})",
979                self.bytes.len(),
980                self.out_features,
981                self.in_features,
982            ));
983        }
984        Ok(())
985    }
986}
987
988struct ResidentE4m3Rank {
989    codes: CudaSlice<u8>,
990    scales: CudaSlice<f32>,
991    out_features: usize,
992    in_features: usize,
993}
994
995enum ResidentBf16Weight {
996    Bf16(CudaSlice<u8>),
997    F32(CudaSlice<f32>),
998}
999
1000impl ResidentBf16Weight {
1001    fn ordinal(&self) -> usize {
1002        match self {
1003            Self::Bf16(bytes) => bytes.ordinal(),
1004            Self::F32(values) => values.ordinal(),
1005        }
1006    }
1007}
1008
1009struct ResidentBf16Rank {
1010    weight: ResidentBf16Weight,
1011    out_features: usize,
1012    in_features: usize,
1013    /// q8_0 mirror built at load under MEMRA_STEP_TP_W8 (numeric-class door; the bf16 slab
1014    /// stays resident because every prefill/verify path is qualified against it).
1015    q8: Option<CudaSlice<u8>>,
1016}
1017
1018pub struct ResidentColumnParallel {
1019    ranks: Vec<ResidentE4m3Rank>,
1020    out_features: usize,
1021    in_features: usize,
1022}
1023
1024pub struct ResidentRowParallel {
1025    ranks: Vec<ResidentE4m3Rank>,
1026    out_features: usize,
1027    in_features: usize,
1028}
1029
1030pub struct ResidentBf16ColumnParallel {
1031    ranks: Vec<ResidentBf16Rank>,
1032    out_features: usize,
1033    in_features: usize,
1034    canonical_chunk_rows: Option<usize>,
1035}
1036
1037pub struct ResidentBf16RowParallel {
1038    ranks: Vec<ResidentBf16Rank>,
1039    out_features: usize,
1040    in_features: usize,
1041}
1042
1043pub struct ResidentStepBf16RowParallel {
1044    ranks: Vec<Vec<ResidentBf16Rank>>,
1045    out_features: usize,
1046    in_features: usize,
1047    canonical_chunk_cols: usize,
1048}
1049
1050/// Root-owned BF16 sigmoid router with persistent F32 weight, bias, and active mask.
1051pub struct ResidentSigmoidTopKRouter {
1052    weight: CudaSlice<f32>,
1053    correction_bias: CudaSlice<f32>,
1054    active: CudaSlice<u8>,
1055    root_device: usize,
1056    input_width: usize,
1057    expert_count: usize,
1058    experts_per_token: usize,
1059    active_count: usize,
1060    scaling_factor: f32,
1061    route_norm: bool,
1062}
1063
1064pub struct SigmoidTopKHostOutput {
1065    pub logits: Vec<f32>,
1066    pub selected: Vec<u32>,
1067    pub weights: Vec<f32>,
1068}
1069
1070/// Full BF16 SwiGLU weights replicated independently on every runtime rank.
1071pub struct ResidentReplicatedBf16SwiGlu {
1072    gate: Vec<ResidentBf16Rank>,
1073    up: Vec<ResidentBf16Rank>,
1074    down: Vec<ResidentBf16Rank>,
1075    input_width: usize,
1076    intermediate_width: usize,
1077}
1078
1079/// One token-major F32 batch replicated across a native-P2P rank group.
1080///
1081/// Every allocation is owned by its matching rank CUDA context. This is the generic handoff
1082/// substrate between independently sharded operators; it carries no model or topology claim.
1083pub struct ResidentReplicatedDeviceRows {
1084    ranks: Vec<CudaSlice<f32>>,
1085    tokens: usize,
1086    width: usize,
1087}
1088
1089impl ResidentReplicatedDeviceRows {
1090    pub fn tokens(&self) -> usize {
1091        self.tokens
1092    }
1093
1094    pub fn width(&self) -> usize {
1095        self.width
1096    }
1097
1098    pub fn ranks(&self) -> usize {
1099        self.ranks.len()
1100    }
1101}
1102
1103/// Canonical MoE output order: routed plus shared, then add the layer residual.
1104pub fn moe_residual_host(
1105    residual: &[f32],
1106    routed: &[f32],
1107    shared: &[f32],
1108) -> Result<Vec<f32>, String> {
1109    if residual.len() != routed.len() || residual.len() != shared.len() {
1110        return Err(format!(
1111            "MoE residual lengths residual={} routed={} shared={}",
1112            residual.len(),
1113            routed.len(),
1114            shared.len()
1115        ));
1116    }
1117    let ffn = routed
1118        .iter()
1119        .zip(shared)
1120        .map(|(&routed, &shared)| routed + shared)
1121        .collect::<Vec<_>>();
1122    Ok(residual
1123        .iter()
1124        .zip(ffn)
1125        .map(|(&residual, ffn)| residual + ffn)
1126        .collect())
1127}
1128
1129pub use memra_kv::{
1130    KvRingAppend, ResidentTpKvCache, ResidentTpKvCacheRank, TpKvAppendPlan, TpKvTransaction,
1131};
1132
1133/// Persistent TP2/TP4/TP8 routed-expert reference.
1134///
1135/// Rank-local checkpoint shards are uploaded once and remain tied to their owning CUDA context.
1136/// Activations and deterministic host-staged collectives remain per invocation. This is the
1137/// correctness substrate for serving TP/EP, not product-throughput evidence.
1138pub struct ResidentTpExpert {
1139    gate: ResidentColumnParallel,
1140    up: ResidentColumnParallel,
1141    down: ResidentRowParallel,
1142    input_width: usize,
1143    expert_width: usize,
1144}
1145
1146struct ResidentE4m3ExpertBankRank {
1147    codes: CudaSlice<u8>,
1148    scales: CudaSlice<f32>,
1149    expert_range: Range<usize>,
1150    out_features: usize,
1151    in_features: usize,
1152    code_stride: usize,
1153    scale_stride: usize,
1154    /// TP row banks are packed by native 128-wide K block so reduction can replay the
1155    /// checkpoint's global block order exactly. Other banks remain row-major.
1156    k_blocks: Option<usize>,
1157}
1158
1159struct PackedE4m3ExpertBankRank {
1160    codes: Vec<u8>,
1161    scales: Vec<f32>,
1162    expert_range: Range<usize>,
1163    out_features: usize,
1164    in_features: usize,
1165    code_stride: usize,
1166    scale_stride: usize,
1167    k_blocks: Option<usize>,
1168}
1169
1170struct ResidentEpRank {
1171    gate: ResidentE4m3ExpertBankRank,
1172    up: ResidentE4m3ExpertBankRank,
1173    down: ResidentE4m3ExpertBankRank,
1174}
1175
1176/// Persistent expert-parallel reference.
1177///
1178/// Every routed expert has exactly one owner rank. Shared experts are deliberately absent from
1179/// this object because Step replicates them per rank. Routes execute on the owner CUDA context.
1180/// The default oracle stages through host memory; the native path peer-dispatches inputs and
1181/// peer-returns owner outputs while preserving host-canonical activation and accumulation.
1182pub struct ResidentExpertParallel {
1183    ranks: Vec<ResidentEpRank>,
1184    expert_count: usize,
1185    input_width: usize,
1186    expert_width: usize,
1187}
1188
1189/// Projection-level output from the opt-in official Step grouped-FP8 gate.
1190///
1191/// Rows remain pair-major. Routing, weighted combine, and production integration are deliberately
1192/// outside this gate-only adapter.
1193pub struct StepGroupedFp8ProjectionOutput {
1194    pub gate: Vec<f32>,
1195    pub up: Vec<f32>,
1196    pub down: Vec<f32>,
1197}
1198
1199/// Prepared official Step grouped-FP8 projection gate.
1200///
1201/// The complete tensor banks, both CSR schedules, input, activation buffer, and three projection
1202/// workspaces are uploaded or allocated once. Repeated execution performs no device allocation.
1203pub struct PreparedStepGroupedFp8Gate {
1204    device: usize,
1205    gate: ResidentE4m3ExpertBankRank,
1206    up: ResidentE4m3ExpertBankRank,
1207    down: ResidentE4m3ExpertBankRank,
1208    input: CudaSlice<f32>,
1209    route_csr: DeviceExpertCsr,
1210    down_csr: DeviceExpertCsr,
1211    gate_workspace: Fp8GroupedWorkspace,
1212    up_workspace: Fp8GroupedWorkspace,
1213    down_workspace: Fp8GroupedWorkspace,
1214    activation: CudaSlice<f32>,
1215    activation_limit: Option<f32>,
1216    tokens: usize,
1217    pairs: usize,
1218}
1219
1220impl PreparedStepGroupedFp8Gate {
1221    pub fn tokens(&self) -> usize {
1222        self.tokens
1223    }
1224
1225    pub fn pairs(&self) -> usize {
1226        self.pairs
1227    }
1228}
1229
1230struct PreparedStepGroupedExpertOwner {
1231    rank: usize,
1232    global_pairs: Vec<usize>,
1233    route_csr: DeviceExpertCsr,
1234    down_csr: DeviceExpertCsr,
1235    gate_workspace: Fp8GroupedWorkspace,
1236    up_workspace: Fp8GroupedWorkspace,
1237    down_workspace: Fp8GroupedWorkspace,
1238    activation: CudaSlice<f32>,
1239}
1240
1241struct StepGroupedExpertOwnerSchedule {
1242    global_pairs: Vec<usize>,
1243    route_csr: ExpertCsr,
1244    down_csr: ExpertCsr,
1245}
1246
1247/// Prepared official Step expert-owner grouped-FP8 projection gate.
1248///
1249/// Route partitioning, owner-local CSR uploads, input dispatch, activation buffers, and grouped
1250/// workspaces are persistent. Projection rows are scattered back to canonical pair order only
1251/// after every owner has completed its rank-local program.
1252pub struct PreparedStepGroupedExpertParallelGate {
1253    rank_inputs: Vec<CudaSlice<f32>>,
1254    owners: Vec<PreparedStepGroupedExpertOwner>,
1255    activation_limit: Option<f32>,
1256    tokens: usize,
1257    pairs: usize,
1258    max_tokens: usize,
1259    max_pairs: usize,
1260    input_width: usize,
1261    expert_width: usize,
1262    generation: u64,
1263    executed_generation: Option<u64>,
1264    ready: bool,
1265}
1266
1267impl PreparedStepGroupedExpertParallelGate {
1268    pub fn tokens(&self) -> usize {
1269        self.tokens
1270    }
1271
1272    pub fn pairs(&self) -> usize {
1273        self.pairs
1274    }
1275
1276    pub fn max_tokens(&self) -> usize {
1277        self.max_tokens
1278    }
1279
1280    pub fn input_width(&self) -> usize {
1281        self.input_width
1282    }
1283
1284    pub fn expert_width(&self) -> usize {
1285        self.expert_width
1286    }
1287
1288    pub fn set_activation_limit(&mut self, limit: Option<f32>) -> Result<(), String> {
1289        validate_step_expert_activation_limit(limit)?;
1290        self.activation_limit = limit;
1291        self.executed_generation = None;
1292        Ok(())
1293    }
1294
1295    pub fn active_owners(&self) -> usize {
1296        self.owners
1297            .iter()
1298            .filter(|owner| !owner.global_pairs.is_empty())
1299            .count()
1300    }
1301
1302    pub fn owner_pair_counts(&self) -> Vec<usize> {
1303        self.owners
1304            .iter()
1305            .map(|owner| owner.global_pairs.len())
1306            .collect()
1307    }
1308
1309    pub fn generation(&self) -> u64 {
1310        self.generation
1311    }
1312}
1313
1314struct PreparedPeerWeightedRouteOwner {
1315    token_rows: CudaSlice<i32>,
1316    slots: CudaSlice<i32>,
1317    weights: CudaSlice<f32>,
1318    active_pairs: usize,
1319}
1320
1321/// Persistent root-side weighted combine for peer-owned canonical route rows.
1322///
1323/// Owner metadata, one reusable peer staging buffer, the canonical slot bank, weight bank, and
1324/// output are allocated once. Refreshes update metadata prefixes; execution peer-copies active
1325/// rows, scatters them by canonical token/slot, and reduces in the requested numeric order.
1326pub struct PreparedPeerWeightedRouteCombine {
1327    root_device: usize,
1328    owners: Vec<PreparedPeerWeightedRouteOwner>,
1329    peer_staging: CudaSlice<f32>,
1330    slots: CudaSlice<f32>,
1331    weights: CudaSlice<f32>,
1332    output: CudaSlice<f32>,
1333    peer_devices: Vec<usize>,
1334    peer_outputs: Vec<CudaSlice<f32>>,
1335    width: usize,
1336    experts_per_token: usize,
1337    max_tokens: usize,
1338    max_pairs: usize,
1339    tokens: usize,
1340    pairs: usize,
1341    projection_generation: u64,
1342    output_generation: Option<u64>,
1343    broadcast_generation: Option<u64>,
1344    ready: bool,
1345}
1346
1347impl PreparedPeerWeightedRouteCombine {
1348    pub fn tokens(&self) -> usize {
1349        self.tokens
1350    }
1351
1352    pub fn pairs(&self) -> usize {
1353        self.pairs
1354    }
1355
1356    pub fn owner_pair_counts(&self) -> Vec<usize> {
1357        self.owners.iter().map(|owner| owner.active_pairs).collect()
1358    }
1359
1360    pub fn distributed_ranks(&self) -> usize {
1361        1 + self.peer_outputs.len()
1362    }
1363}
1364
1365struct ResidentTpExpertBank {
1366    gate: Vec<ResidentE4m3ExpertBankRank>,
1367    up: Vec<ResidentE4m3ExpertBankRank>,
1368    down: Vec<ResidentE4m3ExpertBankRank>,
1369    expert_count: usize,
1370    input_width: usize,
1371    expert_width: usize,
1372}
1373
1374/// Persistent tensor-parallel expert bank.
1375///
1376/// Every rank owns a checkpoint-aligned output-row shard of every gate/up projection and an
1377/// input-column shard of every down projection. Activations cross deterministic host-staged
1378/// collectives on hosts where native peer copies are unavailable or corrupt.
1379pub struct ResidentTensorParallel {
1380    bank: ResidentTpExpertBank,
1381}
1382
1383/// Multi-context TP correctness runtime. Each rank owns an independent `Engine` and CUDA context.
1384///
1385/// Host bounce is the default oracle. Native P2P is opt-in and preserves the oracle's global
1386/// checkpoint-block reduction order; it remains a correctness path until serving gates and
1387/// repeated performance evidence qualify it.
1388pub struct TpE4m3HostBounce {
1389    devices: Vec<usize>,
1390    ranks: Vec<Engine>,
1391    native_p2p: bool,
1392    ep_device_arithmetic: bool,
1393    bulk_p2p: bool,
1394    /// v2 decode-attention workspace (MEMRA_STEP_TP_DECODE_V2). One per runtime, shared by
1395    /// every TP attention layer — the buffer shapes are geometry-constant across the trunk.
1396    decode_v2: std::sync::Mutex<Vec<StepTpDecodeV2Ws>>,
1397}
1398
1399/// Persistent workspace of the v2 rank-local decode-attention driver.
1400///
1401/// Buffers live in their producing rank's CUDA context, are never freed, and events are
1402/// re-recorded per call — the pp.rs `BoundarySlot` discipline — so the per-token path has no
1403/// cuMemAlloc, no cross-stream free, and no host round-trip. Every buffer is fully overwritten
1404/// before its consumers run in the same call; nothing carries state between tokens.
1405/// Per-rank attn_gate row shards for the fused QKV+gate kernel, in the weight class the
1406/// fused kernels read (F32 mirror or raw checkpoint bf16).
1407pub enum StepTpGateShards<'a> {
1408    F32(&'a [crate::CudaSlice<f32>]),
1409    Bf16(&'a [crate::CudaSlice<u8>]),
1410}
1411
1412pub struct StepTpDecodeV2Ws {
1413    /// T-COLUMN verify slabs (spec MTP): per-rank [t, local_dim] projections computed by
1414    /// the weight-amortized qkvg_tcol kernel; the col-select door copies one column into
1415    /// the single-row buffers and everything downstream runs the unmodified t=1 program.
1416    pub(crate) tcol_q: Vec<CudaSlice<f32>>,
1417    pub(crate) tcol_k: Vec<CudaSlice<f32>>,
1418    pub(crate) tcol_v: Vec<CudaSlice<f32>>,
1419    pub(crate) tcol_g: Vec<CudaSlice<f32>>,
1420    pub(crate) tcol_in: Vec<CudaSlice<f32>>,
1421    pub(crate) tcol_cap: usize,
1422    /// MEMRA_STEP_TP_W8 activation scratch: per-rank q8_1 quantized attention input
1423    /// ([in_f] i8 + one f32 scale pair per 32). Persistent because the alternative is an
1424    /// allocation per rank per layer per token.
1425    w8_aq: Vec<CudaSlice<i8>>,
1426    w8_ad: Vec<CudaSlice<f32>>,
1427    w8_in: usize,
1428    /// o_proj-side twin of the same scratch (its activation is the gated attention output,
1429    /// a different vector from the QKV input, so it needs its own buffers).
1430    w8o_aq: Vec<CudaSlice<i8>>,
1431    w8o_ad: Vec<CudaSlice<f32>>,
1432    w8o_in: usize,
1433    /// VERIFY-WALK q8_1 activation scratch, t columns wide (the decode scratch above is one
1434    /// row). Two sets because the QKV input and the gated attention output are different
1435    /// vectors of different widths.
1436    w8t_aq: Vec<CudaSlice<i8>>,
1437    w8t_ad: Vec<CudaSlice<f32>>,
1438    w8t_in: usize,
1439    w8t_oaq: Vec<CudaSlice<i8>>,
1440    w8t_oad: Vec<CudaSlice<f32>>,
1441    w8t_oin: usize,
1442    w8t_cap: usize,
1443    /// MEMRA_TCOL_OPROJ slabs: per-rank stashed `gated` rows ([8, local_q_dim]), per-rank
1444    /// b4_tcol partials ([8, o_out]), a root-side peer pull of rank1's partial slab, and
1445    /// the root-side joined `mixed` slab. Armed lazily by the first stash.
1446    /// MEMRA_SPEC_FA2 slabs: per-rank stashed post-rope q rows ([2, local_q_dim]), gate
1447    /// rows ([2, heads/ranks]) and the two gated outputs the per-row combine writes
1448    /// ([2, local_q_dim]). Armed lazily by the first stash.
1449    pub(crate) fa2_q: Vec<CudaSlice<f32>>,
1450    pub(crate) fa2_gate: Vec<CudaSlice<f32>>,
1451    pub(crate) fa2_gated: Vec<CudaSlice<f32>>,
1452    pub(crate) fa2_cap: usize,
1453    /// T-ROW rope/append twin scratch: per-rank roped-k rows ([8, local_kv]), per-row
1454    /// last-block counters ([8]) and the per-tick position slab ([8]). Armed with the
1455    /// fa2 slabs.
1456    rope_k_t: Vec<CudaSlice<f32>>,
1457    rope_ctr_t: Vec<CudaSlice<u32>>,
1458    rope_pos_t: Vec<CudaSlice<i32>>,
1459    /// Per-rank combined 6-word row tables, keyed by the caller's (layer, session-set,
1460    /// base-arming) signature. LEGACY: only the `MEMRA_ROWS_TAB_RESTAGE=0` rollback arm
1461    /// reads this. See `rows_tab_t` for why the key cannot be made safe.
1462    rows_tabs: Vec<std::collections::HashMap<u64, CudaSlice<u64>>>,
1463    /// Per-rank PERSISTENT 6-word row-table slab ([32, 6] u64), RESTAGED from the live
1464    /// distributed cache before every launch. Replaces the `rows_tabs` memo, whose key was
1465    /// a hash of (k pointer, base pointer, layer, t) while the table it returned also
1466    /// carried the V and LEN pointers: a session whose K buffer address was recycled hit
1467    /// another session's table and the append kernel wrote its K/V through the FREED
1468    /// pointers the entry still held. Same defect and same cure as the row-table twin in
1469    /// `step35_verify_fa_rows_join` (8c8397e0b2, Hermes `11339f5cd3c132a3`), which this
1470    /// path was left out of. One 32-word htod per rank per layer replaces the map lookup;
1471    /// no allocation, and the staging is stream-ordered exactly like `rope_pos_t`.
1472    rows_tab_t: Vec<CudaSlice<u64>>,
1473    /// HOST shadow of the last table staged under each retired memo key, used ONLY by
1474    /// `MEMRA_ROWS_TAB_STALE_SCAN=1` to prove that the retired key would have handed a live
1475    /// launch another allocation's pointers. Never read by a kernel.
1476    rows_tab_shadow: Vec<std::collections::HashMap<u64, Vec<u64>>>,
1477    tcol_gated: Vec<CudaSlice<f32>>,
1478    tcol_opart: Vec<CudaSlice<f32>>,
1479    tcol_opeer: Option<CudaSlice<f32>>,
1480    tcol_omix: Option<CudaSlice<f32>>,
1481    tcol_ocap: usize,
1482    // rank-context buffers, indexed by rank (pub(crate): the v2 driver in hybrid_forward
1483    // feeds them to the KV transaction and attention kernels between the two v2 phases)
1484    pub(crate) q_raw: Vec<CudaSlice<f32>>,
1485    pub(crate) k_raw: Vec<CudaSlice<f32>>,
1486    pub(crate) v_raw: Vec<CudaSlice<f32>>,
1487    pub(crate) q: Vec<CudaSlice<f32>>,
1488    pub(crate) k: Vec<CudaSlice<f32>>,
1489    pub(crate) pos: Vec<CudaSlice<i32>>,
1490    /// FUSION #1 last-block counters (one per rank; atomicInc auto-resets per launch).
1491    pub(crate) fuse_ctr: Vec<CudaSlice<u32>>,
1492    pub(crate) gate: Vec<CudaSlice<f32>>,
1493    pub(crate) attn_out: Vec<CudaSlice<f32>>,
1494    pub(crate) gated: Vec<CudaSlice<f32>>,
1495    /// [rank][block] O partials, each `o_out` wide, in the owning rank's context.
1496    o_partials: Vec<Vec<CudaSlice<f32>>>,
1497    /// Recorded on each rank's stream after its per-call work; root waits before peer reads.
1498    ev_rank: Vec<CudaEvent>,
1499    // root-context buffers
1500    peer_partial: CudaSlice<f32>,
1501    reduce_a: CudaSlice<f32>,
1502    reduce_b: CudaSlice<f32>,
1503    /// Never written; the canonical zero start of the v1 add chain.
1504    zeros: CudaSlice<f32>,
1505    pub(crate) k_shadow: CudaSlice<f32>,
1506    pub(crate) v_shadow: CudaSlice<f32>,
1507    ev_refresh: CudaEvent,
1508    ev_oproj: CudaEvent,
1509    // model-engine (e) context
1510    gate_e: CudaSlice<f32>,
1511    /// Per-token stages (e-ctx, fixed addresses): one eager e-stream copy each per layer; the
1512    /// rank flows raw-copy FROM them, which is exactly the shape graph capture needs.
1513    pub(crate) h_stage: Option<CudaSlice<f32>>,
1514    pub(crate) pos_stage: Option<CudaSlice<i32>>,
1515    /// Workspace-owned per-rank attention input rows (the stage flow copies into THESE, not
1516    /// the per-layer decode_input buffers — the workspace is shared across layers, so every
1517    /// captured/raw address it uses must be layer-invariant).
1518    attn_in: Vec<CudaSlice<f32>>,
1519    /// Cached raw pointers of the stage-flow operands (set when the stages arm).
1520    raw_h_stage: u64,
1521    raw_pos_stage: u64,
1522    raw_attn_in: Vec<u64>,
1523    raw_pos: Vec<u64>,
1524    raw_o_partial1: u64,
1525    raw_peer_partial: u64,
1526    raw_k1: u64,
1527    raw_v1: u64,
1528    raw_k_shadow: u64,
1529    raw_v_shadow: u64,
1530    /// Token-graph e-context mirrors (armed by the orchestrator): the root section
1531    /// raw-copies the reduced attention output and the shadow rows here so the e-glue
1532    /// children read same-context memory (cross-context kernel args are capture-illegal).
1533    raw_mixed_stage_e: u64,
1534    raw_reduce_a: u64,
1535    raw_shadow_stage_e: (u64, u64),
1536    ev_entry: CudaEvent,
1537    e_device: usize,
1538    // geometry pins
1539    local_q_dim: usize,
1540    local_kv_dim: usize,
1541    heads: usize,
1542    pub(crate) o_out: usize,
1543    o_block_cols: usize,
1544    blocks_per_rank: usize,
1545}
1546
1547impl TpE4m3HostBounce {
1548    pub fn new(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1549        Self::new_inner(devices, false, false, false, false)
1550    }
1551
1552    pub fn new_native_p2p(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1553        Self::new_inner(devices, false, true, false, false)
1554    }
1555
1556    pub fn new_native_p2p_device_arithmetic(
1557        devices: &[usize],
1558    ) -> Result<Self, Box<dyn std::error::Error>> {
1559        Self::new_inner(devices, false, true, true, false)
1560    }
1561
1562    pub(crate) fn new_configured(
1563        devices: &[usize],
1564        native_p2p: bool,
1565        ep_device_arithmetic: bool,
1566        bulk_p2p: bool,
1567    ) -> Result<Self, Box<dyn std::error::Error>> {
1568        Self::new_inner(devices, false, native_p2p, ep_device_arithmetic, bulk_p2p)
1569    }
1570
1571    /// Single-rank execution of the canonical checkpoint-block TP program.
1572    ///
1573    /// This is an oracle for distributed exactness, not a serving topology. It lets gates compare
1574    /// TP=1 and TP>1 with the same packing, kernel launches, and deterministic reduction order.
1575    pub fn new_single_rank_oracle(device: usize) -> Result<Self, Box<dyn std::error::Error>> {
1576        Self::new_inner(&[device], true, false, false, false)
1577    }
1578
1579    fn new_inner(
1580        devices: &[usize],
1581        allow_single_rank: bool,
1582        native_p2p: bool,
1583        ep_device_arithmetic: bool,
1584        bulk_p2p: bool,
1585    ) -> Result<Self, Box<dyn std::error::Error>> {
1586        if ep_device_arithmetic && !native_p2p {
1587            return Err("device-resident EP arithmetic requires native P2P".into());
1588        }
1589        if bulk_p2p && !native_p2p {
1590            return Err("bulk TP transport requires native P2P".into());
1591        }
1592        let minimum = if allow_single_rank { 1 } else { 2 };
1593        if !(minimum..=8).contains(&devices.len()) {
1594            return Err(format!(
1595                "TP reference requires {minimum}..=8 devices, got {}",
1596                devices.len()
1597            )
1598            .into());
1599        }
1600        let mut unique = devices.to_vec();
1601        unique.sort_unstable();
1602        unique.dedup();
1603        if unique.len() != devices.len() {
1604            return Err(format!("TP devices must be distinct, got {devices:?}").into());
1605        }
1606        let ranks = devices
1607            .iter()
1608            .map(|&device| Engine::new(device))
1609            .collect::<Result<Vec<_>, _>>()?;
1610        if native_p2p {
1611            configure_native_p2p(&ranks, devices)?;
1612        }
1613        if allow_single_rank {
1614            eprintln!(
1615                "[tp] canonical oracle transport=local device={} performance_claim=false",
1616                devices[0]
1617            );
1618        } else if native_p2p {
1619            if ep_device_arithmetic {
1620                eprintln!(
1621                    "[tp] correctness transport=native-p2p devices={devices:?} \
1622                     native_p2p=true activation=device-host-exact \
1623                     accumulation=device-host-exact output=root-readback \
1624                     bulk_p2p={bulk_p2p} performance_claim=false"
1625                );
1626            } else {
1627                eprintln!(
1628                    "[tp] correctness transport=native-p2p devices={devices:?} \
1629                     native_p2p=true activation=host-canonical bulk_p2p={bulk_p2p} \
1630                     performance_claim=false"
1631                );
1632            }
1633        } else {
1634            eprintln!(
1635                "[tp] correctness transport=host-bounce devices={devices:?} \
1636                 native_p2p=false performance_claim=false"
1637            );
1638        }
1639        Ok(Self {
1640            devices: devices.to_vec(),
1641            ranks,
1642            native_p2p,
1643            ep_device_arithmetic,
1644            bulk_p2p,
1645            decode_v2: std::sync::Mutex::new(Vec::new()),
1646        })
1647    }
1648
1649    pub fn devices(&self) -> &[usize] {
1650        &self.devices
1651    }
1652
1653    pub fn native_p2p(&self) -> bool {
1654        self.native_p2p
1655    }
1656
1657    pub fn bulk_p2p(&self) -> bool {
1658        self.bulk_p2p
1659    }
1660
1661    pub fn expert_activation_label(&self) -> &'static str {
1662        if self.ep_device_arithmetic {
1663            "device-host-exact"
1664        } else {
1665            "host-canonical"
1666        }
1667    }
1668
1669    pub fn expert_accumulation_label(&self) -> &'static str {
1670        self.expert_activation_label()
1671    }
1672
1673    pub fn expert_output_label(&self) -> &'static str {
1674        if self.ep_device_arithmetic {
1675            "root-readback"
1676        } else {
1677            "host-accumulated"
1678        }
1679    }
1680
1681    pub fn transport_label(&self) -> &'static str {
1682        if self.devices.len() == 1 {
1683            "local"
1684        } else if self.native_p2p {
1685            "native-p2p"
1686        } else {
1687            "host-bounce"
1688        }
1689    }
1690
1691    pub fn device_names(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
1692        self.ranks
1693            .iter()
1694            .map(|rank| rank.ctx().name().map_err(Into::into))
1695            .collect()
1696    }
1697
1698    /// Correctness-gate access to the engine that owns one TP rank.
1699    ///
1700    /// Model execution should prefer collective methods on this runtime. This accessor exists so
1701    /// focused gates can prove that the rank-local projection outputs remain device-resident
1702    /// through the next ownership boundary before that boundary is wired into serving.
1703    pub fn rank_engine(&self, rank: usize) -> Option<&Engine> {
1704        self.ranks.get(rank)
1705    }
1706
1707    pub fn allocate_tp_kv_cache(
1708        &self,
1709        kv_dim_k: usize,
1710        kv_dim_v: usize,
1711        capacity: usize,
1712    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1713        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, None)
1714    }
1715
1716    pub fn allocate_tp_swa_kv_cache(
1717        &self,
1718        kv_dim_k: usize,
1719        kv_dim_v: usize,
1720        capacity: usize,
1721        window: usize,
1722    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1723        if window == 0 {
1724            return Err("TP SWA KV window must be nonzero".into());
1725        }
1726        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, Some(window))
1727    }
1728
1729    fn allocate_tp_kv_cache_inner(
1730        &self,
1731        kv_dim_k: usize,
1732        kv_dim_v: usize,
1733        capacity: usize,
1734        window: Option<usize>,
1735    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1736        if capacity == 0 || capacity > i32::MAX as usize {
1737            return Err(
1738                format!("TP KV capacity must be in 1..={}, got {capacity}", i32::MAX).into(),
1739            );
1740        }
1741        let tp = self.ranks.len();
1742        let shape = crate::cache::tp_kv_rank_allocation_shape(kv_dim_k, kv_dim_v, tp)?;
1743        let physical_rows = window
1744            .map(|window| crate::cache::swa_ring_rows(window, capacity))
1745            .unwrap_or(capacity);
1746        let k_plane_bytes = physical_rows
1747            .checked_mul(shape.k_token_bytes)
1748            .and_then(|bytes| bytes.checked_add(8))
1749            .ok_or("TP KV K plane-byte overflow")?;
1750        let v_plane_bytes = physical_rows
1751            .checked_mul(shape.v_token_bytes)
1752            .and_then(|bytes| bytes.checked_add(8))
1753            .ok_or("TP KV V plane-byte overflow")?;
1754        let mut ranks = Vec::with_capacity(tp);
1755        for engine in &self.ranks {
1756            let _main = engine.gpu.enter_main()?;
1757            ranks.push(ResidentTpKvCacheRank::new(
1758                engine.alloc_u8(k_plane_bytes)?,
1759                engine.alloc_u8(v_plane_bytes)?,
1760                engine.htod_i32(&[0])?,
1761            ));
1762        }
1763        Ok(match window {
1764            Some(window) => ResidentTpKvCache::new_swa(
1765                ranks,
1766                shape.kv_dim_k,
1767                shape.kv_dim_v,
1768                shape.k_token_bytes,
1769                shape.v_token_bytes,
1770                capacity,
1771                window,
1772            ),
1773            None => ResidentTpKvCache::new(
1774                ranks,
1775                shape.kv_dim_k,
1776                shape.kv_dim_v,
1777                shape.k_token_bytes,
1778                shape.v_token_bytes,
1779                capacity,
1780            ),
1781        })
1782    }
1783
1784    pub fn grow_tp_kv_cache(
1785        &self,
1786        source: &ResidentTpKvCache,
1787        target_capacity: usize,
1788        rows: usize,
1789    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1790        self.validate_tp_kv_cache(source)?;
1791        let plan = source.prepare_grow(target_capacity, rows)?;
1792        let ranks = self.ranks.len();
1793        let global_k = source
1794            .kv_dim_k()
1795            .checked_mul(ranks)
1796            .ok_or("TP KV grow global K dimension overflow")?;
1797        let global_v = source
1798            .kv_dim_v()
1799            .checked_mul(ranks)
1800            .ok_or("TP KV grow global V dimension overflow")?;
1801        let mut target = match source.ring_window() {
1802            Some(window) => {
1803                self.allocate_tp_swa_kv_cache(global_k, global_v, target_capacity, window)?
1804            }
1805            None => self.allocate_tp_kv_cache(global_k, global_v, target_capacity)?,
1806        };
1807        self.validate_tp_kv_cache(&target)?;
1808
1809        for (rank, engine) in self.ranks.iter().enumerate() {
1810            let _main = engine.gpu.enter_main()?;
1811            let src = source
1812                .rank(rank)
1813                .ok_or_else(|| format!("TP KV grow source has no rank {rank}"))?;
1814            let dst = target
1815                .rank_mut(rank)
1816                .ok_or_else(|| format!("TP KV grow target has no rank {rank}"))?;
1817            if plan.k_bytes() > 0 {
1818                engine.copy_u8_range_into(
1819                    dst.k_mut(),
1820                    0,
1821                    src.k(),
1822                    plan.source_row() * source.k_tok_bytes(),
1823                    plan.k_bytes(),
1824                )?;
1825            }
1826            if plan.v_bytes() > 0 {
1827                engine.copy_u8_range_into(
1828                    dst.v_mut(),
1829                    0,
1830                    src.v(),
1831                    plan.source_row() * source.v_tok_bytes(),
1832                    plan.v_bytes(),
1833                )?;
1834            }
1835        }
1836        self.set_tp_kv_len_mirrors(&mut target, plan.rows())?;
1837
1838        // The caller publishes `target` and immediately drops `source`. Drain every rank's
1839        // stream so an async-pool free cannot recycle a source plane under an in-flight D2D copy.
1840        for engine in &self.ranks {
1841            let _main = engine.gpu.enter_main()?;
1842            engine.stream().synchronize()?;
1843        }
1844        let physical_copy_rows = plan.copy_rows();
1845        target.publish_grow(plan)?;
1846        eprintln!(
1847            "[step-tp-kv-grow] rows={} source_capacity={} target_capacity={} ranks={} \
1848             physical_copy_rows={} ring_window={:?} copy=rank-local-dtod \
1849             rank_streams_synchronized=true generation_preserved=true",
1850            rows,
1851            source.capacity(),
1852            target_capacity,
1853            ranks,
1854            physical_copy_rows,
1855            source.ring_window(),
1856        );
1857        Ok(target)
1858    }
1859
1860    pub fn hydrate_tp_kv_cache(
1861        &self,
1862        cache: &mut ResidentTpKvCache,
1863        rows: usize,
1864        k_rows: &[u8],
1865        v_rows: &[u8],
1866    ) -> Result<(), Box<dyn std::error::Error>> {
1867        self.hydrate_tp_kv_cache_from(cache, rows, 0, k_rows, v_rows)
1868    }
1869
1870    pub fn hydrate_tp_kv_cache_from(
1871        &self,
1872        cache: &mut ResidentTpKvCache,
1873        logical_len: usize,
1874        resident_start: usize,
1875        k_rows: &[u8],
1876        v_rows: &[u8],
1877    ) -> Result<(), Box<dyn std::error::Error>> {
1878        self.validate_tp_kv_cache(cache)?;
1879        if cache.committed_len() != 0 || cache.staged_len() != 0 {
1880            return Err(format!(
1881                "TP KV hydration requires an empty cache, got committed/staged={}/{}",
1882                cache.committed_len(),
1883                cache.staged_len()
1884            )
1885            .into());
1886        }
1887        if resident_start > logical_len || logical_len > cache.capacity() {
1888            return Err(format!(
1889                "TP KV hydration range [{resident_start},{logical_len}) exceeds capacity {}",
1890                cache.capacity(),
1891            )
1892            .into());
1893        }
1894        let rows = logical_len - resident_start;
1895        if rows > cache.physical_capacity() {
1896            return Err(format!(
1897                "TP KV hydration rows {rows} exceed physical capacity {}",
1898                cache.physical_capacity()
1899            )
1900            .into());
1901        }
1902        for rank in 0..self.ranks.len() {
1903            let k_rank =
1904                cache_rank_rows(k_rows, rows, cache.k_tok_bytes(), self.ranks.len(), rank)?;
1905            let v_rank =
1906                cache_rank_rows(v_rows, rows, cache.v_tok_bytes(), self.ranks.len(), rank)?;
1907            let engine = &self.ranks[rank];
1908            let _main = engine.gpu.enter_main()?;
1909            let rank_cache = cache
1910                .rank_mut(rank)
1911                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1912            engine.htod_u8_into(rank_cache.k_mut(), 0, &k_rank)?;
1913            engine.htod_u8_into(rank_cache.v_mut(), 0, &v_rank)?;
1914        }
1915        cache.publish_hydration(logical_len, resident_start)?;
1916        Ok(())
1917    }
1918
1919    pub fn append_tp_kv_transaction(
1920        &self,
1921        cache: &mut ResidentTpKvCache,
1922        transaction: TpKvTransaction,
1923        k_shards: &[CudaSlice<f32>],
1924        v_shards: &[CudaSlice<f32>],
1925        rows: usize,
1926    ) -> Result<(), Box<dyn std::error::Error>> {
1927        self.append_tp_kv_transaction_inner(cache, transaction, k_shards, v_shards, rows, false)
1928    }
1929
1930    /// `external_rank_appends`: the dcw path already wrote the rank rows (device-counter
1931    /// append) — run everything EXCEPT the per-rank quantize/append loop (plan validation,
1932    /// rebase arm — unreachable when the caller peeked — and the absolute len-mirror sets,
1933    /// which land the same value the in-stream inc produced).
1934    #[allow(clippy::too_many_arguments)]
1935    pub fn append_tp_kv_transaction_inner(
1936        &self,
1937        cache: &mut ResidentTpKvCache,
1938        transaction: TpKvTransaction,
1939        k_shards: &[CudaSlice<f32>],
1940        v_shards: &[CudaSlice<f32>],
1941        rows: usize,
1942        external_rank_appends: bool,
1943    ) -> Result<(), Box<dyn std::error::Error>> {
1944        self.validate_tp_kv_cache(cache)?;
1945        let plan = cache.prepare_append(transaction, rows)?;
1946        let target = plan.target();
1947        let expected_k = rows
1948            .checked_mul(cache.kv_dim_k())
1949            .ok_or("TP KV K append size overflow")?;
1950        let expected_v = rows
1951            .checked_mul(cache.kv_dim_v())
1952            .ok_or("TP KV V append size overflow")?;
1953        // external_rank_appends passes no shards — the graph's dcw appends already wrote
1954        // the rank rows, so this call is bookkeeping-only and the shard slices are unused.
1955        if !external_rank_appends
1956            && (k_shards.len() != self.ranks.len() || v_shards.len() != self.ranks.len())
1957        {
1958            return Err(format!(
1959                "TP KV append shard counts k={} v={} != ranks {}",
1960                k_shards.len(),
1961                v_shards.len(),
1962                self.ranks.len()
1963            )
1964            .into());
1965        }
1966        let kv_dim_k = cache.kv_dim_k();
1967        let kv_dim_v = cache.kv_dim_v();
1968        let k_tok_bytes = cache.k_tok_bytes();
1969        let v_tok_bytes = cache.v_tok_bytes();
1970        if let Some(KvRingAppend::Rebase {
1971            src_row,
1972            keep_rows,
1973            new_base,
1974            ..
1975        }) = plan.ring_append()
1976        {
1977            for rank in 0..self.ranks.len() {
1978                let engine = &self.ranks[rank];
1979                let _main = engine.gpu.enter_main()?;
1980                let rank_cache = cache
1981                    .rank_mut(rank)
1982                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1983                if keep_rows > 0 {
1984                    let k_len = keep_rows
1985                        .checked_mul(k_tok_bytes)
1986                        .ok_or("TP KV K rebase-byte overflow")?;
1987                    let v_len = keep_rows
1988                        .checked_mul(v_tok_bytes)
1989                        .ok_or("TP KV V rebase-byte overflow")?;
1990                    let mut k_tmp = engine.alloc_u8_uninit(k_len)?;
1991                    let mut v_tmp = engine.alloc_u8_uninit(v_len)?;
1992                    engine.copy_u8_range_into(
1993                        &mut k_tmp,
1994                        0,
1995                        rank_cache.k(),
1996                        src_row * k_tok_bytes,
1997                        k_len,
1998                    )?;
1999                    engine.copy_u8_range_into(
2000                        &mut v_tmp,
2001                        0,
2002                        rank_cache.v(),
2003                        src_row * v_tok_bytes,
2004                        v_len,
2005                    )?;
2006                    engine.copy_u8_into(rank_cache.k_mut(), 0, &k_tmp, k_len)?;
2007                    engine.copy_u8_into(rank_cache.v_mut(), 0, &v_tmp, v_len)?;
2008                }
2009                // dcw base mirror (graph increment A): physical row 0 now holds logical
2010                // row `new_base`; armed device mirrors track it (rebases are rare host
2011                // events, so a host set here is the whole maintenance cost).
2012                if rank_cache.base_d().is_some() {
2013                    let value = new_base as i32;
2014                    let rank_cache = cache
2015                        .rank_mut(rank)
2016                        .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2017                    if let Some(base_d) = rank_cache.base_d_mut() {
2018                        engine.set_i32_one(base_d, value)?;
2019                    }
2020                }
2021            }
2022        }
2023        cache.publish_append_rebase(plan)?;
2024        let write_row = plan.write_row();
2025        for rank in 0..self.ranks.len() {
2026            if external_rank_appends {
2027                break;
2028            }
2029            let engine = &self.ranks[rank];
2030            let _main = engine.gpu.enter_main()?;
2031            if k_shards[rank].len() != expected_k
2032                || v_shards[rank].len() != expected_v
2033                || k_shards[rank].ordinal() != engine.ctx().ordinal()
2034                || v_shards[rank].ordinal() != engine.ctx().ordinal()
2035            {
2036                return Err(format!(
2037                    "TP KV rank {rank} shard geometry/device k={}/{} v={}/{} \
2038                     != expected {expected_k}/{expected_v} on device {}",
2039                    k_shards[rank].len(),
2040                    k_shards[rank].ordinal(),
2041                    v_shards[rank].len(),
2042                    v_shards[rank].ordinal(),
2043                    engine.ctx().ordinal(),
2044                )
2045                .into());
2046            }
2047            let rank_cache = cache
2048                .rank_mut(rank)
2049                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2050            let (rank_k, rank_v) = rank_cache.planes_mut();
2051            engine.append_kv_quantized_rows(
2052                &k_shards[rank],
2053                &v_shards[rank],
2054                rank_k,
2055                rank_v,
2056                write_row,
2057                rows,
2058                kv_dim_k,
2059                kv_dim_v,
2060                k_tok_bytes,
2061                v_tok_bytes,
2062                Engine::kv_fp8_on(),
2063            )?;
2064        }
2065        if !external_rank_appends {
2066            // dcw appends advance the device counters with in-stream inc_i32; an absolute set
2067            // here would race the merged per-rank append (it reads len_d for its write row).
2068            self.set_tp_kv_len_mirrors(cache, target)?;
2069        }
2070        cache.publish_append_plan(plan)?;
2071        Ok(())
2072    }
2073
2074    pub fn commit_tp_kv_transaction(
2075        &self,
2076        cache: &mut ResidentTpKvCache,
2077        transaction: TpKvTransaction,
2078        accepted_rows: usize,
2079    ) -> Result<(), Box<dyn std::error::Error>> {
2080        self.validate_tp_kv_cache(cache)?;
2081        let target = cache.commit_target(transaction, accepted_rows)?;
2082        self.set_tp_kv_len_mirrors(cache, target)?;
2083        cache.publish_finalize(transaction, target)?;
2084        Ok(())
2085    }
2086
2087    /// Commit for the external-appends (token graph) path: host bookkeeping only, NO absolute
2088    /// len-mirror sets. The graph's in-stream inc_i32 owns the device counters; a rank-stream
2089    /// set here has no ordering edge against the NEXT token's graph launch (graph children do
2090    /// not wait on the rank streams), so it can land AFTER that graph's inc and drag the
2091    /// counter backward mid-token.
2092    pub fn commit_tp_kv_transaction_external(
2093        &self,
2094        cache: &mut ResidentTpKvCache,
2095        transaction: TpKvTransaction,
2096        accepted_rows: usize,
2097    ) -> Result<(), Box<dyn std::error::Error>> {
2098        self.validate_tp_kv_cache(cache)?;
2099        let target = cache.commit_target(transaction, accepted_rows)?;
2100        cache.publish_finalize(transaction, target)?;
2101        Ok(())
2102    }
2103
2104    pub fn rollback_tp_kv_transaction(
2105        &self,
2106        cache: &mut ResidentTpKvCache,
2107        transaction: TpKvTransaction,
2108    ) -> Result<(), Box<dyn std::error::Error>> {
2109        self.validate_tp_kv_cache(cache)?;
2110        cache.validate_transaction(transaction)?;
2111        let target = transaction.base_len();
2112        self.set_tp_kv_len_mirrors(cache, target)?;
2113        cache.publish_finalize(transaction, target)?;
2114        Ok(())
2115    }
2116
2117    pub fn tp_kv_device_lengths(
2118        &self,
2119        cache: &ResidentTpKvCache,
2120    ) -> Result<Vec<i32>, Box<dyn std::error::Error>> {
2121        self.validate_tp_kv_cache(cache)?;
2122        let mut lengths = Vec::with_capacity(self.ranks.len());
2123        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks()) {
2124            let _main = engine.gpu.enter_main()?;
2125            lengths.push(engine.dtoh_i32_one(rank_cache.len_d())?);
2126        }
2127        Ok(lengths)
2128    }
2129
2130    fn set_tp_kv_len_mirrors(
2131        &self,
2132        cache: &mut ResidentTpKvCache,
2133        len: usize,
2134    ) -> Result<(), Box<dyn std::error::Error>> {
2135        let len = i32::try_from(len).map_err(|_| "TP KV length exceeds i32 device mirror")?;
2136        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks_mut()) {
2137            let _main = engine.gpu.enter_main()?;
2138            engine.set_i32_one(rank_cache.len_d_mut(), len)?;
2139        }
2140        Ok(())
2141    }
2142
2143    fn validate_tp_kv_cache(
2144        &self,
2145        cache: &ResidentTpKvCache,
2146    ) -> Result<(), Box<dyn std::error::Error>> {
2147        if cache.ranks_len() != self.ranks.len() {
2148            return Err(format!(
2149                "TP KV cache ranks {} != runtime ranks {}",
2150                cache.ranks_len(),
2151                self.ranks.len()
2152            )
2153            .into());
2154        }
2155        let expected_k = cache
2156            .physical_capacity()
2157            .checked_mul(cache.k_tok_bytes())
2158            .and_then(|bytes| bytes.checked_add(8))
2159            .ok_or("TP KV K plane validation overflow")?;
2160        let expected_v = cache
2161            .physical_capacity()
2162            .checked_mul(cache.v_tok_bytes())
2163            .and_then(|bytes| bytes.checked_add(8))
2164            .ok_or("TP KV V plane validation overflow")?;
2165        for (rank, (engine, rank_cache)) in self.ranks.iter().zip(cache.ranks()).enumerate() {
2166            let device = engine.ctx().ordinal();
2167            if rank_cache.k().len() != expected_k
2168                || rank_cache.v().len() != expected_v
2169                || rank_cache.len_d().len() != 1
2170                || rank_cache.k().ordinal() != device
2171                || rank_cache.v().ordinal() != device
2172                || rank_cache.len_d().ordinal() != device
2173            {
2174                return Err(format!(
2175                    "TP KV rank {rank} residency does not match device {device} or plane geometry"
2176                )
2177                .into());
2178            }
2179        }
2180        Ok(())
2181    }
2182
2183    pub fn full(
2184        &self,
2185        matrix: E4m3BlockMatrix<'_>,
2186        activations: &[f32],
2187        tokens: usize,
2188    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2189        matrix.validate()?;
2190        validate_activations(activations, tokens, matrix.in_features)?;
2191        run_rank(&self.ranks[0], matrix, activations, tokens)
2192    }
2193
2194    /// Column-parallel projection. Weight output rows and their scale rows are partitioned across
2195    /// ranks. The input is host-broadcast, rank-local projections execute independently, and the
2196    /// output is host-gathered in rank order.
2197    pub fn column_parallel(
2198        &self,
2199        matrix: E4m3BlockMatrix<'_>,
2200        activations: &[f32],
2201        tokens: usize,
2202    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2203        matrix.validate()?;
2204        validate_activations(activations, tokens, matrix.in_features)?;
2205        let tp = self.ranks.len();
2206        if matrix.out_features % tp != 0 {
2207            return Err(format!(
2208                "column-parallel out_features {} is not divisible by TP={tp}",
2209                matrix.out_features
2210            )
2211            .into());
2212        }
2213        let local_out = matrix.out_features / tp;
2214        if local_out % FP8_BLOCK != 0 {
2215            return Err(format!(
2216                "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
2217                 E4M3 scale block"
2218            )
2219            .into());
2220        }
2221
2222        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2223        let mut rank_outputs = Vec::with_capacity(tp);
2224        for (rank_index, rank) in self.ranks.iter().enumerate() {
2225            let shard = column_shard(matrix, tp, rank_index)?;
2226            let output = run_rank(rank, shard, activations, tokens)?;
2227            let row_start = rank_index * local_out;
2228            for token in 0..tokens {
2229                gathered[token * matrix.out_features + row_start
2230                    ..token * matrix.out_features + row_start + local_out]
2231                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2232            }
2233            rank_outputs.push(output);
2234        }
2235        Ok(ColumnParallelResult {
2236            gathered,
2237            rank_outputs,
2238        })
2239    }
2240
2241    pub fn upload_column_parallel(
2242        &self,
2243        matrix: E4m3BlockMatrix<'_>,
2244    ) -> Result<ResidentColumnParallel, Box<dyn std::error::Error>> {
2245        matrix.validate()?;
2246        let tp = self.ranks.len();
2247        validate_column_shape(matrix, tp)?;
2248        let mut ranks = Vec::with_capacity(tp);
2249        for (rank_index, engine) in self.ranks.iter().enumerate() {
2250            ranks.push(upload_rank(engine, column_shard(matrix, tp, rank_index)?)?);
2251        }
2252        Ok(ResidentColumnParallel {
2253            ranks,
2254            out_features: matrix.out_features,
2255            in_features: matrix.in_features,
2256        })
2257    }
2258
2259    pub fn column_parallel_resident(
2260        &self,
2261        matrix: &ResidentColumnParallel,
2262        activations: &[f32],
2263        tokens: usize,
2264    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2265        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2266        validate_activations(activations, tokens, matrix.in_features)?;
2267        let local_out = matrix.out_features / self.ranks.len();
2268        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2269        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2270        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2271            let output = run_resident_rank(engine, shard, activations, tokens)?;
2272            let row_start = rank_index * local_out;
2273            for token in 0..tokens {
2274                gathered[token * matrix.out_features + row_start
2275                    ..token * matrix.out_features + row_start + local_out]
2276                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2277            }
2278            rank_outputs.push(output);
2279        }
2280        Ok(ColumnParallelResult {
2281            gathered,
2282            rank_outputs,
2283        })
2284    }
2285
2286    /// Row-parallel projection. Weight/input columns and their scale columns are partitioned
2287    /// across ranks. Rank-local partials return through host memory and are reduced in stable
2288    /// rank order.
2289    pub fn row_parallel(
2290        &self,
2291        matrix: E4m3BlockMatrix<'_>,
2292        activations: &[f32],
2293        tokens: usize,
2294    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2295        matrix.validate()?;
2296        validate_activations(activations, tokens, matrix.in_features)?;
2297        let tp = self.ranks.len();
2298        if matrix.in_features % tp != 0 {
2299            return Err(format!(
2300                "row-parallel in_features {} is not divisible by TP={tp}",
2301                matrix.in_features
2302            )
2303            .into());
2304        }
2305        let local_in = matrix.in_features / tp;
2306        if local_in % FP8_BLOCK != 0 {
2307            return Err(format!(
2308                "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
2309                 E4M3 scale block"
2310            )
2311            .into());
2312        }
2313
2314        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2315        let mut rank_partials = Vec::with_capacity(tp);
2316        for (rank_index, rank) in self.ranks.iter().enumerate() {
2317            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2318            let local_activations =
2319                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2320            let shard = E4m3BlockMatrix {
2321                codes: &codes,
2322                scales: &scales,
2323                out_features: matrix.out_features,
2324                in_features: local_in,
2325            };
2326            let partial = run_rank(rank, shard, &local_activations, tokens)?;
2327            for (sum, value) in reduced.iter_mut().zip(&partial) {
2328                *sum += *value;
2329            }
2330            rank_partials.push(partial);
2331        }
2332        Ok(RowParallelResult {
2333            reduced,
2334            rank_partials,
2335        })
2336    }
2337
2338    pub fn upload_row_parallel(
2339        &self,
2340        matrix: E4m3BlockMatrix<'_>,
2341    ) -> Result<ResidentRowParallel, Box<dyn std::error::Error>> {
2342        matrix.validate()?;
2343        let tp = self.ranks.len();
2344        validate_row_shape(matrix, tp)?;
2345        let local_in = matrix.in_features / tp;
2346        let mut ranks = Vec::with_capacity(tp);
2347        for (rank_index, engine) in self.ranks.iter().enumerate() {
2348            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2349            ranks.push(upload_rank(
2350                engine,
2351                E4m3BlockMatrix {
2352                    codes: &codes,
2353                    scales: &scales,
2354                    out_features: matrix.out_features,
2355                    in_features: local_in,
2356                },
2357            )?);
2358        }
2359        Ok(ResidentRowParallel {
2360            ranks,
2361            out_features: matrix.out_features,
2362            in_features: matrix.in_features,
2363        })
2364    }
2365
2366    pub fn row_parallel_resident(
2367        &self,
2368        matrix: &ResidentRowParallel,
2369        activations: &[f32],
2370        tokens: usize,
2371    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2372        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2373        validate_activations(activations, tokens, matrix.in_features)?;
2374        let tp = self.ranks.len();
2375        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2376        let mut rank_partials = Vec::with_capacity(tp);
2377        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2378            let local_activations =
2379                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2380            let partial = run_resident_rank(engine, shard, &local_activations, tokens)?;
2381            for (sum, value) in reduced.iter_mut().zip(&partial) {
2382                *sum += *value;
2383            }
2384            rank_partials.push(partial);
2385        }
2386        Ok(RowParallelResult {
2387            reduced,
2388            rank_partials,
2389        })
2390    }
2391
2392    pub fn upload_bf16_column_parallel(
2393        &self,
2394        matrix: Bf16Matrix<'_>,
2395    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2396        self.upload_bf16_column_parallel_inner(matrix, None, false)
2397    }
2398
2399    /// Step-3.7 column projection with one numerical program across TP1/TP2/TP4/TP8.
2400    pub fn upload_step_bf16_column_parallel(
2401        &self,
2402        matrix: Bf16Matrix<'_>,
2403    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2404        self.upload_step_bf16_column_parallel_inner(matrix, false)
2405    }
2406
2407    /// Load-time exact F32 expansion of a Step BF16 shard.
2408    ///
2409    /// The original BF16 allocation is released after the stream-ordered conversion. Decode then
2410    /// reuses the resident F32 values with the same topology-invariant output-row chunks.
2411    pub fn upload_step_bf16_column_parallel_f32_mirror(
2412        &self,
2413        matrix: Bf16Matrix<'_>,
2414    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2415        self.upload_step_bf16_column_parallel_inner(matrix, true)
2416    }
2417
2418    fn upload_step_bf16_column_parallel_inner(
2419        &self,
2420        matrix: Bf16Matrix<'_>,
2421        f32_mirror: bool,
2422    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2423        let canonical_chunk_rows =
2424            step_bf16_canonical_chunk_rows(matrix.out_features, self.ranks.len())?;
2425        self.upload_bf16_column_parallel_inner(matrix, Some(canonical_chunk_rows), f32_mirror)
2426    }
2427
2428    fn upload_bf16_column_parallel_inner(
2429        &self,
2430        matrix: Bf16Matrix<'_>,
2431        canonical_chunk_rows: Option<usize>,
2432        f32_mirror: bool,
2433    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2434        matrix.validate()?;
2435        let tp = self.ranks.len();
2436        if matrix.out_features % tp != 0 {
2437            return Err(format!(
2438                "BF16 column-parallel out_features {} is not divisible by TP={tp}",
2439                matrix.out_features
2440            )
2441            .into());
2442        }
2443        let mut ranks = Vec::with_capacity(tp);
2444        for (rank, engine) in self.ranks.iter().enumerate() {
2445            ranks.push(upload_bf16_rank(
2446                engine,
2447                bf16_column_shard(matrix, tp, rank)?,
2448                f32_mirror,
2449            )?);
2450        }
2451        Ok(ResidentBf16ColumnParallel {
2452            ranks,
2453            out_features: matrix.out_features,
2454            in_features: matrix.in_features,
2455            canonical_chunk_rows,
2456        })
2457    }
2458
2459    pub fn bf16_column_parallel_resident(
2460        &self,
2461        matrix: &ResidentBf16ColumnParallel,
2462        activations: &[f32],
2463        tokens: usize,
2464    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2465        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2466        validate_activations(activations, tokens, matrix.in_features)?;
2467        let local_out = matrix.out_features / self.ranks.len();
2468        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2469        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2470        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2471            let output = run_resident_bf16_rank(
2472                engine,
2473                shard,
2474                activations,
2475                tokens,
2476                matrix.canonical_chunk_rows,
2477            )?;
2478            for token in 0..tokens {
2479                let src = &output[token * local_out..(token + 1) * local_out];
2480                let dst_start = token * matrix.out_features + rank * local_out;
2481                gathered[dst_start..dst_start + local_out].copy_from_slice(src);
2482            }
2483            rank_outputs.push(output);
2484        }
2485        Ok(ColumnParallelResult {
2486            gathered,
2487            rank_outputs,
2488        })
2489    }
2490
2491    /// Native-P2P twin of [`Self::bf16_column_parallel_resident`].
2492    ///
2493    /// The host-canonical activation is uploaded once on rank zero and peer-broadcast to the
2494    /// remaining ranks. Rank-local outputs are peer-gathered in token-major order before one root
2495    /// readback. This removes per-rank host staging but deliberately still returns a host oracle;
2496    /// attention and KV ownership are separate milestones.
2497    pub fn bf16_column_parallel_resident_native(
2498        &self,
2499        matrix: &ResidentBf16ColumnParallel,
2500        activations: &[f32],
2501        tokens: usize,
2502    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2503        let rank_outputs =
2504            self.bf16_column_parallel_resident_device_shards(matrix, activations, tokens)?;
2505        let local_out = matrix.out_features / self.ranks.len();
2506        self.gather_native_column_shards(&rank_outputs, tokens, local_out)
2507    }
2508
2509    /// Does the serving engine live in the SAME CUDA context as this runtime's root rank?
2510    /// The device-resident input/output seams below hand raw device buffers across the
2511    /// Engine boundary, which is only addressable when both sides share the root device's
2512    /// primary context — the seam `step35_tp_qkv` keys its residency dispatch on.
2513    pub fn root_shares_ctx(&self, e: &Engine) -> bool {
2514        self.ranks
2515            .first()
2516            .is_some_and(|root| root.ctx().cu_ctx() == e.ctx().cu_ctx())
2517    }
2518
2519    /// Device-input twin of [`Self::bf16_column_parallel_resident_native`] (lane/
2520    /// hermes-perf-fixes, 2026-08-23 — the step QKV TP host-bounce finding). The activation
2521    /// arrives as a ROOT-DEVICE buffer (first `tokens * in_features` values) instead of a
2522    /// host slice, and the gathered output stays root-resident: no DtoH of the hidden state,
2523    /// no host q/k/v staging, no re-upload. BYTE-IDENTICAL to the host-canonical native arm
2524    /// by construction — the root input bytes are dtod-copied where the host arm htod'd the
2525    /// same bytes, and every kernel, peer copy, and gather order is shared.
2526    ///
2527    /// FENCES: caller must have synchronized the producer stream that wrote
2528    /// `root_activation` (the serving engine's — a DIFFERENT stream in the same context);
2529    /// this method synchronizes the root stream before returning so the caller's stream can
2530    /// consume the gathered output immediately.
2531    pub fn bf16_column_parallel_resident_native_device(
2532        &self,
2533        matrix: &ResidentBf16ColumnParallel,
2534        root_activation: &CudaSlice<f32>,
2535        tokens: usize,
2536    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
2537        let rank_outputs = self.bf16_column_parallel_resident_device_shards_from_root(
2538            matrix,
2539            root_activation,
2540            tokens,
2541        )?;
2542        let local_out = matrix.out_features / self.ranks.len();
2543        let gathered = self.gather_native_column_shards_device(&rank_outputs, tokens, local_out)?;
2544        let root = &self.ranks[0];
2545        let _main = root.gpu.enter_main()?;
2546        root.stream().synchronize()?;
2547        Ok(gathered)
2548    }
2549
2550    /// Root-device-input twin of [`Self::bf16_column_parallel_resident_device_shards`]:
2551    /// the canonical activation is already resident on the root device (len >=
2552    /// `tokens * in_features`; extra tail values beyond the active prefix are ignored,
2553    /// the reused-prime-slab contract of `active_matrix_values`).
2554    pub fn bf16_column_parallel_resident_device_shards_from_root(
2555        &self,
2556        matrix: &ResidentBf16ColumnParallel,
2557        root_activation: &CudaSlice<f32>,
2558        tokens: usize,
2559    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2560        if self.ranks.len() > 1 && !self.native_p2p {
2561            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
2562        }
2563        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2564        let values = tokens
2565            .checked_mul(matrix.in_features)
2566            .ok_or("device BF16 column activation size overflow")?;
2567        let root = &self.ranks[0];
2568        if tokens == 0
2569            || root_activation.len() < values
2570            || root_activation.ordinal() != root.ctx().ordinal()
2571        {
2572            return Err("device BF16 column root activation geometry mismatch".into());
2573        }
2574
2575        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
2576        let root_input = {
2577            let _main = root.gpu.enter_main()?;
2578            let mut root_input = root.uninit(values)?;
2579            root.stream()
2580                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
2581            root_input
2582        };
2583        // PRODUCER FENCE (same discipline as the host-input twin): the peer broadcast
2584        // below reads this buffer from the OTHER ranks' streams while the root dtod may
2585        // still be in flight.
2586        {
2587            let _main = root.gpu.enter_main()?;
2588            root.stream().synchronize()?;
2589        }
2590        rank_inputs.push(root_input);
2591        for engine in &self.ranks[1..] {
2592            let peer_input = {
2593                let _main = engine.gpu.enter_main()?;
2594                let mut peer_input = engine.uninit(values)?;
2595                engine
2596                    .stream()
2597                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
2598                peer_input
2599            };
2600            rank_inputs.push(peer_input);
2601        }
2602
2603        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2604        for rank in 0..self.ranks.len() {
2605            rank_outputs.push(run_resident_bf16_rank_device(
2606                &self.ranks[rank],
2607                &matrix.ranks[rank],
2608                &rank_inputs[rank],
2609                tokens,
2610                matrix.canonical_chunk_rows,
2611                self.bulk_p2p,
2612            )?);
2613        }
2614        Ok(rank_outputs)
2615    }
2616
2617    /// Keep Step BF16 column outputs resident on their owning TP ranks.
2618    ///
2619    /// Rank zero receives the host-canonical activation once and peer-broadcasts it when TP>1.
2620    /// Unlike [`Self::bf16_column_parallel_resident_native`], this method performs no output
2621    /// gather or readback. It is the correctness substrate for rank-local norm, RoPE, attention,
2622    /// and cache ownership; callers must not treat its existence as serving qualification.
2623    pub fn bf16_column_parallel_resident_device_shards(
2624        &self,
2625        matrix: &ResidentBf16ColumnParallel,
2626        activations: &[f32],
2627        tokens: usize,
2628    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2629        if self.ranks.len() > 1 && !self.native_p2p {
2630            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
2631        }
2632        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2633        validate_activations(activations, tokens, matrix.in_features)?;
2634
2635        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
2636        let root_input = {
2637            let root = &self.ranks[0];
2638            let _main = root.gpu.enter_main()?;
2639            root.htod(activations)?
2640        };
2641        // PRODUCER FENCE (2026-08-20 flake fix): the peer broadcast below reads this buffer from
2642        // the OTHER ranks' streams, and clone_htod is asynchronous on the root stream. Without
2643        // this fence a peer copy can overtake the in-flight H2D and replicate stale bytes — the
2644        // measured ~30%-of-boots prefill/decode argmax flake. Same discipline as
2645        // `upload_replicated_device_rows`.
2646        {
2647            let root = &self.ranks[0];
2648            let _main = root.gpu.enter_main()?;
2649            root.stream().synchronize()?;
2650        }
2651        rank_inputs.push(root_input);
2652        for engine in &self.ranks[1..] {
2653            let peer_input = {
2654                let _main = engine.gpu.enter_main()?;
2655                let mut peer_input = engine.uninit(activations.len())?;
2656                engine
2657                    .stream()
2658                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
2659                peer_input
2660            };
2661            rank_inputs.push(peer_input);
2662        }
2663
2664        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2665        for rank in 0..self.ranks.len() {
2666            rank_outputs.push(run_resident_bf16_rank_device(
2667                &self.ranks[rank],
2668                &matrix.ranks[rank],
2669                &rank_inputs[rank],
2670                tokens,
2671                matrix.canonical_chunk_rows,
2672                self.bulk_p2p,
2673            )?);
2674        }
2675        Ok(rank_outputs)
2676    }
2677
2678    /// Allocate one fixed-shape replicated batch without initializing its contents.
2679    ///
2680    /// Callers must refresh every rank before passing the batch to an operator.
2681    pub fn allocate_replicated_device_rows(
2682        &self,
2683        tokens: usize,
2684        width: usize,
2685    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2686        if self.ranks.len() > 1 && !self.native_p2p {
2687            return Err("replicated device rows require native P2P ranks".into());
2688        }
2689        let values = tokens
2690            .checked_mul(width)
2691            .ok_or("replicated device row size overflow")?;
2692        let rank_lengths = vec![values; self.ranks.len()];
2693        replicated_device_row_values(tokens, width, self.ranks.len(), &rank_lengths)?;
2694        let mut ranks = Vec::with_capacity(self.ranks.len());
2695        for engine in &self.ranks {
2696            let _main = engine.gpu.enter_main()?;
2697            ranks.push(engine.uninit(values)?);
2698        }
2699        Ok(ResidentReplicatedDeviceRows {
2700            ranks,
2701            tokens,
2702            width,
2703        })
2704    }
2705
2706    /// Replace a fixed-shape replicated batch from a root-device source.
2707    pub fn refresh_replicated_device_rows_from_root(
2708        &self,
2709        rows: &mut ResidentReplicatedDeviceRows,
2710        source: &CudaSlice<f32>,
2711    ) -> Result<(), Box<dyn std::error::Error>> {
2712        if self.ranks.len() > 1 && !self.native_p2p {
2713            return Err("replicated device rows require native P2P ranks".into());
2714        }
2715        validate_replicated_device_rows(&self.ranks, rows)?;
2716        let root = self
2717            .ranks
2718            .first()
2719            .ok_or("replicated rows have no root rank")?;
2720        let values = replicated_device_row_source_values(
2721            rows.tokens,
2722            rows.width,
2723            source.len(),
2724            source.ordinal(),
2725            root.ctx().ordinal(),
2726        )?;
2727        let (root_rows, peer_rows) = rows
2728            .ranks
2729            .split_first_mut()
2730            .ok_or("replicated rows have no root allocation")?;
2731        {
2732            let _main = root.gpu.enter_main()?;
2733            let mut destination = root_rows.slice_mut(0..values);
2734            root.stream()
2735                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
2736            root.stream().synchronize()?;
2737        }
2738        for (engine, peer_rows) in self.ranks.iter().skip(1).zip(peer_rows) {
2739            let _main = engine.gpu.enter_main()?;
2740            let mut destination = peer_rows.slice_mut(0..values);
2741            engine
2742                .stream()
2743                .memcpy_dtod(&root_rows.slice(0..values), &mut destination)?;
2744        }
2745        Ok(())
2746    }
2747
2748    /// Upload one canonical batch on rank zero and replicate it over native P2P.
2749    pub fn upload_replicated_device_rows(
2750        &self,
2751        rows: &[f32],
2752        tokens: usize,
2753        width: usize,
2754    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2755        if self.ranks.len() > 1 && !self.native_p2p {
2756            return Err("replicated device rows require native P2P ranks".into());
2757        }
2758        validate_activations(rows, tokens, width)?;
2759        let root = self
2760            .ranks
2761            .first()
2762            .ok_or("replicated rows have no root rank")?;
2763        let root_rows = {
2764            let _main = root.gpu.enter_main()?;
2765            root.htod(rows)?
2766        };
2767        {
2768            let _main = root.gpu.enter_main()?;
2769            root.stream().synchronize()?;
2770        }
2771        let mut ranks = Vec::with_capacity(self.ranks.len());
2772        ranks.push(root_rows);
2773        for engine in self.ranks.iter().skip(1) {
2774            let _main = engine.gpu.enter_main()?;
2775            let mut peer_rows = engine.uninit(rows.len())?;
2776            engine.stream().memcpy_dtod(&ranks[0], &mut peer_rows)?;
2777            ranks.push(peer_rows);
2778        }
2779        Ok(ResidentReplicatedDeviceRows {
2780            ranks,
2781            tokens,
2782            width,
2783        })
2784    }
2785
2786    /// Execute a column-parallel BF16 matrix directly from rank-local replicated inputs.
2787    pub fn bf16_column_parallel_resident_replicated_device_shards(
2788        &self,
2789        matrix: &ResidentBf16ColumnParallel,
2790        activations: &ResidentReplicatedDeviceRows,
2791    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2792        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2793        validate_replicated_device_rows(&self.ranks, activations)?;
2794        if activations.width != matrix.in_features {
2795            return Err(format!(
2796                "replicated BF16 column input width {} != matrix width {}",
2797                activations.width, matrix.in_features
2798            )
2799            .into());
2800        }
2801        let mut outputs = Vec::with_capacity(self.ranks.len());
2802        for rank in 0..self.ranks.len() {
2803            outputs.push(run_resident_bf16_rank_device(
2804                &self.ranks[rank],
2805                &matrix.ranks[rank],
2806                &activations.ranks[rank],
2807                activations.tokens,
2808                matrix.canonical_chunk_rows,
2809                self.bulk_p2p,
2810            )?);
2811        }
2812        Ok(outputs)
2813    }
2814
2815    /// Upload a BF16 router once on rank zero and retain its exact F32 expansion.
2816    #[allow(clippy::too_many_arguments)]
2817    pub fn upload_sigmoid_topk_router(
2818        &self,
2819        weight: Bf16Matrix<'_>,
2820        correction_bias: &[f32],
2821        active: Option<&[bool]>,
2822        experts_per_token: usize,
2823        scaling_factor: f32,
2824        route_norm: bool,
2825    ) -> Result<ResidentSigmoidTopKRouter, Box<dyn std::error::Error>> {
2826        weight.validate()?;
2827        if correction_bias.len() != weight.out_features
2828            || experts_per_token == 0
2829            || experts_per_token > weight.out_features
2830            || !correction_bias.iter().all(|value| value.is_finite())
2831            || !scaling_factor.is_finite()
2832            || scaling_factor <= 0.0
2833        {
2834            return Err(format!(
2835                "sigmoid router geometry weight={}x{} bias={} top_k={} scale={scaling_factor}",
2836                weight.out_features,
2837                weight.in_features,
2838                correction_bias.len(),
2839                experts_per_token,
2840            )
2841            .into());
2842        }
2843        let active_row = active
2844            .map(|mask| {
2845                if mask.len() != weight.out_features {
2846                    return Err(format!(
2847                        "sigmoid router active mask {} != experts {}",
2848                        mask.len(),
2849                        weight.out_features
2850                    ));
2851                }
2852                Ok(mask
2853                    .iter()
2854                    .map(|&enabled| u8::from(enabled))
2855                    .collect::<Vec<_>>())
2856            })
2857            .transpose()?
2858            .unwrap_or_else(|| vec![1; weight.out_features]);
2859        let active_count = active_row.iter().filter(|&&enabled| enabled != 0).count();
2860        crate::sigrouter_contract::validate_active_count(experts_per_token, active_count)?;
2861
2862        let root = self
2863            .ranks
2864            .first()
2865            .ok_or("sigmoid router runtime has no root rank")?;
2866        let _main = root.gpu.enter_main()?;
2867        let bf16 = root.htod_bytes(weight.bytes)?;
2868        let weight_f32 = root.bf16_to_f32(
2869            &bf16.slice(0..bf16.len()),
2870            weight.out_features * weight.in_features,
2871        )?;
2872        Ok(ResidentSigmoidTopKRouter {
2873            weight: weight_f32,
2874            correction_bias: root.htod(correction_bias)?,
2875            active: root.htod_bytes(&active_row)?,
2876            root_device: root.ctx().ordinal(),
2877            input_width: weight.in_features,
2878            expert_count: weight.out_features,
2879            experts_per_token,
2880            active_count,
2881            scaling_factor,
2882            route_norm,
2883        })
2884    }
2885
2886    /// Route rank-zero replicated rows and return the narrow host control result plus logits.
2887    ///
2888    /// The logits readback exists for independent oracle comparison. This method is a correctness
2889    /// surface; a serving scheduler may retain logits and selected routes on device.
2890    pub fn sigmoid_topk_replicated_device_rows_host(
2891        &self,
2892        router: &ResidentSigmoidTopKRouter,
2893        input: &ResidentReplicatedDeviceRows,
2894    ) -> Result<SigmoidTopKHostOutput, Box<dyn std::error::Error>> {
2895        validate_replicated_device_rows(&self.ranks, input)?;
2896        if input.width != router.input_width {
2897            return Err(format!(
2898                "sigmoid router input width {} != resident width {}",
2899                input.width, router.input_width
2900            )
2901            .into());
2902        }
2903        let root = self
2904            .ranks
2905            .first()
2906            .ok_or("sigmoid router runtime has no root rank")?;
2907        let _main = root.gpu.enter_main()?;
2908        if root.ctx().ordinal() != router.root_device
2909            || router.weight.ordinal() != router.root_device
2910            || router.correction_bias.ordinal() != router.root_device
2911            || router.active.ordinal() != router.root_device
2912        {
2913            return Err("sigmoid router root residency changed".into());
2914        }
2915        let logits = root.router_gemv(
2916            &router.weight,
2917            &input.ranks[0],
2918            router.input_width,
2919            router.expert_count,
2920            input.tokens,
2921        )?;
2922        let (selected, weights) = root.moe_router_sigmoid_topk_host(
2923            &logits,
2924            input.tokens,
2925            router.expert_count,
2926            router.experts_per_token,
2927            router.active_count,
2928            &router.correction_bias,
2929            &router.active,
2930            router.scaling_factor,
2931            router.route_norm,
2932        )?;
2933        Ok(SigmoidTopKHostOutput {
2934            logits: root.dtoh(&logits)?,
2935            selected,
2936            weights,
2937        })
2938    }
2939
2940    /// Replicate a full BF16 SwiGLU bank on every rank.
2941    pub fn upload_replicated_bf16_swiglu(
2942        &self,
2943        gate: Bf16Matrix<'_>,
2944        up: Bf16Matrix<'_>,
2945        down: Bf16Matrix<'_>,
2946    ) -> Result<ResidentReplicatedBf16SwiGlu, Box<dyn std::error::Error>> {
2947        gate.validate()?;
2948        up.validate()?;
2949        down.validate()?;
2950        if gate.in_features != up.in_features
2951            || gate.out_features != up.out_features
2952            || down.in_features != gate.out_features
2953            || down.out_features != gate.in_features
2954        {
2955            return Err(format!(
2956                "replicated BF16 SwiGLU geometry gate={}x{} up={}x{} down={}x{}",
2957                gate.out_features,
2958                gate.in_features,
2959                up.out_features,
2960                up.in_features,
2961                down.out_features,
2962                down.in_features,
2963            )
2964            .into());
2965        }
2966        let mut gate_ranks = Vec::with_capacity(self.ranks.len());
2967        let mut up_ranks = Vec::with_capacity(self.ranks.len());
2968        let mut down_ranks = Vec::with_capacity(self.ranks.len());
2969        for engine in &self.ranks {
2970            gate_ranks.push(upload_bf16_rank(engine, gate, false)?);
2971            up_ranks.push(upload_bf16_rank(engine, up, false)?);
2972            down_ranks.push(upload_bf16_rank(engine, down, false)?);
2973        }
2974        Ok(ResidentReplicatedBf16SwiGlu {
2975            gate: gate_ranks,
2976            up: up_ranks,
2977            down: down_ranks,
2978            input_width: gate.in_features,
2979            intermediate_width: gate.out_features,
2980        })
2981    }
2982
2983    /// Execute a fully replicated BF16 SwiGLU directly from replicated device rows.
2984    pub fn replicated_bf16_swiglu_resident_device(
2985        &self,
2986        mlp: &ResidentReplicatedBf16SwiGlu,
2987        input: &ResidentReplicatedDeviceRows,
2988        activation_limit: Option<f32>,
2989    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2990        validate_step_expert_activation_limit(activation_limit)?;
2991        validate_replicated_device_rows(&self.ranks, input)?;
2992        validate_resident_bf16_ranks(&self.ranks, &mlp.gate)?;
2993        validate_resident_bf16_ranks(&self.ranks, &mlp.up)?;
2994        validate_resident_bf16_ranks(&self.ranks, &mlp.down)?;
2995        if input.width != mlp.input_width
2996            || mlp.gate.len() != self.ranks.len()
2997            || mlp.up.len() != self.ranks.len()
2998            || mlp.down.len() != self.ranks.len()
2999        {
3000            return Err("replicated BF16 SwiGLU residency or input width changed".into());
3001        }
3002
3003        let mut outputs = Vec::with_capacity(self.ranks.len());
3004        for rank in 0..self.ranks.len() {
3005            let engine = &self.ranks[rank];
3006            let gate = run_resident_bf16_rank_device(
3007                engine,
3008                &mlp.gate[rank],
3009                &input.ranks[rank],
3010                input.tokens,
3011                None,
3012                self.bulk_p2p,
3013            )?;
3014            let up = run_resident_bf16_rank_device(
3015                engine,
3016                &mlp.up[rank],
3017                &input.ranks[rank],
3018                input.tokens,
3019                None,
3020                self.bulk_p2p,
3021            )?;
3022            let _main = engine.gpu.enter_main()?;
3023            let values = input
3024                .tokens
3025                .checked_mul(mlp.intermediate_width)
3026                .ok_or("replicated BF16 SwiGLU activation size overflow")?;
3027            let mut activation = engine.uninit(values)?;
3028            if let Some(limit) = activation_limit {
3029                engine.silu_clamped_mul_host_expf(&gate, &up, limit, &mut activation, values)?;
3030            } else {
3031                engine.silu_mul_host_expf(&gate, &up, &mut activation, values)?;
3032            }
3033            outputs.push(run_resident_bf16_rank_device(
3034                engine,
3035                &mlp.down[rank],
3036                &activation,
3037                input.tokens,
3038                None,
3039                self.bulk_p2p,
3040            )?);
3041        }
3042        Ok(ResidentReplicatedDeviceRows {
3043            ranks: outputs,
3044            tokens: input.tokens,
3045            width: mlp.input_width,
3046        })
3047    }
3048
3049    /// Apply the same RMS-norm row program independently on every replicated rank.
3050    pub fn rms_norm_replicated_device_rows(
3051        &self,
3052        input: &ResidentReplicatedDeviceRows,
3053        weight: &[f32],
3054        eps: f32,
3055    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3056        validate_replicated_device_rows(&self.ranks, input)?;
3057        if weight.len() != input.width || !eps.is_finite() || eps <= 0.0 {
3058            return Err(format!(
3059                "replicated RMS norm weight/eps {}/{} != width {}",
3060                weight.len(),
3061                eps,
3062                input.width
3063            )
3064            .into());
3065        }
3066        let mut ranks = Vec::with_capacity(self.ranks.len());
3067        for (rank, engine) in self.ranks.iter().enumerate() {
3068            let _main = engine.gpu.enter_main()?;
3069            let weight = engine.htod(weight)?;
3070            let mut output = engine.uninit(input.tokens * input.width)?;
3071            engine.rms_norm(
3072                &input.ranks[rank],
3073                &weight,
3074                &mut output,
3075                input.width,
3076                input.tokens,
3077                eps,
3078            )?;
3079            ranks.push(output);
3080        }
3081        Ok(ResidentReplicatedDeviceRows {
3082            ranks,
3083            tokens: input.tokens,
3084            width: input.width,
3085        })
3086    }
3087
3088    /// Add two replicated batches and RMS-normalize the exact residual on every rank.
3089    pub fn add_rms_norm_replicated_device_rows(
3090        &self,
3091        input: &ResidentReplicatedDeviceRows,
3092        update: &ResidentReplicatedDeviceRows,
3093        weight: &[f32],
3094        eps: f32,
3095    ) -> Result<
3096        (ResidentReplicatedDeviceRows, ResidentReplicatedDeviceRows),
3097        Box<dyn std::error::Error>,
3098    > {
3099        validate_replicated_device_rows(&self.ranks, input)?;
3100        validate_replicated_device_rows(&self.ranks, update)?;
3101        if input.tokens != update.tokens
3102            || input.width != update.width
3103            || weight.len() != input.width
3104            || !eps.is_finite()
3105            || eps <= 0.0
3106        {
3107            return Err(format!(
3108                "replicated add/RMS geometry input={}x{} update={}x{} weight={} eps={eps}",
3109                input.tokens,
3110                input.width,
3111                update.tokens,
3112                update.width,
3113                weight.len(),
3114            )
3115            .into());
3116        }
3117        let values = input.tokens * input.width;
3118        let mut residual_ranks = Vec::with_capacity(self.ranks.len());
3119        let mut normalized_ranks = Vec::with_capacity(self.ranks.len());
3120        for (rank, engine) in self.ranks.iter().enumerate() {
3121            let _main = engine.gpu.enter_main()?;
3122            let weight = engine.htod(weight)?;
3123            let mut residual = engine.uninit(values)?;
3124            let mut normalized = engine.uninit(values)?;
3125            engine.add_rms_norm(
3126                &input.ranks[rank],
3127                &update.ranks[rank],
3128                &weight,
3129                &mut residual,
3130                &mut normalized,
3131                input.width,
3132                input.tokens,
3133                eps,
3134            )?;
3135            residual_ranks.push(residual);
3136            normalized_ranks.push(normalized);
3137        }
3138        Ok((
3139            ResidentReplicatedDeviceRows {
3140                ranks: residual_ranks,
3141                tokens: input.tokens,
3142                width: input.width,
3143            },
3144            ResidentReplicatedDeviceRows {
3145                ranks: normalized_ranks,
3146                tokens: input.tokens,
3147                width: input.width,
3148            },
3149        ))
3150    }
3151
3152    pub fn collect_replicated_device_rows(
3153        &self,
3154        rows: &ResidentReplicatedDeviceRows,
3155    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
3156        validate_replicated_device_rows(&self.ranks, rows)?;
3157        let mut outputs = Vec::with_capacity(self.ranks.len());
3158        for (rank, engine) in self.ranks.iter().enumerate() {
3159            let _main = engine.gpu.enter_main()?;
3160            outputs.push(engine.dtoh(&rows.ranks[rank])?);
3161        }
3162        Ok(outputs)
3163    }
3164
3165    pub fn upload_bf16_row_parallel(
3166        &self,
3167        matrix: Bf16Matrix<'_>,
3168    ) -> Result<ResidentBf16RowParallel, Box<dyn std::error::Error>> {
3169        matrix.validate()?;
3170        let tp = self.ranks.len();
3171        if matrix.in_features % tp != 0 {
3172            return Err(format!(
3173                "BF16 row-parallel in_features {} is not divisible by TP={tp}",
3174                matrix.in_features
3175            )
3176            .into());
3177        }
3178        let mut ranks = Vec::with_capacity(tp);
3179        for (rank, engine) in self.ranks.iter().enumerate() {
3180            let shard = bf16_row_shard(matrix, tp, rank)?;
3181            ranks.push(upload_bf16_rank(
3182                engine,
3183                Bf16Matrix {
3184                    bytes: &shard,
3185                    out_features: matrix.out_features,
3186                    in_features: matrix.in_features / tp,
3187                },
3188                false,
3189            )?);
3190        }
3191        Ok(ResidentBf16RowParallel {
3192            ranks,
3193            out_features: matrix.out_features,
3194            in_features: matrix.in_features,
3195        })
3196    }
3197
3198    pub fn bf16_row_parallel_resident(
3199        &self,
3200        matrix: &ResidentBf16RowParallel,
3201        activations: &[f32],
3202        tokens: usize,
3203    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
3204        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3205        validate_activations(activations, tokens, matrix.in_features)?;
3206        let tp = self.ranks.len();
3207        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
3208        let mut rank_partials = Vec::with_capacity(tp);
3209        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3210            let local_activations =
3211                activation_shard(activations, tokens, matrix.in_features, tp, rank);
3212            let partial = run_resident_bf16_rank(engine, shard, &local_activations, tokens, None)?;
3213            for (sum, value) in reduced.iter_mut().zip(&partial) {
3214                *sum += value;
3215            }
3216            rank_partials.push(partial);
3217        }
3218        Ok(RowParallelResult {
3219            reduced,
3220            rank_partials,
3221        })
3222    }
3223
3224    /// Step-3.7 row projection split into the same eight global K blocks for TP1/TP2/TP4/TP8.
3225    pub fn upload_step_bf16_row_parallel(
3226        &self,
3227        matrix: Bf16Matrix<'_>,
3228    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3229        self.upload_step_bf16_row_parallel_inner(matrix, false)
3230    }
3231
3232    pub fn upload_step_bf16_row_parallel_f32_mirror(
3233        &self,
3234        matrix: Bf16Matrix<'_>,
3235    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3236        self.upload_step_bf16_row_parallel_inner(matrix, true)
3237    }
3238
3239    fn upload_step_bf16_row_parallel_inner(
3240        &self,
3241        matrix: Bf16Matrix<'_>,
3242        f32_mirror: bool,
3243    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3244        matrix.validate()?;
3245        let tp = self.ranks.len();
3246        let canonical_chunk_cols = step_bf16_canonical_chunk_cols(matrix.in_features, tp)?;
3247        let local_in = matrix.in_features / tp;
3248        let blocks_per_rank = local_in / canonical_chunk_cols;
3249        let mut ranks = Vec::with_capacity(tp);
3250        for (rank, engine) in self.ranks.iter().enumerate() {
3251            let mut blocks = Vec::with_capacity(blocks_per_rank);
3252            for block in 0..blocks_per_rank {
3253                let global_block = rank * blocks_per_rank + block;
3254                let col_start = global_block * canonical_chunk_cols;
3255                let bytes = bf16_row_block(matrix, col_start, canonical_chunk_cols)?;
3256                blocks.push(upload_bf16_rank(
3257                    engine,
3258                    Bf16Matrix {
3259                        bytes: &bytes,
3260                        out_features: matrix.out_features,
3261                        in_features: canonical_chunk_cols,
3262                    },
3263                    f32_mirror,
3264                )?);
3265            }
3266            ranks.push(blocks);
3267        }
3268        Ok(ResidentStepBf16RowParallel {
3269            ranks,
3270            out_features: matrix.out_features,
3271            in_features: matrix.in_features,
3272            canonical_chunk_cols,
3273        })
3274    }
3275
3276    /// Host-staged exactness twin of [`Self::step_bf16_row_parallel_resident_native`].
3277    ///
3278    /// Block inputs and partials cross host memory, but every partial is added on the root device
3279    /// in global checkpoint-column order. Native transport must reproduce this result bitwise.
3280    pub fn step_bf16_row_parallel_resident(
3281        &self,
3282        matrix: &ResidentStepBf16RowParallel,
3283        activations: &[f32],
3284        tokens: usize,
3285    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3286        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3287        validate_activations(activations, tokens, matrix.in_features)?;
3288        let root = &self.ranks[0];
3289        let output_len = tokens
3290            .checked_mul(matrix.out_features)
3291            .ok_or("Step BF16 row output size overflow")?;
3292        let mut reduced = {
3293            let _main = root.gpu.enter_main()?;
3294            root.htod(&vec![0.0f32; output_len])?
3295        };
3296        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3297        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3298            for (block, resident) in blocks.iter().enumerate() {
3299                let global_block = rank * blocks_per_rank + block;
3300                let input = activation_shard(
3301                    activations,
3302                    tokens,
3303                    matrix.in_features,
3304                    PRODUCT_MAX_CARDS,
3305                    global_block,
3306                );
3307                let partial =
3308                    run_resident_bf16_rank(&self.ranks[rank], resident, &input, tokens, None)?;
3309                let next = {
3310                    let _main = root.gpu.enter_main()?;
3311                    let partial = root.htod(&partial)?;
3312                    let mut next = root.uninit(output_len)?;
3313                    root.add(&reduced, &partial, &mut next, output_len)?;
3314                    next
3315                };
3316                reduced = next;
3317            }
3318        }
3319        let _main = root.gpu.enter_main()?;
3320        root.dtoh(&reduced)
3321    }
3322
3323    /// Native-P2P Step row projection with canonical global K-block reduction.
3324    ///
3325    /// The full activation is uploaded once on the root. Each TP8-sized block is peer-scattered
3326    /// to its owning rank, its BF16 partial is peer-returned to the root, and root-device adds
3327    /// replay the same eight-block order as TP1 and the host-staged oracle.
3328    pub fn step_bf16_row_parallel_resident_native(
3329        &self,
3330        matrix: &ResidentStepBf16RowParallel,
3331        activations: &[f32],
3332        tokens: usize,
3333    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3334        if self.ranks.len() > 1 && !self.native_p2p {
3335            return Err("native Step BF16 row parallelism requires P2P ranks".into());
3336        }
3337        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3338        validate_activations(activations, tokens, matrix.in_features)?;
3339        let root = &self.ranks[0];
3340        let root_input = {
3341            let _main = root.gpu.enter_main()?;
3342            root.htod(activations)?
3343        };
3344        // PRODUCER FENCE (2026-08-20 flake fix): the non-bulk arm below peer-reads root_input
3345        // from the other ranks' streams while root's clone_htod may still be in flight.
3346        {
3347            let _main = root.gpu.enter_main()?;
3348            root.stream().synchronize()?;
3349        }
3350        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
3351        let _main = root.gpu.enter_main()?;
3352        root.dtoh(&reduced)
3353    }
3354
3355    /// Device-input twin of [`Self::step_bf16_row_parallel_resident_native`] (lane/
3356    /// hermes-perf-fixes, 2026-08-23): the full activation arrives as a ROOT-DEVICE buffer
3357    /// and the reduced output stays root-resident — no DtoH of the attention output, no
3358    /// host O staging, no re-upload. Byte-identical to the host-canonical arm by
3359    /// construction (same block scatter, kernels, and global TP8 reduction order; the root
3360    /// bytes are dtod-copied where the host arm htod'd the same bytes). Caller must have
3361    /// synchronized the producer stream; the root stream is synchronized before returning.
3362    pub fn step_bf16_row_parallel_resident_native_device(
3363        &self,
3364        matrix: &ResidentStepBf16RowParallel,
3365        root_activation: &CudaSlice<f32>,
3366        tokens: usize,
3367    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3368        if self.ranks.len() > 1 && !self.native_p2p {
3369            return Err("native Step BF16 row parallelism requires P2P ranks".into());
3370        }
3371        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3372        let values = tokens
3373            .checked_mul(matrix.in_features)
3374            .ok_or("device Step BF16 row activation size overflow")?;
3375        let root = &self.ranks[0];
3376        if tokens == 0
3377            || root_activation.len() < values
3378            || root_activation.ordinal() != root.ctx().ordinal()
3379        {
3380            return Err("device Step BF16 row root activation geometry mismatch".into());
3381        }
3382        let root_input = {
3383            let _main = root.gpu.enter_main()?;
3384            let mut root_input = root.uninit(values)?;
3385            root.stream()
3386                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
3387            root.stream().synchronize()?; // producer fence, as the host-input twin
3388            root_input
3389        };
3390        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
3391        let _main = root.gpu.enter_main()?;
3392        root.stream().synchronize()?;
3393        Ok(reduced)
3394    }
3395
3396    /// Shared core of the two native Step row arms above: block scatter + rank GEMMs +
3397    /// canonical global TP8-order root reduction, from a root-resident input, returning the
3398    /// root-resident reduced output. Extracted verbatim so the host and device twins cannot
3399    /// drift numerically.
3400    fn step_bf16_row_native_reduce_from_root(
3401        &self,
3402        matrix: &ResidentStepBf16RowParallel,
3403        root_input: &CudaSlice<f32>,
3404        tokens: usize,
3405    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3406        let root = &self.ranks[0];
3407        let output_len = tokens
3408            .checked_mul(matrix.out_features)
3409            .ok_or("native Step BF16 row output size overflow")?;
3410        let mut reduced = {
3411            let _main = root.gpu.enter_main()?;
3412            root.htod(&vec![0.0f32; output_len])?
3413        };
3414        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3415        let mut block_input_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3416        let mut root_packed_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3417        let mut remote_partial_keepalive = Vec::new();
3418        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3419            for (block, resident) in blocks.iter().enumerate() {
3420                let global_block = rank * blocks_per_rank + block;
3421                let col_start = global_block * matrix.canonical_chunk_cols;
3422                let block_len = tokens
3423                    .checked_mul(matrix.canonical_chunk_cols)
3424                    .ok_or("native Step BF16 row block size overflow")?;
3425                let block_input = if self.bulk_p2p {
3426                    let root_packed = {
3427                        let _main = root.gpu.enter_main()?;
3428                        let mut root_packed = root.uninit(block_len)?;
3429                        root.copy_rows_strided(
3430                            &root_input,
3431                            &mut root_packed,
3432                            matrix.canonical_chunk_cols,
3433                            tokens,
3434                            matrix.in_features,
3435                            col_start,
3436                        )?;
3437                        root_packed
3438                    };
3439                    if rank == 0 {
3440                        root_packed
3441                    } else {
3442                        // PRODUCER FENCE (2026-08-20 flake fix): the pack kernel runs on the
3443                        // root stream; this rank's peer read must not overtake it.
3444                        {
3445                            let _main = root.gpu.enter_main()?;
3446                            root.stream().synchronize()?;
3447                        }
3448                        let engine = &self.ranks[rank];
3449                        let _main = engine.gpu.enter_main()?;
3450                        let mut block_input = engine.uninit(block_len)?;
3451                        engine
3452                            .stream()
3453                            .memcpy_dtod(&root_packed, &mut block_input)?;
3454                        root_packed_keepalive.push(root_packed);
3455                        block_input
3456                    }
3457                } else {
3458                    let engine = &self.ranks[rank];
3459                    let _main = engine.gpu.enter_main()?;
3460                    let mut block_input = engine.uninit(block_len)?;
3461                    for token in 0..tokens {
3462                        let source_start = token * matrix.in_features + col_start;
3463                        let source = root_input
3464                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3465                        let destination_start = token * matrix.canonical_chunk_cols;
3466                        let mut destination = block_input.slice_mut(
3467                            destination_start..destination_start + matrix.canonical_chunk_cols,
3468                        );
3469                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3470                    }
3471                    block_input
3472                };
3473                let partial = run_resident_bf16_rank_device(
3474                    &self.ranks[rank],
3475                    resident,
3476                    &block_input,
3477                    tokens,
3478                    None,
3479                    self.bulk_p2p,
3480                )?;
3481                block_input_keepalive.push(block_input);
3482                let root_partial = if rank == 0 {
3483                    partial
3484                } else {
3485                    // PRODUCER FENCE (2026-08-20 flake fix): the partial was produced by this
3486                    // rank's kernel on its own stream; root's peer read must not overtake it.
3487                    {
3488                        let engine = &self.ranks[rank];
3489                        let _main = engine.gpu.enter_main()?;
3490                        engine.stream().synchronize()?;
3491                    }
3492                    let _main = root.gpu.enter_main()?;
3493                    let mut peer_partial = root.uninit(output_len)?;
3494                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
3495                    remote_partial_keepalive.push(partial);
3496                    peer_partial
3497                };
3498                let next = {
3499                    let _main = root.gpu.enter_main()?;
3500                    let mut next = root.uninit(output_len)?;
3501                    root.add(&reduced, &root_partial, &mut next, output_len)?;
3502                    next
3503                };
3504                reduced = next;
3505            }
3506        }
3507        {
3508            let _main = root.gpu.enter_main()?;
3509            root.stream().synchronize()?;
3510        }
3511        drop(remote_partial_keepalive);
3512        drop(root_packed_keepalive);
3513        drop(block_input_keepalive);
3514        Ok(reduced)
3515    }
3516
3517    /// Reduce rank-local Step attention shards in canonical TP8 K-block order and keep the result
3518    /// on the root device.
3519    pub fn step_bf16_row_parallel_resident_root_device(
3520        &self,
3521        matrix: &ResidentStepBf16RowParallel,
3522        rank_activations: &[CudaSlice<f32>],
3523        tokens: usize,
3524    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3525        if self.ranks.len() > 1 && !self.native_p2p {
3526            return Err(
3527                "device-resident Step BF16 row parallelism requires native P2P ranks".into(),
3528            );
3529        }
3530        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3531        let local_width = matrix.in_features / self.ranks.len();
3532        let shard_len = tokens
3533            .checked_mul(local_width)
3534            .ok_or("device Step BF16 row shard size overflow")?;
3535        if tokens == 0
3536            || rank_activations.len() != self.ranks.len()
3537            || rank_activations
3538                .iter()
3539                .zip(&self.ranks)
3540                .any(|(rows, engine)| {
3541                    rows.len() != shard_len || rows.ordinal() != engine.ctx().ordinal()
3542                })
3543        {
3544            return Err("device Step BF16 row activation shard geometry changed".into());
3545        }
3546
3547        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3548        let mut block_inputs = Vec::with_capacity(self.ranks.len());
3549        let mut partials = Vec::with_capacity(self.ranks.len());
3550        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3551            if blocks.len() != blocks_per_rank {
3552                return Err(format!(
3553                    "device Step BF16 row rank {rank} blocks {} != {blocks_per_rank}",
3554                    blocks.len()
3555                )
3556                .into());
3557            }
3558            let engine = &self.ranks[rank];
3559            let _main = engine.gpu.enter_main()?;
3560            let mut rank_inputs = Vec::with_capacity(blocks_per_rank);
3561            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
3562            for (block, resident) in blocks.iter().enumerate() {
3563                let block_len = tokens
3564                    .checked_mul(matrix.canonical_chunk_cols)
3565                    .ok_or("device Step BF16 row block size overflow")?;
3566                let mut block_input = engine.uninit(block_len)?;
3567                let local_col_start = block * matrix.canonical_chunk_cols;
3568                if self.bulk_p2p {
3569                    engine.copy_rows_strided(
3570                        &rank_activations[rank],
3571                        &mut block_input,
3572                        matrix.canonical_chunk_cols,
3573                        tokens,
3574                        local_width,
3575                        local_col_start,
3576                    )?;
3577                } else {
3578                    for token in 0..tokens {
3579                        let source_start = token * local_width + local_col_start;
3580                        let source = rank_activations[rank]
3581                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3582                        let destination_start = token * matrix.canonical_chunk_cols;
3583                        let mut destination = block_input.slice_mut(
3584                            destination_start..destination_start + matrix.canonical_chunk_cols,
3585                        );
3586                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3587                    }
3588                }
3589                let partial = run_resident_bf16_rank_device(
3590                    engine,
3591                    resident,
3592                    &block_input,
3593                    tokens,
3594                    None,
3595                    self.bulk_p2p,
3596                )?;
3597                rank_inputs.push(block_input);
3598                rank_partials.push(partial);
3599            }
3600            block_inputs.push(rank_inputs);
3601            partials.push(rank_partials);
3602        }
3603        for engine in self.ranks.iter().skip(1) {
3604            let _main = engine.gpu.enter_main()?;
3605            engine.stream().synchronize()?;
3606        }
3607
3608        let output_len = tokens
3609            .checked_mul(matrix.out_features)
3610            .ok_or("device Step BF16 row output size overflow")?;
3611        let root = &self.ranks[0];
3612        let _main = root.gpu.enter_main()?;
3613        let mut reduced = root.htod(&vec![0.0f32; output_len])?;
3614        let mut remote_partials = Vec::new();
3615        for (rank, rank_partials) in partials.into_iter().enumerate() {
3616            for partial in rank_partials {
3617                let root_partial = if rank == 0 {
3618                    partial
3619                } else {
3620                    let mut peer_partial = root.uninit(output_len)?;
3621                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
3622                    remote_partials.push(partial);
3623                    peer_partial
3624                };
3625                let mut next = root.uninit(output_len)?;
3626                root.add(&reduced, &root_partial, &mut next, output_len)?;
3627                reduced = next;
3628            }
3629        }
3630        root.stream().synchronize()?;
3631        drop(remote_partials);
3632        drop(block_inputs);
3633        Ok(reduced)
3634    }
3635
3636    /// Reduce rank-local Step attention shards, then replicate the canonical root result.
3637    pub fn step_bf16_row_parallel_resident_replicated_device(
3638        &self,
3639        matrix: &ResidentStepBf16RowParallel,
3640        rank_activations: &[CudaSlice<f32>],
3641        tokens: usize,
3642    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3643        let reduced =
3644            self.step_bf16_row_parallel_resident_root_device(matrix, rank_activations, tokens)?;
3645        let output_len = tokens
3646            .checked_mul(matrix.out_features)
3647            .ok_or("device Step BF16 row output size overflow")?;
3648        let mut ranks = Vec::with_capacity(self.ranks.len());
3649        ranks.push(reduced);
3650        for engine in self.ranks.iter().skip(1) {
3651            let _main = engine.gpu.enter_main()?;
3652            let mut peer_output = engine.uninit(output_len)?;
3653            engine.stream().memcpy_dtod(&ranks[0], &mut peer_output)?;
3654            ranks.push(peer_output);
3655        }
3656        Ok(ResidentReplicatedDeviceRows {
3657            ranks,
3658            tokens,
3659            width: matrix.out_features,
3660        })
3661    }
3662
3663    pub fn upload_expert(
3664        &self,
3665        gate: E4m3BlockMatrix<'_>,
3666        up: E4m3BlockMatrix<'_>,
3667        down: E4m3BlockMatrix<'_>,
3668    ) -> Result<ResidentTpExpert, Box<dyn std::error::Error>> {
3669        if gate.in_features != up.in_features || gate.out_features != up.out_features {
3670            return Err("TP expert gate/up dimensions differ".into());
3671        }
3672        if down.in_features != gate.out_features || down.out_features != gate.in_features {
3673            return Err(format!(
3674                "TP expert down {}x{} does not invert gate/up {}x{}",
3675                down.out_features, down.in_features, gate.out_features, gate.in_features
3676            )
3677            .into());
3678        }
3679        Ok(ResidentTpExpert {
3680            gate: self.upload_column_parallel(gate)?,
3681            up: self.upload_column_parallel(up)?,
3682            down: self.upload_row_parallel(down)?,
3683            input_width: gate.in_features,
3684            expert_width: gate.out_features,
3685        })
3686    }
3687
3688    pub fn run_expert(
3689        &self,
3690        expert: &ResidentTpExpert,
3691        input: &[f32],
3692        tokens: usize,
3693    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3694        validate_activations(input, tokens, expert.input_width)?;
3695        let gate = self.column_parallel_resident(&expert.gate, input, tokens)?;
3696        let up = self.column_parallel_resident(&expert.up, input, tokens)?;
3697        let activated: Vec<f32> = gate
3698            .gathered
3699            .iter()
3700            .zip(&up.gathered)
3701            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
3702            .collect();
3703        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
3704        Ok(self
3705            .row_parallel_resident(&expert.down, &activated, tokens)?
3706            .reduced)
3707    }
3708
3709    pub fn upload_expert_parallel(
3710        &self,
3711        gate: E4m3ExpertBank<'_>,
3712        up: E4m3ExpertBank<'_>,
3713        down: E4m3ExpertBank<'_>,
3714    ) -> Result<ResidentExpertParallel, Box<dyn std::error::Error>> {
3715        gate.validate()?;
3716        up.validate()?;
3717        down.validate()?;
3718        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
3719            return Err("EP gate/up/down expert counts differ".into());
3720        }
3721        if gate.in_features != up.in_features || gate.out_features != up.out_features {
3722            return Err("EP gate/up dimensions differ".into());
3723        }
3724        if down.in_features != gate.out_features || down.out_features != gate.in_features {
3725            return Err(format!(
3726                "EP down {}x{} does not invert gate/up {}x{}",
3727                down.out_features, down.in_features, gate.out_features, gate.in_features
3728            )
3729            .into());
3730        }
3731        if gate.expert_count % self.ranks.len() != 0 {
3732            return Err(format!(
3733                "EP expert count {} is not divisible by {} ranks",
3734                gate.expert_count,
3735                self.ranks.len()
3736            )
3737            .into());
3738        }
3739
3740        let per_rank = gate.expert_count / self.ranks.len();
3741        let mut ranks = Vec::with_capacity(self.ranks.len());
3742        for (rank, engine) in self.ranks.iter().enumerate() {
3743            let expert_range = rank * per_rank..(rank + 1) * per_rank;
3744            ranks.push(ResidentEpRank {
3745                gate: upload_expert_bank_rank(engine, gate, expert_range.clone())?,
3746                up: upload_expert_bank_rank(engine, up, expert_range.clone())?,
3747                down: upload_expert_bank_rank(engine, down, expert_range)?,
3748            });
3749        }
3750        Ok(ResidentExpertParallel {
3751            ranks,
3752            expert_count: gate.expert_count,
3753            input_width: gate.in_features,
3754            expert_width: gate.out_features,
3755        })
3756    }
3757
3758    /// Prepare the official Step gate-only grouped-FP8 projection oracle on rank zero.
3759    ///
3760    /// This intentionally does not alter the resident EP path. It owns a full rank-local tensor
3761    /// bank solely so the grouped projection can be compared with the existing per-route oracle
3762    /// without routing, transport, or combine changing underneath it.
3763    #[allow(clippy::too_many_arguments)]
3764    pub fn prepare_step_grouped_fp8_gate(
3765        &self,
3766        gate: E4m3ExpertBank<'_>,
3767        up: E4m3ExpertBank<'_>,
3768        down: E4m3ExpertBank<'_>,
3769        input: &[f32],
3770        tokens: usize,
3771        selected: &[usize],
3772        activation_limit: Option<f32>,
3773    ) -> Result<PreparedStepGroupedFp8Gate, Box<dyn std::error::Error>> {
3774        gate.validate()?;
3775        up.validate()?;
3776        down.validate()?;
3777        validate_step_expert_activation_limit(activation_limit)?;
3778        if gate.expert_count != STEP_GROUPED_FP8_EXPERTS
3779            || up.expert_count != STEP_GROUPED_FP8_EXPERTS
3780            || down.expert_count != STEP_GROUPED_FP8_EXPERTS
3781        {
3782            return Err(format!(
3783                "official Step grouped FP8 gate requires {STEP_GROUPED_FP8_EXPERTS} experts, \
3784                 got gate/up/down={}/{}/{}",
3785                gate.expert_count, up.expert_count, down.expert_count,
3786            )
3787            .into());
3788        }
3789        if gate.in_features != up.in_features
3790            || gate.out_features != STEP_GROUPED_FP8_WIDTH
3791            || up.out_features != STEP_GROUPED_FP8_WIDTH
3792            || down.in_features != STEP_GROUPED_FP8_WIDTH
3793            || down.out_features != gate.in_features
3794        {
3795            return Err(format!(
3796                "official Step grouped FP8 geometry gate={}x{} up={}x{} down={}x{}",
3797                gate.out_features,
3798                gate.in_features,
3799                up.out_features,
3800                up.in_features,
3801                down.out_features,
3802                down.in_features,
3803            )
3804            .into());
3805        }
3806        validate_activations(input, tokens, gate.in_features)?;
3807        let pairs = tokens
3808            .checked_mul(STEP_GROUPED_FP8_TOP_K)
3809            .ok_or("official Step grouped FP8 route count overflow")?;
3810        if selected.len() != pairs {
3811            return Err(format!(
3812                "official Step grouped FP8 routes {} != {tokens}x{STEP_GROUPED_FP8_TOP_K} \
3813                 ({pairs})",
3814                selected.len()
3815            )
3816            .into());
3817        }
3818        for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
3819            let mut unique = routes.to_vec();
3820            unique.sort_unstable();
3821            unique.dedup();
3822            if unique.len() != STEP_GROUPED_FP8_TOP_K {
3823                return Err(format!(
3824                    "official Step grouped FP8 token {token} routes are not top-8 unique: \
3825                     {routes:?}"
3826                )
3827                .into());
3828            }
3829        }
3830
3831        let engine = self
3832            .ranks
3833            .first()
3834            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
3835        let _main = engine.gpu.enter_main()?;
3836        let expert_range = 0..STEP_GROUPED_FP8_EXPERTS;
3837        let gate = upload_expert_bank_rank(engine, gate, expert_range.clone())?;
3838        let up = upload_expert_bank_rank(engine, up, expert_range.clone())?;
3839        let down = upload_expert_bank_rank(engine, down, expert_range)?;
3840        let input = engine.htod(input)?;
3841        let route_csr = ExpertCsr::from_token_routes(
3842            STEP_GROUPED_FP8_EXPERTS,
3843            tokens,
3844            STEP_GROUPED_FP8_TOP_K,
3845            selected,
3846        )?
3847        .upload(engine)?;
3848        let pair_rows = (0..pairs).collect::<Vec<_>>();
3849        let down_csr =
3850            ExpertCsr::from_pair_rows(STEP_GROUPED_FP8_EXPERTS, pairs, selected, &pair_rows)?
3851                .upload(engine)?;
3852        let gate_workspace =
3853            Fp8GroupedWorkspace::new(engine, gate.in_features, gate.out_features, tokens, pairs)?;
3854        let up_workspace =
3855            Fp8GroupedWorkspace::new(engine, up.in_features, up.out_features, tokens, pairs)?;
3856        let down_workspace =
3857            Fp8GroupedWorkspace::new(engine, down.in_features, down.out_features, pairs, pairs)?;
3858        let activation = engine.uninit(pairs * STEP_GROUPED_FP8_WIDTH)?;
3859        Ok(PreparedStepGroupedFp8Gate {
3860            device: engine.ctx().ordinal(),
3861            gate,
3862            up,
3863            down,
3864            input,
3865            route_csr,
3866            down_csr,
3867            gate_workspace,
3868            up_workspace,
3869            down_workspace,
3870            activation,
3871            activation_limit,
3872            tokens,
3873            pairs,
3874        })
3875    }
3876
3877    /// Execute one prepared gate/up/activation/down projection sequence on rank zero.
3878    pub fn run_step_grouped_fp8_gate(
3879        &self,
3880        plan: &mut PreparedStepGroupedFp8Gate,
3881    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
3882        let engine = self
3883            .ranks
3884            .first()
3885            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
3886        if engine.ctx().ordinal() != plan.device {
3887            return Err(format!(
3888                "official Step grouped FP8 plan device {} != rank-zero device {}",
3889                plan.device,
3890                engine.ctx().ordinal()
3891            )
3892            .into());
3893        }
3894        let _main = engine.gpu.enter_main()?;
3895
3896        plan.gate_workspace.quantize(engine, &plan.input)?;
3897        plan.gate_workspace.project(
3898            engine,
3899            &plan.gate.codes,
3900            &plan.gate.scales,
3901            &plan.route_csr,
3902            plan.gate.code_stride,
3903            plan.gate.scale_stride,
3904            1.0,
3905        )?;
3906        plan.up_workspace.quantize(engine, &plan.input)?;
3907        plan.up_workspace.project(
3908            engine,
3909            &plan.up.codes,
3910            &plan.up.scales,
3911            &plan.route_csr,
3912            plan.up.code_stride,
3913            plan.up.scale_stride,
3914            1.0,
3915        )?;
3916        if let Some(limit) = plan.activation_limit {
3917            engine.silu_clamped_mul_host_expf(
3918                plan.gate_workspace.output(),
3919                plan.up_workspace.output(),
3920                limit,
3921                &mut plan.activation,
3922                plan.pairs * STEP_GROUPED_FP8_WIDTH,
3923            )?;
3924        } else {
3925            engine.silu_mul_host_expf(
3926                plan.gate_workspace.output(),
3927                plan.up_workspace.output(),
3928                &mut plan.activation,
3929                plan.pairs * STEP_GROUPED_FP8_WIDTH,
3930            )?;
3931        }
3932        plan.down_workspace.quantize(engine, &plan.activation)?;
3933        plan.down_workspace.project(
3934            engine,
3935            &plan.down.codes,
3936            &plan.down.scales,
3937            &plan.down_csr,
3938            plan.down.code_stride,
3939            plan.down.scale_stride,
3940            1.0,
3941        )?;
3942
3943        Ok(StepGroupedFp8ProjectionOutput {
3944            gate: engine.dtoh(plan.gate_workspace.output())?,
3945            up: engine.dtoh(plan.up_workspace.output())?,
3946            down: engine.dtoh(plan.down_workspace.output())?,
3947        })
3948    }
3949
3950    pub fn prepare_step_grouped_expert_parallel_gate(
3951        &self,
3952        experts: &ResidentExpertParallel,
3953        input: &[f32],
3954        tokens: usize,
3955        selected: &[usize],
3956        activation_limit: Option<f32>,
3957    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
3958        self.prepare_step_grouped_expert_parallel_gate_with_capacity(
3959            experts,
3960            input,
3961            tokens,
3962            selected,
3963            activation_limit,
3964            tokens,
3965        )
3966    }
3967
3968    #[allow(clippy::too_many_arguments)]
3969    pub fn prepare_step_grouped_expert_parallel_gate_with_capacity(
3970        &self,
3971        experts: &ResidentExpertParallel,
3972        input: &[f32],
3973        tokens: usize,
3974        selected: &[usize],
3975        activation_limit: Option<f32>,
3976        max_tokens: usize,
3977    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
3978        if !self.native_p2p || !self.ep_device_arithmetic {
3979            return Err(
3980                "Step owner-grouped FP8 requires native P2P and device-resident arithmetic".into(),
3981            );
3982        }
3983        validate_step_expert_activation_limit(activation_limit)?;
3984        validate_ep_residency(&self.ranks, experts)?;
3985        validate_activations(input, tokens, experts.input_width)?;
3986        if max_tokens < tokens || max_tokens > i32::MAX as usize {
3987            return Err(format!(
3988                "official Step owner-grouped FP8 tokens {tokens} exceed capacity {max_tokens}"
3989            )
3990            .into());
3991        }
3992        if experts.expert_count != STEP_GROUPED_FP8_EXPERTS
3993            || experts.expert_width != STEP_GROUPED_FP8_WIDTH
3994        {
3995            return Err(format!(
3996                "official Step owner-grouped FP8 requires {} experts at width {}, got {} at {}",
3997                STEP_GROUPED_FP8_EXPERTS,
3998                STEP_GROUPED_FP8_WIDTH,
3999                experts.expert_count,
4000                experts.expert_width,
4001            )
4002            .into());
4003        }
4004        validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4005        let max_pairs = max_tokens
4006            .checked_mul(STEP_GROUPED_FP8_TOP_K)
4007            .ok_or("official Step owner-grouped FP8 capacity route count overflow")?;
4008        let input_capacity = max_tokens
4009            .checked_mul(experts.input_width)
4010            .ok_or("official Step owner-grouped FP8 input capacity overflow")?;
4011
4012        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
4013        for engine in &self.ranks {
4014            let _main = engine.gpu.enter_main()?;
4015            rank_inputs.push(engine.uninit(input_capacity)?);
4016        }
4017
4018        let mut owners = Vec::with_capacity(self.ranks.len());
4019        for (owner_rank, rank) in experts.ranks.iter().enumerate() {
4020            if rank.gate.expert_range != rank.up.expert_range
4021                || rank.gate.expert_range != rank.down.expert_range
4022            {
4023                return Err(format!(
4024                    "owner-grouped FP8 rank {} gate/up/down expert ranges differ",
4025                    owner_rank
4026                )
4027                .into());
4028            }
4029            let local_experts = rank.gate.expert_range.len();
4030            let engine = &self.ranks[owner_rank];
4031            let _main = engine.gpu.enter_main()?;
4032            let route_csr =
4033                DeviceExpertCsr::with_capacity(engine, local_experts, max_tokens, max_pairs)?;
4034            let down_csr =
4035                DeviceExpertCsr::with_capacity(engine, local_experts, max_pairs, max_pairs)?;
4036            let gate_workspace = Fp8GroupedWorkspace::new(
4037                engine,
4038                experts.input_width,
4039                experts.expert_width,
4040                max_tokens,
4041                max_pairs,
4042            )?;
4043            let up_workspace = Fp8GroupedWorkspace::new(
4044                engine,
4045                experts.input_width,
4046                experts.expert_width,
4047                max_tokens,
4048                max_pairs,
4049            )?;
4050            let down_workspace = Fp8GroupedWorkspace::new(
4051                engine,
4052                experts.expert_width,
4053                experts.input_width,
4054                max_pairs,
4055                max_pairs,
4056            )?;
4057            let activation = engine.uninit(
4058                max_pairs
4059                    .checked_mul(experts.expert_width)
4060                    .ok_or("official Step owner-grouped FP8 activation capacity overflow")?,
4061            )?;
4062            owners.push(PreparedStepGroupedExpertOwner {
4063                rank: owner_rank,
4064                global_pairs: Vec::new(),
4065                route_csr,
4066                down_csr,
4067                gate_workspace,
4068                up_workspace,
4069                down_workspace,
4070                activation,
4071            });
4072        }
4073
4074        let mut plan = PreparedStepGroupedExpertParallelGate {
4075            rank_inputs,
4076            owners,
4077            activation_limit,
4078            tokens: 0,
4079            pairs: 0,
4080            max_tokens,
4081            max_pairs,
4082            input_width: experts.input_width,
4083            expert_width: experts.expert_width,
4084            generation: 0,
4085            executed_generation: None,
4086            ready: false,
4087        };
4088        self.refresh_step_grouped_expert_parallel_gate(
4089            experts, &mut plan, input, tokens, selected,
4090        )?;
4091        Ok(plan)
4092    }
4093
4094    fn prepare_step_grouped_expert_parallel_refresh(
4095        &self,
4096        experts: &ResidentExpertParallel,
4097        plan: &PreparedStepGroupedExpertParallelGate,
4098        tokens: usize,
4099        selected: &[usize],
4100    ) -> Result<(usize, u64, Vec<Option<StepGroupedExpertOwnerSchedule>>), Box<dyn std::error::Error>>
4101    {
4102        validate_ep_residency(&self.ranks, experts)?;
4103        if plan.rank_inputs.len() != self.ranks.len()
4104            || plan.owners.len() != self.ranks.len()
4105            || plan.input_width != experts.input_width
4106            || plan.expert_width != experts.expert_width
4107            || tokens > plan.max_tokens
4108        {
4109            return Err(format!(
4110                "Step owner-grouped FP8 refresh geometry changed ranks={}/{} owners={}/{} \
4111                 input={}/{} expert={}/{} tokens={}/{}",
4112                plan.rank_inputs.len(),
4113                self.ranks.len(),
4114                plan.owners.len(),
4115                self.ranks.len(),
4116                plan.input_width,
4117                experts.input_width,
4118                plan.expert_width,
4119                experts.expert_width,
4120                tokens,
4121                plan.max_tokens,
4122            )
4123            .into());
4124        }
4125        let pairs = validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4126        if pairs > plan.max_pairs {
4127            return Err(format!(
4128                "Step owner-grouped FP8 route count {pairs} exceeds capacity {}",
4129                plan.max_pairs
4130            )
4131            .into());
4132        }
4133        let next_generation = plan
4134            .generation
4135            .checked_add(1)
4136            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4137        let owner_routes = partition_expert_owner_routes(
4138            experts.expert_count,
4139            self.ranks.len(),
4140            tokens,
4141            STEP_GROUPED_FP8_TOP_K,
4142            selected,
4143        )?;
4144        let mut schedules = Vec::with_capacity(self.ranks.len());
4145        for routes in owner_routes {
4146            if routes.selected.is_empty() {
4147                schedules.push(None);
4148                continue;
4149            }
4150            let local_experts = experts.ranks[routes.rank].gate.expert_range.len();
4151            let local_pairs = routes.selected.len();
4152            let route_csr = ExpertCsr::from_pair_rows(
4153                local_experts,
4154                tokens,
4155                &routes.selected,
4156                &routes.token_rows,
4157            )?;
4158            let down_rows = (0..local_pairs).collect::<Vec<_>>();
4159            let down_csr = ExpertCsr::from_pair_rows(
4160                local_experts,
4161                local_pairs,
4162                &routes.selected,
4163                &down_rows,
4164            )?;
4165            schedules.push(Some(StepGroupedExpertOwnerSchedule {
4166                global_pairs: routes.global_pairs,
4167                route_csr,
4168                down_csr,
4169            }));
4170        }
4171        Ok((pairs, next_generation, schedules))
4172    }
4173
4174    fn commit_step_grouped_expert_parallel_refresh(
4175        &self,
4176        plan: &mut PreparedStepGroupedExpertParallelGate,
4177        tokens: usize,
4178        pairs: usize,
4179        next_generation: u64,
4180        schedules: Vec<Option<StepGroupedExpertOwnerSchedule>>,
4181    ) -> Result<(), Box<dyn std::error::Error>> {
4182        for (owner, schedule) in plan.owners.iter_mut().zip(schedules) {
4183            let engine = &self.ranks[owner.rank];
4184            let _main = engine.gpu.enter_main()?;
4185            if let Some(schedule) = schedule {
4186                owner.route_csr.refresh(engine, &schedule.route_csr)?;
4187                owner.down_csr.refresh(engine, &schedule.down_csr)?;
4188                owner.global_pairs = schedule.global_pairs;
4189            } else {
4190                owner.route_csr.clear();
4191                owner.down_csr.clear();
4192                owner.global_pairs.clear();
4193            }
4194        }
4195        plan.tokens = tokens;
4196        plan.pairs = pairs;
4197        plan.generation = next_generation;
4198        plan.ready = true;
4199        Ok(())
4200    }
4201
4202    pub fn refresh_step_grouped_expert_parallel_gate(
4203        &self,
4204        experts: &ResidentExpertParallel,
4205        plan: &mut PreparedStepGroupedExpertParallelGate,
4206        input: &[f32],
4207        tokens: usize,
4208        selected: &[usize],
4209    ) -> Result<(), Box<dyn std::error::Error>> {
4210        validate_activations(input, tokens, experts.input_width)?;
4211        let (pairs, next_generation, schedules) =
4212            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4213
4214        plan.ready = false;
4215        plan.executed_generation = None;
4216        {
4217            let root = &self.ranks[0];
4218            let _main = root.gpu.enter_main()?;
4219            let mut destination = plan.rank_inputs[0].slice_mut(0..input.len());
4220            root.stream().memcpy_htod(input, &mut destination)?;
4221            root.stream().synchronize()?;
4222        }
4223        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4224        let root_input = &root_inputs[0];
4225        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4226            let engine = &self.ranks[rank + 1];
4227            let _main = engine.gpu.enter_main()?;
4228            let mut destination = peer_input.slice_mut(0..input.len());
4229            engine
4230                .stream()
4231                .memcpy_dtod(&root_input.slice(0..input.len()), &mut destination)?;
4232        }
4233        self.commit_step_grouped_expert_parallel_refresh(
4234            plan,
4235            tokens,
4236            pairs,
4237            next_generation,
4238            schedules,
4239        )
4240    }
4241
4242    /// Refresh routes and inputs from an already-resident rank-zero activation.
4243    ///
4244    /// The caller must order the source producer before this call. The root copy is completed
4245    /// before peer dispatch, while CSR and workspace allocations retain their stable addresses.
4246    pub fn refresh_step_grouped_expert_parallel_gate_from_root_device(
4247        &self,
4248        experts: &ResidentExpertParallel,
4249        plan: &mut PreparedStepGroupedExpertParallelGate,
4250        input: &CudaSlice<f32>,
4251        tokens: usize,
4252        selected: &[usize],
4253    ) -> Result<(), Box<dyn std::error::Error>> {
4254        let input_values = tokens
4255            .checked_mul(experts.input_width)
4256            .ok_or("Step owner-grouped FP8 input size overflow")?;
4257        let root = self
4258            .ranks
4259            .first()
4260            .ok_or("Step owner-grouped FP8 runtime has no root rank")?;
4261        if input.len() < input_values || input.ordinal() != root.ctx().ordinal() {
4262            return Err(format!(
4263                "Step owner-grouped FP8 root input len/device {}/{} does not cover {} values on \
4264                 device {}",
4265                input.len(),
4266                input.ordinal(),
4267                input_values,
4268                root.ctx().ordinal(),
4269            )
4270            .into());
4271        }
4272        let (pairs, next_generation, schedules) =
4273            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4274
4275        plan.ready = false;
4276        plan.executed_generation = None;
4277        {
4278            let _main = root.gpu.enter_main()?;
4279            let mut destination = plan.rank_inputs[0].slice_mut(0..input_values);
4280            root.stream()
4281                .memcpy_dtod(&input.slice(0..input_values), &mut destination)?;
4282            root.stream().synchronize()?;
4283        }
4284        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4285        let root_input = &root_inputs[0];
4286        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4287            let engine = &self.ranks[rank + 1];
4288            let _main = engine.gpu.enter_main()?;
4289            let mut destination = peer_input.slice_mut(0..input_values);
4290            engine
4291                .stream()
4292                .memcpy_dtod(&root_input.slice(0..input_values), &mut destination)?;
4293        }
4294        self.commit_step_grouped_expert_parallel_refresh(
4295            plan,
4296            tokens,
4297            pairs,
4298            next_generation,
4299            schedules,
4300        )
4301    }
4302
4303    /// Replace a fixed route plan's rank inputs from an already replicated device batch.
4304    ///
4305    /// Route CSR remains unchanged. Advancing the generation invalidates every prior projection
4306    /// and combine result, so callers must refresh combine metadata before executing again.
4307    pub fn refresh_step_grouped_expert_parallel_inputs_from_replicated(
4308        &self,
4309        experts: &ResidentExpertParallel,
4310        plan: &mut PreparedStepGroupedExpertParallelGate,
4311        input: &ResidentReplicatedDeviceRows,
4312    ) -> Result<(), Box<dyn std::error::Error>> {
4313        validate_ep_residency(&self.ranks, experts)?;
4314        validate_replicated_device_rows(&self.ranks, input)?;
4315        if !plan.ready
4316            || input.tokens != plan.tokens
4317            || input.width != plan.input_width
4318            || input.tokens > plan.max_tokens
4319            || plan.rank_inputs.len() != self.ranks.len()
4320            || plan.owners.len() != self.ranks.len()
4321            || plan.input_width != experts.input_width
4322            || plan.expert_width != experts.expert_width
4323        {
4324            return Err("Step owner-grouped replicated input geometry changed".into());
4325        }
4326        let values = input
4327            .tokens
4328            .checked_mul(input.width)
4329            .ok_or("Step owner-grouped replicated input size overflow")?;
4330        let next_generation = plan
4331            .generation
4332            .checked_add(1)
4333            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4334        plan.ready = false;
4335        plan.executed_generation = None;
4336        for (rank, engine) in self.ranks.iter().enumerate() {
4337            let _main = engine.gpu.enter_main()?;
4338            let mut destination = plan.rank_inputs[rank].slice_mut(0..values);
4339            engine
4340                .stream()
4341                .memcpy_dtod(&input.ranks[rank], &mut destination)?;
4342        }
4343        plan.generation = next_generation;
4344        plan.ready = true;
4345        Ok(())
4346    }
4347
4348    pub fn execute_step_grouped_expert_parallel_gate(
4349        &self,
4350        experts: &ResidentExpertParallel,
4351        plan: &mut PreparedStepGroupedExpertParallelGate,
4352    ) -> Result<(), Box<dyn std::error::Error>> {
4353        validate_ep_residency(&self.ranks, experts)?;
4354        if !plan.ready
4355            || plan.rank_inputs.len() != self.ranks.len()
4356            || plan.owners.len() != self.ranks.len()
4357            || plan.input_width != experts.input_width
4358            || plan.expert_width != experts.expert_width
4359        {
4360            return Err("Step owner-grouped FP8 plan is not ready or its geometry changed".into());
4361        }
4362        plan.executed_generation = None;
4363
4364        for owner in &mut plan.owners {
4365            if owner.global_pairs.is_empty() {
4366                continue;
4367            }
4368            let engine = &self.ranks[owner.rank];
4369            let bank = &experts.ranks[owner.rank];
4370            let _main = engine.gpu.enter_main()?;
4371            let local_pairs = owner.global_pairs.len();
4372            owner.gate_workspace.quantize_for_shape(
4373                engine,
4374                &plan.rank_inputs[owner.rank],
4375                plan.tokens,
4376                local_pairs,
4377            )?;
4378            owner.gate_workspace.project(
4379                engine,
4380                &bank.gate.codes,
4381                &bank.gate.scales,
4382                &owner.route_csr,
4383                bank.gate.code_stride,
4384                bank.gate.scale_stride,
4385                1.0,
4386            )?;
4387            owner.up_workspace.quantize_for_shape(
4388                engine,
4389                &plan.rank_inputs[owner.rank],
4390                plan.tokens,
4391                local_pairs,
4392            )?;
4393            owner.up_workspace.project(
4394                engine,
4395                &bank.up.codes,
4396                &bank.up.scales,
4397                &owner.route_csr,
4398                bank.up.code_stride,
4399                bank.up.scale_stride,
4400                1.0,
4401            )?;
4402        }
4403        for owner in &mut plan.owners {
4404            if owner.global_pairs.is_empty() {
4405                continue;
4406            }
4407            let engine = &self.ranks[owner.rank];
4408            let _main = engine.gpu.enter_main()?;
4409            let values = owner.global_pairs.len() * plan.expert_width;
4410            if let Some(limit) = plan.activation_limit {
4411                engine.silu_clamped_mul_host_expf(
4412                    owner.gate_workspace.output(),
4413                    owner.up_workspace.output(),
4414                    limit,
4415                    &mut owner.activation,
4416                    values,
4417                )?;
4418            } else {
4419                engine.silu_mul_host_expf(
4420                    owner.gate_workspace.output(),
4421                    owner.up_workspace.output(),
4422                    &mut owner.activation,
4423                    values,
4424                )?;
4425            }
4426        }
4427        for owner in &mut plan.owners {
4428            if owner.global_pairs.is_empty() {
4429                continue;
4430            }
4431            let engine = &self.ranks[owner.rank];
4432            let bank = &experts.ranks[owner.rank];
4433            let _main = engine.gpu.enter_main()?;
4434            let local_pairs = owner.global_pairs.len();
4435            owner.down_workspace.quantize_for_shape(
4436                engine,
4437                &owner.activation,
4438                local_pairs,
4439                local_pairs,
4440            )?;
4441            owner.down_workspace.project(
4442                engine,
4443                &bank.down.codes,
4444                &bank.down.scales,
4445                &owner.down_csr,
4446                bank.down.code_stride,
4447                bank.down.scale_stride,
4448                1.0,
4449            )?;
4450        }
4451        plan.executed_generation = Some(plan.generation);
4452        Ok(())
4453    }
4454
4455    pub fn collect_step_grouped_expert_parallel_gate(
4456        &self,
4457        plan: &PreparedStepGroupedExpertParallelGate,
4458    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4459        if !plan.ready || plan.executed_generation != Some(plan.generation) {
4460            return Err("Step owner-grouped FP8 projection is stale or has not executed".into());
4461        }
4462        let mut gate = vec![0.0f32; plan.pairs * plan.expert_width];
4463        let mut up = vec![0.0f32; plan.pairs * plan.expert_width];
4464        let mut down = vec![0.0f32; plan.pairs * plan.input_width];
4465        for owner in &plan.owners {
4466            if owner.global_pairs.is_empty() {
4467                continue;
4468            }
4469            let engine = &self.ranks[owner.rank];
4470            let _main = engine.gpu.enter_main()?;
4471            let owner_gate = engine.dtoh_view(
4472                &owner
4473                    .gate_workspace
4474                    .output()
4475                    .slice(0..owner.gate_workspace.output_len()),
4476            )?;
4477            let owner_up = engine.dtoh_view(
4478                &owner
4479                    .up_workspace
4480                    .output()
4481                    .slice(0..owner.up_workspace.output_len()),
4482            )?;
4483            let owner_down = engine.dtoh_view(
4484                &owner
4485                    .down_workspace
4486                    .output()
4487                    .slice(0..owner.down_workspace.output_len()),
4488            )?;
4489            for (local_pair, &global_pair) in owner.global_pairs.iter().enumerate() {
4490                let local_expert = local_pair * plan.expert_width;
4491                let global_expert = global_pair * plan.expert_width;
4492                gate[global_expert..global_expert + plan.expert_width]
4493                    .copy_from_slice(&owner_gate[local_expert..local_expert + plan.expert_width]);
4494                up[global_expert..global_expert + plan.expert_width]
4495                    .copy_from_slice(&owner_up[local_expert..local_expert + plan.expert_width]);
4496
4497                let local_hidden = local_pair * plan.input_width;
4498                let global_hidden = global_pair * plan.input_width;
4499                down[global_hidden..global_hidden + plan.input_width]
4500                    .copy_from_slice(&owner_down[local_hidden..local_hidden + plan.input_width]);
4501            }
4502        }
4503        Ok(StepGroupedFp8ProjectionOutput { gate, up, down })
4504    }
4505
4506    pub fn run_step_grouped_expert_parallel_gate(
4507        &self,
4508        experts: &ResidentExpertParallel,
4509        plan: &mut PreparedStepGroupedExpertParallelGate,
4510    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4511        self.execute_step_grouped_expert_parallel_gate(experts, plan)?;
4512        self.collect_step_grouped_expert_parallel_gate(plan)
4513    }
4514
4515    pub fn prepare_step_grouped_expert_parallel_combine(
4516        &self,
4517        plan: &PreparedStepGroupedExpertParallelGate,
4518        route_weights: &[f32],
4519    ) -> Result<PreparedPeerWeightedRouteCombine, Box<dyn std::error::Error>> {
4520        if !self.native_p2p || !self.ep_device_arithmetic || !plan.ready {
4521            return Err(
4522                "Step owner-grouped combine requires a ready native-P2P device plan".into(),
4523            );
4524        }
4525        let owner_pairs = plan
4526            .owners
4527            .iter()
4528            .map(|owner| owner.global_pairs.as_slice())
4529            .collect::<Vec<_>>();
4530        let shape = validate_weighted_route_combine(
4531            plan.input_width,
4532            STEP_GROUPED_FP8_TOP_K,
4533            plan.max_tokens,
4534            plan.tokens,
4535            &owner_pairs,
4536            route_weights,
4537        )?;
4538        if shape.max_pairs != plan.max_pairs {
4539            return Err(format!(
4540                "Step owner-grouped combine capacity {} != projection capacity {}",
4541                shape.max_pairs, plan.max_pairs
4542            )
4543            .into());
4544        }
4545        let root = self
4546            .ranks
4547            .first()
4548            .ok_or("Step owner-grouped combine has no root rank")?;
4549        let slot_values = shape
4550            .max_pairs
4551            .checked_mul(plan.input_width)
4552            .ok_or("Step owner-grouped combine slot capacity overflow")?;
4553        let output_values = plan
4554            .max_tokens
4555            .checked_mul(plan.input_width)
4556            .ok_or("Step owner-grouped combine output capacity overflow")?;
4557        let (root_device, owners, peer_staging, slots, weights, output) = {
4558            let _main = root.gpu.enter_main()?;
4559            let mut owners = Vec::with_capacity(plan.owners.len());
4560            for _ in &plan.owners {
4561                owners.push(PreparedPeerWeightedRouteOwner {
4562                    token_rows: root.htod_i32(&vec![0; shape.max_pairs])?,
4563                    slots: root.htod_i32(&vec![0; shape.max_pairs])?,
4564                    weights: root.htod(&vec![0.0; shape.max_pairs])?,
4565                    active_pairs: 0,
4566                });
4567            }
4568            (
4569                root.ctx().ordinal(),
4570                owners,
4571                root.uninit(slot_values)?,
4572                root.uninit(slot_values)?,
4573                root.uninit(shape.max_pairs)?,
4574                root.uninit(output_values)?,
4575            )
4576        };
4577        let mut peer_devices = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4578        let mut peer_outputs = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4579        for engine in self.ranks.iter().skip(1) {
4580            let _main = engine.gpu.enter_main()?;
4581            peer_devices.push(engine.ctx().ordinal());
4582            peer_outputs.push(engine.uninit(output_values)?);
4583        }
4584        let mut combine = PreparedPeerWeightedRouteCombine {
4585            root_device,
4586            owners,
4587            peer_staging,
4588            slots,
4589            weights,
4590            output,
4591            peer_devices,
4592            peer_outputs,
4593            width: plan.input_width,
4594            experts_per_token: STEP_GROUPED_FP8_TOP_K,
4595            max_tokens: plan.max_tokens,
4596            max_pairs: shape.max_pairs,
4597            tokens: 0,
4598            pairs: 0,
4599            projection_generation: 0,
4600            output_generation: None,
4601            broadcast_generation: None,
4602            ready: false,
4603        };
4604        self.refresh_step_grouped_expert_parallel_combine(plan, &mut combine, route_weights)?;
4605        Ok(combine)
4606    }
4607
4608    pub fn refresh_step_grouped_expert_parallel_combine(
4609        &self,
4610        plan: &PreparedStepGroupedExpertParallelGate,
4611        combine: &mut PreparedPeerWeightedRouteCombine,
4612        route_weights: &[f32],
4613    ) -> Result<(), Box<dyn std::error::Error>> {
4614        let output_capacity = combine
4615            .max_tokens
4616            .checked_mul(combine.width)
4617            .ok_or("Step owner-grouped combine output capacity overflow")?;
4618        if !plan.ready
4619            || combine.owners.len() != plan.owners.len()
4620            || combine.peer_devices.len() + 1 != self.ranks.len()
4621            || combine.peer_outputs.len() + 1 != self.ranks.len()
4622            || combine.width != plan.input_width
4623            || combine.experts_per_token != STEP_GROUPED_FP8_TOP_K
4624            || combine.max_tokens != plan.max_tokens
4625            || combine.max_pairs != plan.max_pairs
4626            || combine.output.len() < output_capacity
4627            || combine
4628                .peer_outputs
4629                .iter()
4630                .any(|output| output.len() < output_capacity)
4631        {
4632            return Err("Step owner-grouped combine/projection geometry changed".into());
4633        }
4634        if self
4635            .ranks
4636            .iter()
4637            .skip(1)
4638            .zip(&combine.peer_devices)
4639            .any(|(engine, &device)| engine.ctx().ordinal() != device)
4640        {
4641            return Err("Step owner-grouped combine peer devices changed".into());
4642        }
4643        let owner_pairs = plan
4644            .owners
4645            .iter()
4646            .map(|owner| owner.global_pairs.as_slice())
4647            .collect::<Vec<_>>();
4648        let shape = validate_weighted_route_combine(
4649            combine.width,
4650            combine.experts_per_token,
4651            combine.max_tokens,
4652            plan.tokens,
4653            &owner_pairs,
4654            route_weights,
4655        )?;
4656        if shape.max_pairs != combine.max_pairs {
4657            return Err("Step owner-grouped combine capacity changed during refresh".into());
4658        }
4659        let metadata = owner_pairs
4660            .iter()
4661            .map(|pairs| {
4662                let token_rows = pairs
4663                    .iter()
4664                    .map(|&pair| (pair / combine.experts_per_token) as i32)
4665                    .collect::<Vec<_>>();
4666                let slots = pairs
4667                    .iter()
4668                    .map(|&pair| (pair % combine.experts_per_token) as i32)
4669                    .collect::<Vec<_>>();
4670                let weights = pairs
4671                    .iter()
4672                    .map(|&pair| route_weights[pair])
4673                    .collect::<Vec<_>>();
4674                (token_rows, slots, weights)
4675            })
4676            .collect::<Vec<_>>();
4677
4678        combine.ready = false;
4679        combine.output_generation = None;
4680        combine.broadcast_generation = None;
4681        let root = self
4682            .ranks
4683            .first()
4684            .ok_or("Step owner-grouped combine has no root rank")?;
4685        let _main = root.gpu.enter_main()?;
4686        if root.ctx().ordinal() != combine.root_device {
4687            return Err(format!(
4688                "Step owner-grouped combine root device changed {} != {}",
4689                root.ctx().ordinal(),
4690                combine.root_device
4691            )
4692            .into());
4693        }
4694        for (owner, (token_rows, slots, weights)) in combine.owners.iter_mut().zip(metadata) {
4695            if token_rows.is_empty() {
4696                owner.active_pairs = 0;
4697                continue;
4698            }
4699            root.htod_i32_into(&mut owner.token_rows, &token_rows)?;
4700            root.htod_i32_into(&mut owner.slots, &slots)?;
4701            let mut weight_prefix = owner.weights.slice_mut(0..weights.len());
4702            root.stream().memcpy_htod(&weights, &mut weight_prefix)?;
4703            owner.active_pairs = token_rows.len();
4704        }
4705        combine.tokens = plan.tokens;
4706        combine.pairs = shape.pairs;
4707        combine.projection_generation = plan.generation;
4708        combine.ready = true;
4709        Ok(())
4710    }
4711
4712    pub fn execute_step_grouped_expert_parallel_combine(
4713        &self,
4714        plan: &PreparedStepGroupedExpertParallelGate,
4715        combine: &mut PreparedPeerWeightedRouteCombine,
4716    ) -> Result<(), Box<dyn std::error::Error>> {
4717        if !plan.ready
4718            || plan.executed_generation != Some(plan.generation)
4719            || !combine.ready
4720            || combine.tokens != plan.tokens
4721            || combine.pairs != plan.pairs
4722            || combine.width != plan.input_width
4723            || combine.owners.len() != plan.owners.len()
4724            || combine.projection_generation != plan.generation
4725        {
4726            return Err("Step owner-grouped combine is stale or its geometry changed".into());
4727        }
4728        combine.output_generation = None;
4729        combine.broadcast_generation = None;
4730        for owner in &plan.owners {
4731            if owner.rank == 0 || owner.global_pairs.is_empty() {
4732                continue;
4733            }
4734            let engine = &self.ranks[owner.rank];
4735            let _main = engine.gpu.enter_main()?;
4736            engine.stream().synchronize()?;
4737        }
4738        let root = self
4739            .ranks
4740            .first()
4741            .ok_or("Step owner-grouped combine has no root rank")?;
4742        let _main = root.gpu.enter_main()?;
4743        if root.ctx().ordinal() != combine.root_device {
4744            return Err("Step owner-grouped combine is not resident on the root device".into());
4745        }
4746        for (index, owner) in plan.owners.iter().enumerate() {
4747            let metadata = &combine.owners[index];
4748            if owner.global_pairs.len() != metadata.active_pairs {
4749                return Err(format!(
4750                    "Step owner-grouped combine owner {index} rows {} != metadata {}",
4751                    owner.global_pairs.len(),
4752                    metadata.active_pairs
4753                )
4754                .into());
4755            }
4756            if metadata.active_pairs == 0 {
4757                continue;
4758            }
4759            let values = metadata
4760                .active_pairs
4761                .checked_mul(combine.width)
4762                .ok_or("Step owner-grouped combine peer value count overflow")?;
4763            if owner.rank == 0 {
4764                root.scatter_slot(
4765                    owner.down_workspace.output(),
4766                    &metadata.token_rows,
4767                    &metadata.slots,
4768                    &metadata.weights,
4769                    &mut combine.slots,
4770                    &mut combine.weights,
4771                    combine.width,
4772                    combine.experts_per_token,
4773                    metadata.active_pairs,
4774                )?;
4775            } else {
4776                let source = owner.down_workspace.output().slice(0..values);
4777                let mut destination = combine.peer_staging.slice_mut(0..values);
4778                root.stream().memcpy_dtod(&source, &mut destination)?;
4779                root.scatter_slot(
4780                    &combine.peer_staging,
4781                    &metadata.token_rows,
4782                    &metadata.slots,
4783                    &metadata.weights,
4784                    &mut combine.slots,
4785                    &mut combine.weights,
4786                    combine.width,
4787                    combine.experts_per_token,
4788                    metadata.active_pairs,
4789                )?;
4790            }
4791        }
4792        root.reduce_slots_host(
4793            &combine.slots,
4794            &combine.weights,
4795            &mut combine.output,
4796            combine.width,
4797            combine.experts_per_token,
4798            combine.tokens,
4799        )?;
4800        combine.output_generation = Some(plan.generation);
4801        Ok(())
4802    }
4803
4804    pub fn collect_step_grouped_expert_parallel_combine(
4805        &self,
4806        plan: &PreparedStepGroupedExpertParallelGate,
4807        combine: &PreparedPeerWeightedRouteCombine,
4808    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4809        if !plan.ready
4810            || combine.output_generation != Some(plan.generation)
4811            || combine.projection_generation != plan.generation
4812        {
4813            return Err("Step owner-grouped combine output is stale or has not executed".into());
4814        }
4815        let root = self
4816            .ranks
4817            .first()
4818            .ok_or("Step owner-grouped combine has no root rank")?;
4819        let _main = root.gpu.enter_main()?;
4820        if root.ctx().ordinal() != combine.root_device {
4821            return Err("Step owner-grouped combine is not resident on the root device".into());
4822        }
4823        root.dtoh_view(&combine.output.slice(0..combine.tokens * combine.width))
4824    }
4825
4826    /// Copy the active root combine result into a caller-owned engine on the same CUDA device.
4827    ///
4828    /// The persistent combine buffer remains reusable by the next route generation; the returned
4829    /// allocation follows the serving runtime's ordinary transient-output ownership.
4830    pub fn copy_step_grouped_expert_parallel_combine_root(
4831        &self,
4832        plan: &PreparedStepGroupedExpertParallelGate,
4833        combine: &PreparedPeerWeightedRouteCombine,
4834        destination: &Engine,
4835    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
4836        if !plan.ready
4837            || combine.output_generation != Some(plan.generation)
4838            || combine.projection_generation != plan.generation
4839        {
4840            return Err("Step owner-grouped combine output is stale or has not executed".into());
4841        }
4842        let root = self
4843            .ranks
4844            .first()
4845            .ok_or("Step owner-grouped combine has no root rank")?;
4846        if root.ctx().ordinal() != combine.root_device
4847            || destination.ctx().ordinal() != combine.root_device
4848        {
4849            return Err(format!(
4850                "Step owner-grouped combine root/destination devices {}/{} != {}",
4851                root.ctx().ordinal(),
4852                destination.ctx().ordinal(),
4853                combine.root_device,
4854            )
4855            .into());
4856        }
4857        let values = combine
4858            .tokens
4859            .checked_mul(combine.width)
4860            .ok_or("Step owner-grouped combine copy size overflow")?;
4861        {
4862            let _main = root.gpu.enter_main()?;
4863            root.stream().synchronize()?;
4864        }
4865        let _main = destination.gpu.enter_main()?;
4866        let mut output = destination.uninit(values)?;
4867        destination
4868            .stream()
4869            .memcpy_dtod(&combine.output.slice(0..values), &mut output)?;
4870        Ok(output)
4871    }
4872
4873    pub fn broadcast_step_grouped_expert_parallel_combine(
4874        &self,
4875        plan: &PreparedStepGroupedExpertParallelGate,
4876        combine: &mut PreparedPeerWeightedRouteCombine,
4877    ) -> Result<(), Box<dyn std::error::Error>> {
4878        if !plan.ready
4879            || combine.output_generation != Some(plan.generation)
4880            || combine.projection_generation != plan.generation
4881            || combine.peer_devices.len() + 1 != self.ranks.len()
4882            || combine.peer_outputs.len() + 1 != self.ranks.len()
4883        {
4884            return Err("Step owner-grouped combine output cannot be broadcast".into());
4885        }
4886        combine.broadcast_generation = None;
4887        let values = combine
4888            .tokens
4889            .checked_mul(combine.width)
4890            .ok_or("Step owner-grouped combine broadcast size overflow")?;
4891        {
4892            let root = self
4893                .ranks
4894                .first()
4895                .ok_or("Step owner-grouped combine has no root rank")?;
4896            let _main = root.gpu.enter_main()?;
4897            if root.ctx().ordinal() != combine.root_device {
4898                return Err("Step owner-grouped combine root device changed".into());
4899            }
4900            root.stream().synchronize()?;
4901        }
4902        let source = &combine.output;
4903        for (index, destination_buffer) in combine.peer_outputs.iter_mut().enumerate() {
4904            let engine = &self.ranks[index + 1];
4905            let _main = engine.gpu.enter_main()?;
4906            if engine.ctx().ordinal() != combine.peer_devices[index] {
4907                return Err(format!(
4908                    "Step owner-grouped combine peer {} device changed",
4909                    index + 1
4910                )
4911                .into());
4912            }
4913            let mut destination = destination_buffer.slice_mut(0..values);
4914            engine
4915                .stream()
4916                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
4917        }
4918        combine.broadcast_generation = Some(plan.generation);
4919        Ok(())
4920    }
4921
4922    pub fn collect_step_grouped_expert_parallel_broadcast(
4923        &self,
4924        plan: &PreparedStepGroupedExpertParallelGate,
4925        combine: &PreparedPeerWeightedRouteCombine,
4926    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
4927        if !plan.ready
4928            || combine.output_generation != Some(plan.generation)
4929            || combine.broadcast_generation != Some(plan.generation)
4930            || combine.peer_outputs.len() + 1 != self.ranks.len()
4931        {
4932            return Err("Step owner-grouped combine broadcast is stale or incomplete".into());
4933        }
4934        let values = combine
4935            .tokens
4936            .checked_mul(combine.width)
4937            .ok_or("Step owner-grouped combine collection size overflow")?;
4938        let mut outputs = Vec::with_capacity(self.ranks.len());
4939        {
4940            let root = &self.ranks[0];
4941            let _main = root.gpu.enter_main()?;
4942            outputs.push(root.dtoh_view(&combine.output.slice(0..values))?);
4943        }
4944        for (index, output) in combine.peer_outputs.iter().enumerate() {
4945            let engine = &self.ranks[index + 1];
4946            let _main = engine.gpu.enter_main()?;
4947            outputs.push(engine.dtoh_view(&output.slice(0..values))?);
4948        }
4949        Ok(outputs)
4950    }
4951
4952    /// Add routed and replicated shared-expert outputs, then add the attention residual.
4953    pub fn finish_step_grouped_expert_parallel_layer(
4954        &self,
4955        plan: &PreparedStepGroupedExpertParallelGate,
4956        combine: &PreparedPeerWeightedRouteCombine,
4957        shared: &ResidentReplicatedDeviceRows,
4958        residual: &ResidentReplicatedDeviceRows,
4959    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
4960        validate_replicated_device_rows(&self.ranks, shared)?;
4961        validate_replicated_device_rows(&self.ranks, residual)?;
4962        if !plan.ready
4963            || plan.executed_generation != Some(plan.generation)
4964            || combine.output_generation != Some(plan.generation)
4965            || combine.broadcast_generation != Some(plan.generation)
4966            || combine.projection_generation != plan.generation
4967            || combine.peer_outputs.len() + 1 != self.ranks.len()
4968            || shared.tokens != combine.tokens
4969            || residual.tokens != combine.tokens
4970            || shared.width != combine.width
4971            || residual.width != combine.width
4972        {
4973            return Err("Step full-layer finish inputs are stale or their geometry changed".into());
4974        }
4975        let values = combine
4976            .tokens
4977            .checked_mul(combine.width)
4978            .ok_or("Step full-layer output size overflow")?;
4979        let mut ranks = Vec::with_capacity(self.ranks.len());
4980        for rank in 0..self.ranks.len() {
4981            let engine = &self.ranks[rank];
4982            let _main = engine.gpu.enter_main()?;
4983            let routed = if rank == 0 {
4984                &combine.output
4985            } else {
4986                &combine.peer_outputs[rank - 1]
4987            };
4988            let mut ffn = engine.uninit(values)?;
4989            engine.add(routed, &shared.ranks[rank], &mut ffn, values)?;
4990            let mut output = engine.uninit(values)?;
4991            engine.add(&residual.ranks[rank], &ffn, &mut output, values)?;
4992            ranks.push(output);
4993        }
4994        Ok(ResidentReplicatedDeviceRows {
4995            ranks,
4996            tokens: combine.tokens,
4997            width: combine.width,
4998        })
4999    }
5000
5001    pub fn run_step_grouped_expert_parallel_combine(
5002        &self,
5003        plan: &PreparedStepGroupedExpertParallelGate,
5004        combine: &mut PreparedPeerWeightedRouteCombine,
5005    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5006        self.execute_step_grouped_expert_parallel_combine(plan, combine)?;
5007        self.collect_step_grouped_expert_parallel_combine(plan, combine)
5008    }
5009
5010    pub fn upload_tensor_parallel(
5011        &self,
5012        gate: E4m3ExpertBank<'_>,
5013        up: E4m3ExpertBank<'_>,
5014        down: E4m3ExpertBank<'_>,
5015    ) -> Result<ResidentTensorParallel, Box<dyn std::error::Error>> {
5016        gate.validate()?;
5017        up.validate()?;
5018        down.validate()?;
5019        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
5020            return Err("TP gate/up/down expert counts differ".into());
5021        }
5022        if gate.in_features != up.in_features || gate.out_features != up.out_features {
5023            return Err("TP gate/up dimensions differ".into());
5024        }
5025        if down.in_features != gate.out_features || down.out_features != gate.in_features {
5026            return Err(format!(
5027                "TP down {}x{} does not invert gate/up {}x{}",
5028                down.out_features, down.in_features, gate.out_features, gate.in_features
5029            )
5030            .into());
5031        }
5032        let tp = self.ranks.len();
5033        validate_column_bank_shape(gate, tp)?;
5034        validate_column_bank_shape(up, tp)?;
5035        validate_row_bank_shape(down, tp)?;
5036
5037        let mut gate_ranks = Vec::with_capacity(tp);
5038        let mut up_ranks = Vec::with_capacity(tp);
5039        let mut down_ranks = Vec::with_capacity(tp);
5040        for (rank, engine) in self.ranks.iter().enumerate() {
5041            gate_ranks.push(upload_column_bank_rank(engine, gate, tp, rank)?);
5042            up_ranks.push(upload_column_bank_rank(engine, up, tp, rank)?);
5043            down_ranks.push(upload_row_bank_rank(engine, down, tp, rank)?);
5044        }
5045        Ok(ResidentTensorParallel {
5046            bank: ResidentTpExpertBank {
5047                gate: gate_ranks,
5048                up: up_ranks,
5049                down: down_ranks,
5050                expert_count: gate.expert_count,
5051                input_width: gate.in_features,
5052                expert_width: gate.out_features,
5053            },
5054        })
5055    }
5056
5057    pub fn run_tensor_parallel_routes(
5058        &self,
5059        experts: &ResidentTensorParallel,
5060        input: &[f32],
5061        tokens: usize,
5062        selected: &[usize],
5063        route_weights: &[f32],
5064        experts_per_token: usize,
5065    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5066        validate_tp_bank_residency(&self.ranks, &experts.bank)?;
5067        validate_activations(input, tokens, experts.bank.input_width)?;
5068        let pairs = tokens
5069            .checked_mul(experts_per_token)
5070            .ok_or("TP route count overflow")?;
5071        if selected.len() != pairs || route_weights.len() != pairs {
5072            return Err(format!(
5073                "TP routes selected={} weights={} != tokens {tokens} x experts/token \
5074                 {experts_per_token} ({pairs})",
5075                selected.len(),
5076                route_weights.len(),
5077            )
5078            .into());
5079        }
5080        if !route_weights.iter().all(|weight| weight.is_finite()) {
5081            return Err("TP route weights contain a non-finite value".into());
5082        }
5083
5084        let mut output = vec![0.0f32; tokens * experts.bank.input_width];
5085        for token in 0..tokens {
5086            let input_row =
5087                &input[token * experts.bank.input_width..(token + 1) * experts.bank.input_width];
5088            for slot in 0..experts_per_token {
5089                let pair = token * experts_per_token + slot;
5090                let expert = selected[pair];
5091                if expert >= experts.bank.expert_count {
5092                    return Err(format!(
5093                        "TP selected expert {expert} outside 0..{}",
5094                        experts.bank.expert_count
5095                    )
5096                    .into());
5097                }
5098                let down = if self.native_p2p {
5099                    self.run_tensor_parallel_expert_native(&experts.bank, expert, input_row)?
5100                } else {
5101                    let gate =
5102                        self.run_column_bank_expert(&experts.bank.gate, expert, input_row)?;
5103                    let up = self.run_column_bank_expert(&experts.bank.up, expert, input_row)?;
5104                    let activated: Vec<f32> = gate
5105                        .iter()
5106                        .zip(&up)
5107                        .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5108                        .collect();
5109                    debug_assert_eq!(activated.len(), experts.bank.expert_width);
5110                    self.run_row_bank_expert(&experts.bank.down, expert, &activated)?
5111                };
5112                let weight = route_weights[pair];
5113                for (sum, value) in output
5114                    [token * experts.bank.input_width..(token + 1) * experts.bank.input_width]
5115                    .iter_mut()
5116                    .zip(down)
5117                {
5118                    *sum += weight * value;
5119                }
5120            }
5121        }
5122        Ok(output)
5123    }
5124
5125    fn run_column_bank_expert(
5126        &self,
5127        ranks: &[ResidentE4m3ExpertBankRank],
5128        expert: usize,
5129        input: &[f32],
5130    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5131        let local_out = ranks
5132            .first()
5133            .ok_or("TP column bank has no ranks")?
5134            .out_features;
5135        let mut gathered = vec![0.0f32; local_out * ranks.len()];
5136        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5137            let shard = run_resident_bank_expert(engine, bank, expert, input, 1)?;
5138            gathered[rank * local_out..(rank + 1) * local_out].copy_from_slice(&shard);
5139        }
5140        Ok(gathered)
5141    }
5142
5143    fn run_row_bank_expert(
5144        &self,
5145        ranks: &[ResidentE4m3ExpertBankRank],
5146        expert: usize,
5147        input: &[f32],
5148    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5149        let local_in = ranks.first().ok_or("TP row bank has no ranks")?.in_features;
5150        if input.len() != local_in * ranks.len() {
5151            return Err(format!(
5152                "TP row input {} != {} ranks x {local_in}",
5153                input.len(),
5154                ranks.len()
5155            )
5156            .into());
5157        }
5158        let out_features = ranks[0].out_features;
5159        let mut reduced = vec![0.0f32; out_features];
5160        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5161            let blocks = bank
5162                .k_blocks
5163                .ok_or("TP row bank is not packed in native K-block order")?;
5164            if blocks * FP8_BLOCK != local_in {
5165                return Err(format!(
5166                    "TP row bank has {blocks} blocks but local input width is {local_in}"
5167                )
5168                .into());
5169            }
5170            for block in 0..blocks {
5171                let global_start = rank * local_in + block * FP8_BLOCK;
5172                let partial = run_resident_bank_expert_block(
5173                    engine,
5174                    bank,
5175                    expert,
5176                    block,
5177                    &input[global_start..global_start + FP8_BLOCK],
5178                )?;
5179                for (sum, value) in reduced.iter_mut().zip(partial) {
5180                    *sum += value;
5181                }
5182            }
5183        }
5184        Ok(reduced)
5185    }
5186
5187    fn run_tensor_parallel_expert_native(
5188        &self,
5189        bank: &ResidentTpExpertBank,
5190        expert: usize,
5191        input: &[f32],
5192    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5193        if !self.native_p2p || self.ranks.len() < 2 {
5194            return Err("native TP expert execution requires at least two P2P ranks".into());
5195        }
5196        let local_out = bank
5197            .gate
5198            .first()
5199            .ok_or("native TP gate bank has no ranks")?
5200            .out_features;
5201        if local_out * self.ranks.len() != bank.expert_width {
5202            return Err(format!(
5203                "native TP gate shards {}x{local_out} != expert width {}",
5204                self.ranks.len(),
5205                bank.expert_width
5206            )
5207            .into());
5208        }
5209
5210        // The caller's routed input is already host-canonical. Upload once on rank zero, then
5211        // broadcast over peer copies so no other rank receives a host-staged duplicate.
5212        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
5213        let root_input = {
5214            let root = &self.ranks[0];
5215            let _main = root.gpu.enter_main()?;
5216            root.htod(input)?
5217        };
5218        rank_inputs.push(root_input);
5219        for engine in &self.ranks[1..] {
5220            let peer_input = {
5221                let _main = engine.gpu.enter_main()?;
5222                let mut peer_input = engine.uninit(input.len())?;
5223                engine
5224                    .stream()
5225                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
5226                peer_input
5227            };
5228            rank_inputs.push(peer_input);
5229        }
5230
5231        let mut gate_shards = Vec::with_capacity(self.ranks.len());
5232        let mut up_shards = Vec::with_capacity(self.ranks.len());
5233        for rank in 0..self.ranks.len() {
5234            gate_shards.push(run_resident_bank_expert_device(
5235                &self.ranks[rank],
5236                &bank.gate[rank],
5237                expert,
5238                &rank_inputs[rank],
5239                1,
5240            )?);
5241            up_shards.push(run_resident_bank_expert_device(
5242                &self.ranks[rank],
5243                &bank.up[rank],
5244                expert,
5245                &rank_inputs[rank],
5246                1,
5247            )?);
5248        }
5249
5250        // Preserve the established canonical activation program for the first native transport
5251        // milestone. The shards move to rank zero over P2P; only the scalar activation expression
5252        // executes on host. A later device-activation increment must earn its own exactness gate.
5253        let gate = self.gather_native_column_shards(&gate_shards, 1, local_out)?;
5254        let up = self.gather_native_column_shards(&up_shards, 1, local_out)?;
5255        let activated = gate
5256            .iter()
5257            .zip(&up)
5258            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5259            .collect::<Vec<_>>();
5260        debug_assert_eq!(activated.len(), bank.expert_width);
5261
5262        let root_activated = {
5263            let root = &self.ranks[0];
5264            let _main = root.gpu.enter_main()?;
5265            root.htod(&activated)?
5266        };
5267        let mut rank_activated = Vec::with_capacity(self.ranks.len());
5268        for (rank, engine) in self.ranks.iter().enumerate() {
5269            let start = rank * local_out;
5270            let source = root_activated.slice(start..start + local_out);
5271            let local = {
5272                let _main = engine.gpu.enter_main()?;
5273                let mut local = engine.uninit(local_out)?;
5274                engine.stream().memcpy_dtod(&source, &mut local)?;
5275                local
5276            };
5277            rank_activated.push(local);
5278        }
5279
5280        let out_features = bank
5281            .down
5282            .first()
5283            .ok_or("native TP down bank has no ranks")?
5284            .out_features;
5285        let mut reduced = {
5286            let root = &self.ranks[0];
5287            let _main = root.gpu.enter_main()?;
5288            root.htod(&vec![0.0f32; out_features])?
5289        };
5290        let mut remote_partial_keepalive = Vec::new();
5291        for rank in 0..self.ranks.len() {
5292            let down = &bank.down[rank];
5293            let blocks = down
5294                .k_blocks
5295                .ok_or("native TP row bank is not packed in checkpoint-block order")?;
5296            if blocks * FP8_BLOCK != local_out {
5297                return Err(format!(
5298                    "native TP rank {rank} has {blocks} blocks but local activation width is \
5299                     {local_out}"
5300                )
5301                .into());
5302            }
5303            for block in 0..blocks {
5304                let start = block * FP8_BLOCK;
5305                let input_block = rank_activated[rank].slice(start..start + FP8_BLOCK);
5306                let partial = run_resident_bank_expert_block_device(
5307                    &self.ranks[rank],
5308                    down,
5309                    expert,
5310                    block,
5311                    &input_block,
5312                )?;
5313                let root_partial = if rank == 0 {
5314                    partial
5315                } else {
5316                    let root = &self.ranks[0];
5317                    let _main = root.gpu.enter_main()?;
5318                    let mut peer_partial = root.uninit(out_features)?;
5319                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
5320                    remote_partial_keepalive.push(partial);
5321                    peer_partial
5322                };
5323                let next = {
5324                    let root = &self.ranks[0];
5325                    let _main = root.gpu.enter_main()?;
5326                    let mut next = root.uninit(out_features)?;
5327                    root.add(&reduced, &root_partial, &mut next, out_features)?;
5328                    next
5329                };
5330                reduced = next;
5331            }
5332        }
5333        let output = {
5334            let root = &self.ranks[0];
5335            let _main = root.gpu.enter_main()?;
5336            root.dtoh(&reduced)?
5337        };
5338        drop(remote_partial_keepalive);
5339        Ok(output)
5340    }
5341
5342    /// Gather token-major rank-local columns into one canonical root-device matrix.
5343    pub fn gather_native_column_shards_device(
5344        &self,
5345        shards: &[CudaSlice<f32>],
5346        tokens: usize,
5347        local_out: usize,
5348    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5349        let shard_len = tokens
5350            .checked_mul(local_out)
5351            .ok_or("native TP gather shard size overflow")?;
5352        if shards.len() != self.ranks.len() || shards.iter().any(|shard| shard.len() != shard_len) {
5353            return Err("native TP gather shard geometry mismatch".into());
5354        }
5355        // PRODUCER FENCE (2026-08-20 flake fix): the root stream peer-reads shards produced on
5356        // the other ranks' streams; without fencing those producers the copy can read a partial
5357        // kernel output.
5358        for engine in &self.ranks[1..] {
5359            let _main = engine.gpu.enter_main()?;
5360            engine.stream().synchronize()?;
5361        }
5362        let root = &self.ranks[0];
5363        let _main = root.gpu.enter_main()?;
5364        let global_out = shards
5365            .len()
5366            .checked_mul(local_out)
5367            .ok_or("native TP gather output width overflow")?;
5368        let gathered_len = tokens
5369            .checked_mul(global_out)
5370            .ok_or("native TP gather output size overflow")?;
5371        let mut gathered = root.uninit(gathered_len)?;
5372        if self.bulk_p2p {
5373            root.place_rows_strided(&shards[0], &mut gathered, local_out, tokens, global_out, 0)?;
5374            if shards.len() > 1 {
5375                let mut staging = root.uninit(shard_len)?;
5376                for (rank, shard) in shards.iter().enumerate().skip(1) {
5377                    root.stream().memcpy_dtod(shard, &mut staging)?;
5378                    root.place_rows_strided(
5379                        &staging,
5380                        &mut gathered,
5381                        local_out,
5382                        tokens,
5383                        global_out,
5384                        rank * local_out,
5385                    )?;
5386                }
5387            }
5388        } else {
5389            for token in 0..tokens {
5390                for (rank, shard) in shards.iter().enumerate() {
5391                    let source = shard.slice(token * local_out..(token + 1) * local_out);
5392                    let start = token * global_out + rank * local_out;
5393                    let mut destination = gathered.slice_mut(start..start + local_out);
5394                    root.stream().memcpy_dtod(&source, &mut destination)?;
5395                }
5396            }
5397        }
5398        Ok(gathered)
5399    }
5400
5401    pub fn gather_native_column_shards(
5402        &self,
5403        shards: &[CudaSlice<f32>],
5404        tokens: usize,
5405        local_out: usize,
5406    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5407        let gathered = self.gather_native_column_shards_device(shards, tokens, local_out)?;
5408        let root = &self.ranks[0];
5409        let _main = root.gpu.enter_main()?;
5410        root.dtoh(&gathered)
5411    }
5412
5413    pub(crate) fn decode_v2_workspace(&self) -> &std::sync::Mutex<Vec<StepTpDecodeV2Ws>> {
5414        &self.decode_v2
5415    }
5416
5417    /// Build the v2 decode-attention workspace for this layer's geometry on first use, or
5418    /// return the index of the matching one. Attention geometry varies across the trunk
5419    /// (per-layer query-head counts), so workspaces are keyed by their geometry pins — a
5420    /// handful exist per model, never one per layer.
5421    ///
5422    /// Refuses non-F32-resident projections: the v2 driver's bit-exactness claim against v1
5423    /// holds per residency class, and only the mirror class has no per-call weight expansion
5424    /// to hide allocation churn behind.
5425    pub(crate) fn decode_v2_ensure(
5426        &self,
5427        e: &Engine,
5428        q_m: &ResidentBf16ColumnParallel,
5429        k_m: &ResidentBf16ColumnParallel,
5430        v_m: &ResidentBf16ColumnParallel,
5431        o_m: &ResidentStepBf16RowParallel,
5432        heads: usize,
5433    ) -> Result<usize, Box<dyn std::error::Error>> {
5434        if self.ranks.len() > 1 && !self.native_p2p {
5435            return Err("step TP decode v2 requires native P2P ranks".into());
5436        }
5437        let ranks = self.ranks.len();
5438        // Residency contract: the canonical-chunk (non-fused) program needs the F32 mirror;
5439        // the fused-kernel door also reads raw checkpoint bf16 directly (halving the weight
5440        // traffic), so bf16 residency is accepted when that door is on.
5441        let fused_door = step_tp_qkv_fused_enabled()?;
5442        let arm_ok = |weight: &ResidentBf16Weight| match weight {
5443            ResidentBf16Weight::F32(_) => true,
5444            ResidentBf16Weight::Bf16(_) => fused_door,
5445        };
5446        for matrix in [q_m, k_m, v_m] {
5447            validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
5448            if matrix.out_features % ranks != 0 || matrix.in_features != q_m.in_features {
5449                return Err("step TP decode v2 QKV geometry mismatch".into());
5450            }
5451            for rank in &matrix.ranks {
5452                if !arm_ok(&rank.weight) {
5453                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5454                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5455                        .into());
5456                }
5457            }
5458        }
5459        validate_step_bf16_row_residency(&self.ranks, o_m)?;
5460        for blocks in &o_m.ranks {
5461            for block in blocks {
5462                if !arm_ok(&block.weight) {
5463                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5464                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5465                        .into());
5466                }
5467            }
5468        }
5469        if v_m.out_features != k_m.out_features
5470            || o_m.in_features != q_m.out_features
5471            || heads == 0
5472            || heads % ranks != 0
5473        {
5474            return Err("step TP decode v2 K/V/O geometry mismatch".into());
5475        }
5476        let local_q_dim = q_m.out_features / ranks;
5477        let local_kv_dim = k_m.out_features / ranks;
5478        let o_out = o_m.out_features;
5479        let o_block_cols = o_m.canonical_chunk_cols;
5480        let blocks_per_rank = o_m.ranks.first().map(Vec::len).unwrap_or(0);
5481        if blocks_per_rank == 0
5482            || o_m
5483                .ranks
5484                .iter()
5485                .any(|blocks| blocks.len() != blocks_per_rank)
5486            || blocks_per_rank * o_block_cols * ranks != o_m.in_features
5487        {
5488            return Err("step TP decode v2 O canonical block grid mismatch".into());
5489        }
5490
5491        let mut guard = self
5492            .decode_v2
5493            .lock()
5494            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5495        if let Some(index) = guard.iter().position(|ws| {
5496            ws.local_q_dim == local_q_dim
5497                && ws.local_kv_dim == local_kv_dim
5498                && ws.heads == heads
5499                && ws.o_out == o_out
5500                && ws.o_block_cols == o_block_cols
5501                && ws.blocks_per_rank == blocks_per_rank
5502                && ws.e_device == e.ctx().ordinal()
5503                && ws.q.len() == ranks
5504        }) {
5505            return Ok(index);
5506        }
5507
5508        let mut q_raw = Vec::with_capacity(ranks);
5509        let mut k_raw = Vec::with_capacity(ranks);
5510        let mut v_raw = Vec::with_capacity(ranks);
5511        let mut q = Vec::with_capacity(ranks);
5512        let mut k = Vec::with_capacity(ranks);
5513        let mut pos = Vec::with_capacity(ranks);
5514        let mut gate = Vec::with_capacity(ranks);
5515        let mut attn_out = Vec::with_capacity(ranks);
5516        let mut gated = Vec::with_capacity(ranks);
5517        let mut fuse_ctr = Vec::with_capacity(ranks);
5518        let mut o_partials = Vec::with_capacity(ranks);
5519        let mut ev_rank = Vec::with_capacity(ranks);
5520        let direct_join = oproj_direct_on();
5521        for (rank, engine) in self.ranks.iter().enumerate() {
5522            let _main = engine.gpu.enter_main()?;
5523            q_raw.push(engine.uninit(local_q_dim)?);
5524            k_raw.push(engine.uninit(local_kv_dim)?);
5525            v_raw.push(engine.uninit(local_kv_dim)?);
5526            q.push(engine.uninit(local_q_dim)?);
5527            k.push(engine.uninit(local_kv_dim)?);
5528            pos.push(engine.htod_i32(&[0])?);
5529            fuse_ctr.push(engine.stream().clone_htod(&[0u32])?);
5530            gate.push(engine.uninit(heads / ranks)?);
5531            attn_out.push(engine.uninit(local_q_dim)?);
5532            gated.push(engine.uninit(local_q_dim)?);
5533            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
5534            for _ in 0..blocks_per_rank {
5535                // Direct join: peer ranks' partials live on ROOT so the b4 kernel's
5536                // stores land there over P2P (UVA) and no pull copy is needed.
5537                if direct_join && rank != 0 {
5538                    let root = &self.ranks[0];
5539                    let _root_main = root.gpu.enter_main()?;
5540                    rank_partials.push(root.uninit(o_out)?);
5541                } else {
5542                    rank_partials.push(engine.uninit(o_out)?);
5543                }
5544            }
5545            o_partials.push(rank_partials);
5546            ev_rank.push(engine.ctx().new_event(None)?);
5547        }
5548        let root = &self.ranks[0];
5549        let (peer_partial, reduce_a, reduce_b, zeros, k_shadow, v_shadow, ev_refresh, ev_oproj) = {
5550            let _main = root.gpu.enter_main()?;
5551            (
5552                root.uninit(o_out)?,
5553                root.uninit(o_out)?,
5554                root.uninit(o_out)?,
5555                root.htod(&vec![0.0f32; o_out])?,
5556                root.uninit(ranks * local_kv_dim)?,
5557                root.uninit(ranks * local_kv_dim)?,
5558                root.ctx().new_event(None)?,
5559                root.ctx().new_event(None)?,
5560            )
5561        };
5562        let (gate_e, ev_entry) = {
5563            let _main = e.gpu.enter_main()?;
5564            (e.uninit(heads)?, e.ctx().new_event(None)?)
5565        };
5566        let raw_attn_in = Vec::new();
5567        let raw_pos = Vec::new();
5568        guard.push(StepTpDecodeV2Ws {
5569            tcol_q: Vec::new(),
5570            tcol_k: Vec::new(),
5571            tcol_v: Vec::new(),
5572            tcol_g: Vec::new(),
5573            tcol_in: Vec::new(),
5574            tcol_cap: 0,
5575            w8_aq: Vec::new(),
5576            w8_ad: Vec::new(),
5577            w8_in: 0,
5578            w8o_aq: Vec::new(),
5579            w8o_ad: Vec::new(),
5580            w8o_in: 0,
5581            w8t_aq: Vec::new(),
5582            w8t_ad: Vec::new(),
5583            w8t_in: 0,
5584            w8t_oaq: Vec::new(),
5585            w8t_oad: Vec::new(),
5586            w8t_oin: 0,
5587            w8t_cap: 0,
5588            fa2_q: Vec::new(),
5589            fa2_gate: Vec::new(),
5590            fa2_gated: Vec::new(),
5591            fa2_cap: 0,
5592            rope_k_t: Vec::new(),
5593            rope_ctr_t: Vec::new(),
5594            rope_pos_t: Vec::new(),
5595            rows_tabs: Vec::new(),
5596            rows_tab_t: Vec::new(),
5597            rows_tab_shadow: Vec::new(),
5598            tcol_gated: Vec::new(),
5599            tcol_opart: Vec::new(),
5600            tcol_opeer: None,
5601            tcol_omix: None,
5602            tcol_ocap: 0,
5603            q_raw,
5604            k_raw,
5605            v_raw,
5606            q,
5607            k,
5608            pos,
5609            fuse_ctr,
5610            gate,
5611            attn_out,
5612            gated,
5613            o_partials,
5614            ev_rank,
5615            peer_partial,
5616            reduce_a,
5617            reduce_b,
5618            zeros,
5619            k_shadow,
5620            v_shadow,
5621            ev_refresh,
5622            ev_oproj,
5623            gate_e,
5624            attn_in: Vec::new(),
5625            h_stage: None,
5626            pos_stage: None,
5627            raw_h_stage: 0,
5628            raw_pos_stage: 0,
5629            raw_attn_in,
5630            raw_pos,
5631            raw_o_partial1: 0,
5632            raw_peer_partial: 0,
5633            raw_k1: 0,
5634            raw_v1: 0,
5635            raw_k_shadow: 0,
5636            raw_v_shadow: 0,
5637            raw_mixed_stage_e: 0,
5638            raw_reduce_a: 0,
5639            raw_shadow_stage_e: (0, 0),
5640            ev_entry,
5641            e_device: e.ctx().ordinal(),
5642            local_q_dim,
5643            local_kv_dim,
5644            heads,
5645            o_out,
5646            o_block_cols,
5647            blocks_per_rank,
5648        });
5649        eprintln!(
5650            "[step-tp-decode-v2] workspace ranks={ranks} local_q={local_q_dim} \
5651             local_kv={local_kv_dim} heads={heads} o_blocks={blocks_per_rank}x{o_block_cols} \
5652             residency=persistent ordering=evented performance_claim=false"
5653        );
5654        Ok(guard.len() - 1)
5655    }
5656
5657    /// v2 phase 1: replicate the layer input, project QKV, norm, rope, and stage the gate —
5658    /// all into the persistent workspace, ordered by events instead of host syncs.
5659    ///
5660    /// The caller must have queued every producer of `h`, `pos_d`, and `gate_raw` on `e`'s
5661    /// stream BEFORE this call: `ev_entry` is recorded once here and every rank stream waits
5662    /// on it (the entry fence also guards workspace reuse across layers — any consumer of the
5663    /// previous layer's outputs was queued on `e`'s stream before this record).
5664    #[allow(clippy::too_many_arguments)]
5665    /// T-COLUMN verify precompute (spec MTP): stage T input rows to every rank and run the
5666    /// weight-amortized qkvg_tcol per rank into the ws slabs. Rope/norm/append stay per
5667    /// column in the unmodified t=1 program (defer_norm_rope contract). Bit-exact per
5668    /// column vs the t=1 kernel by construction.
5669    #[allow(clippy::too_many_arguments)]
5670    pub fn decode_v2_input_qkv_tcol(
5671        &self,
5672        ws_index: usize,
5673        e: &Engine,
5674        h_t: &CudaSlice<f32>,
5675        t: usize,
5676        q_m: &ResidentBf16ColumnParallel,
5677        k_m: &ResidentBf16ColumnParallel,
5678        v_m: &ResidentBf16ColumnParallel,
5679        gate_shards: Option<StepTpGateShards<'_>>,
5680    ) -> Result<(), Box<dyn std::error::Error>> {
5681        let ranks = self.ranks.len();
5682        let mut guard = self
5683            .decode_v2
5684            .lock()
5685            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5686        let ws = guard
5687            .get_mut(ws_index)
5688            .ok_or("step TP decode v2 workspace index out of range")?;
5689        let in_f = q_m.in_features;
5690        if h_t.len() < t * in_f || t == 0 || t > 32 {
5691            return Err("decode_v2_input_qkv_tcol geometry".into());
5692        }
5693        // Lazily arm the slabs to capacity.
5694        if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
5695            ws.tcol_q.clear();
5696            ws.tcol_k.clear();
5697            ws.tcol_v.clear();
5698            ws.tcol_g.clear();
5699            ws.tcol_in.clear();
5700            for engine in &self.ranks {
5701                let _m = engine.gpu.enter_main()?;
5702                ws.tcol_q.push(engine.uninit(32 * ws.local_q_dim)?);
5703                ws.tcol_k.push(engine.uninit(32 * ws.local_kv_dim)?);
5704                ws.tcol_v.push(engine.uninit(32 * ws.local_kv_dim)?);
5705                ws.tcol_g
5706                    .push(engine.uninit(32 * (ws.heads / ranks).max(1))?);
5707                ws.tcol_in.push(engine.uninit(32 * in_f)?);
5708            }
5709            ws.tcol_cap = 32;
5710        }
5711        // Stage the T input rows on e, fence, per-rank pull + tcol launch.
5712        use cudarc::driver::DevicePtr;
5713        let raw_src = {
5714            let _main = e.gpu.enter_main()?;
5715            let stream = e.stream();
5716            let (p, _g) = h_t.device_ptr(&stream);
5717            ws.ev_entry.record(&stream)?;
5718            p as u64
5719        };
5720        for rank in 0..ranks {
5721            let engine = &self.ranks[rank];
5722            let _main = engine.gpu.enter_main()?;
5723            engine.stream().wait(&ws.ev_entry)?;
5724            let raw_dst = {
5725                let stream = engine.stream();
5726                let (p, _g) = ws.tcol_in[rank].device_ptr(&stream);
5727                p as u64
5728            };
5729            raw_copy_bytes(raw_dst, raw_src, t * in_f * 4, engine)?;
5730            let out_g = match &gate_shards {
5731                Some(_) => ws.heads / ranks,
5732                None => 0,
5733            };
5734            match (
5735                &q_m.ranks[rank].weight,
5736                &k_m.ranks[rank].weight,
5737                &v_m.ranks[rank].weight,
5738            ) {
5739                (
5740                    ResidentBf16Weight::Bf16(wq),
5741                    ResidentBf16Weight::Bf16(wk),
5742                    ResidentBf16Weight::Bf16(wv),
5743                ) => {
5744                    let wg = match &gate_shards {
5745                        Some(StepTpGateShards::Bf16(shards)) => &shards[rank],
5746                        Some(StepTpGateShards::F32(_)) => {
5747                            return Err(
5748                                "tcol verify: gate shard class does not match bf16 QKV".into()
5749                            );
5750                        }
5751                        None => wq,
5752                    };
5753                    let StepTpDecodeV2Ws {
5754                        tcol_q,
5755                        tcol_k,
5756                        tcol_v,
5757                        tcol_g,
5758                        tcol_in,
5759                        local_q_dim,
5760                        local_kv_dim,
5761                        w8t_aq,
5762                        w8t_ad,
5763                        w8t_in,
5764                        w8t_cap,
5765                        ..
5766                    } = &mut *ws;
5767                    // MEMRA_TCOL_REFKERN=1 (bisect): fill the slabs via the t=1 kernel per
5768                    // column — separates driver bugs from tcol-kernel bugs.
5769                    static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
5770                    let refk = *REFK
5771                        .get_or_init(|| std::env::var("MEMRA_TCOL_REFKERN").as_deref() == Ok("1"));
5772                    if refk {
5773                        let lq = *local_q_dim;
5774                        let lkv = *local_kv_dim;
5775                        let mut hrow = engine.uninit(in_f)?;
5776                        let mut qr = engine.uninit(lq)?;
5777                        let mut kr = engine.uninit(lkv)?;
5778                        let mut vr = engine.uninit(lkv)?;
5779                        let mut gr = engine.uninit(out_g.max(1))?;
5780                        for c in 0..t {
5781                            {
5782                                let mut dst = hrow.slice_mut(0..in_f);
5783                                engine.stream().memcpy_dtod(
5784                                    &tcol_in[rank].slice(c * in_f..(c + 1) * in_f),
5785                                    &mut dst,
5786                                )?;
5787                            }
5788                            engine.matvec_bf16_qkvg_into(
5789                                wq, wk, wv, wg, &hrow, &mut qr, &mut kr, &mut vr, &mut gr, in_f,
5790                                lq, lkv, out_g,
5791                            )?;
5792                            let stream = engine.stream();
5793                            {
5794                                let mut dst = tcol_q[rank].slice_mut(c * lq..(c + 1) * lq);
5795                                stream.memcpy_dtod(&qr.slice(0..lq), &mut dst)?;
5796                            }
5797                            {
5798                                let mut dst = tcol_k[rank].slice_mut(c * lkv..(c + 1) * lkv);
5799                                stream.memcpy_dtod(&kr.slice(0..lkv), &mut dst)?;
5800                            }
5801                            {
5802                                let mut dst = tcol_v[rank].slice_mut(c * lkv..(c + 1) * lkv);
5803                                stream.memcpy_dtod(&vr.slice(0..lkv), &mut dst)?;
5804                            }
5805                            if out_g > 0 {
5806                                let mut dst = tcol_g[rank].slice_mut(c * out_g..(c + 1) * out_g);
5807                                stream.memcpy_dtod(&gr.slice(0..out_g), &mut dst)?;
5808                            }
5809                        }
5810                    } else if crate::step_tp_w8_on()
5811                        && q_m.ranks[rank].q8.is_some()
5812                        && k_m.ranks[rank].q8.is_some()
5813                        && v_m.ranks[rank].q8.is_some()
5814                        && in_f % 32 == 0
5815                    {
5816                        // MEMRA_STEP_TP_W8 on the VERIFY walk. nsys put the bf16 tcol QKV at
5817                        // 12.3% of spec GPU time and the bf16 tcol o_proj at 24.8% — the door
5818                        // had only ever replaced the DECODE kernels, so 37% of the verify still
5819                        // streamed bf16 weights. One q8 launch over all t columns; the gate rows
5820                        // stay bf16 as on the decode side.
5821                        if *w8t_in != in_f || *w8t_cap < t || w8t_aq.len() != ranks {
5822                            w8t_aq.clear();
5823                            w8t_ad.clear();
5824                            for e_rank in &self.ranks {
5825                                let _m = e_rank.gpu.enter_main()?;
5826                                w8t_aq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
5827                                w8t_ad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
5828                            }
5829                            *w8t_in = in_f;
5830                            *w8t_cap = 32;
5831                        }
5832                        engine.quantize_q8_1_into(
5833                            &tcol_in[rank],
5834                            t,
5835                            in_f,
5836                            &mut w8t_aq[rank],
5837                            &mut w8t_ad[rank],
5838                        )?;
5839                        engine.qmatvec_q8_0_qkv_rp_t_into(
5840                            q_m.ranks[rank].q8.as_ref().unwrap(),
5841                            k_m.ranks[rank].q8.as_ref().unwrap(),
5842                            v_m.ranks[rank].q8.as_ref().unwrap(),
5843                            &w8t_aq[rank],
5844                            &w8t_ad[rank],
5845                            &mut tcol_q[rank],
5846                            &mut tcol_k[rank],
5847                            &mut tcol_v[rank],
5848                            in_f,
5849                            *local_q_dim,
5850                            *local_kv_dim,
5851                            t,
5852                        )?;
5853                        if out_g > 0 {
5854                            engine.matvec_bf16_rows_into(
5855                                wg,
5856                                &tcol_in[rank],
5857                                &mut tcol_g[rank],
5858                                in_f,
5859                                out_g,
5860                                t,
5861                            )?;
5862                        }
5863                    } else {
5864                        engine.matvec_bf16_qkvg_tcol_into(
5865                            wq,
5866                            wk,
5867                            wv,
5868                            wg,
5869                            &tcol_in[rank],
5870                            &mut tcol_q[rank],
5871                            &mut tcol_k[rank],
5872                            &mut tcol_v[rank],
5873                            &mut tcol_g[rank],
5874                            in_f,
5875                            *local_q_dim,
5876                            *local_kv_dim,
5877                            out_g,
5878                            t,
5879                        )?;
5880                    }
5881                }
5882                _ => return Err("tcol verify requires bf16-resident fused QKV".into()),
5883            }
5884        }
5885        Ok(())
5886    }
5887
5888    /// MEMRA_TCOL_OPROJ eligibility: the defer replaces exactly the o_fused direct-join
5889    /// finish (bf16 b4 kernel, 2 ranks, 4 canonical blocks) with the shadow gathers
5890    /// skipped — so it requires the same doors that arm dictate that finish shape.
5891    pub(crate) fn decode_v2_oproj_tcol_eligible(
5892        &self,
5893        ws: &StepTpDecodeV2Ws,
5894        o_m: &ResidentStepBf16RowParallel,
5895    ) -> bool {
5896        self.ranks.len() == 2
5897            && ws.blocks_per_rank == 4
5898            && step_tp_qkv_fused_enabled().unwrap_or(false)
5899            && no_local_shadow_on()
5900            && std::env::var("MEMRA_B4_X2").as_deref() != Ok("1")
5901            && o_m
5902                .ranks
5903                .iter()
5904                .flatten()
5905                .all(|block| matches!(block.weight, ResidentBf16Weight::Bf16(_)))
5906    }
5907
5908    /// MEMRA_SPEC_FA2 stash: copy this column's per-rank post-rope q and gate rows into
5909    /// the fa2 slabs (rank-stream ordered behind the rope/append that produced them), and
5910    /// give `e` the same anti-dependency wait the skipped finish provided (next column's
5911    /// h/pos re-staging must not overtake this column's rank pulls).
5912    pub(crate) fn decode_v2_stash_fa2(
5913        &self,
5914        ws: &mut StepTpDecodeV2Ws,
5915        e: &Engine,
5916        col: usize,
5917    ) -> Result<(), Box<dyn std::error::Error>> {
5918        let ranks = self.ranks.len();
5919        if col >= 32 {
5920            return Err("decode_v2_stash_fa2 column out of range".into());
5921        }
5922        let lq = ws.local_q_dim;
5923        let lg = (ws.heads / ranks).max(1);
5924        if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
5925            ws.fa2_q.clear();
5926            ws.fa2_gate.clear();
5927            ws.fa2_gated.clear();
5928            ws.rope_k_t.clear();
5929            ws.rope_ctr_t.clear();
5930            ws.rope_pos_t.clear();
5931            ws.rows_tab_t.clear();
5932            for engine in &self.ranks {
5933                let _m = engine.gpu.enter_main()?;
5934                ws.fa2_q.push(engine.uninit(32 * lq)?);
5935                ws.fa2_gate.push(engine.uninit(32 * lg)?);
5936                ws.fa2_gated.push(engine.uninit(32 * lq)?);
5937                ws.rope_k_t.push(engine.uninit(32 * ws.local_kv_dim)?);
5938                ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
5939                ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
5940                ws.rows_tab_t
5941                    .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
5942            }
5943            ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
5944            ws.fa2_cap = 32;
5945        }
5946        for rank in 0..ranks {
5947            let engine = &self.ranks[rank];
5948            let _main = engine.gpu.enter_main()?;
5949            {
5950                let mut dst = ws.fa2_q[rank].slice_mut(col * lq..(col + 1) * lq);
5951                engine
5952                    .stream()
5953                    .memcpy_dtod(&ws.q[rank].slice(0..lq), &mut dst)?;
5954            }
5955            {
5956                let mut dst = ws.fa2_gate[rank].slice_mut(col * lg..(col + 1) * lg);
5957                engine
5958                    .stream()
5959                    .memcpy_dtod(&ws.gate[rank].slice(0..lg), &mut dst)?;
5960            }
5961            ws.ev_rank[rank].record(&engine.stream())?;
5962        }
5963        {
5964            let _main = e.gpu.enter_main()?;
5965            for ev in ws.ev_rank.iter() {
5966                e.stream().wait(ev)?;
5967            }
5968        }
5969        Ok(())
5970    }
5971
5972    /// MEMRA_SPEC_FA2 join: after BOTH verify columns stashed (their appends landed in
5973    /// rank-stream order), run ONE fa_decode_dcw2 per rank over the shared KV stream —
5974    /// two query rows, per-row causal bounds, per-row combine+gate — then land the two
5975    /// gated rows in the o-tcol slabs and reuse the weight-amortized o_proj join.
5976    /// Returns the [2, o_out] `mixed` slab on `e`. The caller's precheck enforced the
5977    /// equal-partition guard (boundary rounds never arm the defer).
5978    #[allow(clippy::too_many_arguments)]
5979    pub(crate) fn decode_v2_spec_fa2_join(
5980        &self,
5981        ws_index: usize,
5982        e: &Engine,
5983        o_m: &ResidentStepBf16RowParallel,
5984        kv: &ResidentTpKvCache,
5985        head_dim: usize,
5986        window: usize,
5987        bucket_max: usize,
5988        scale: f32,
5989    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5990        let ranks = self.ranks.len();
5991        // Engagement receipt: a vacuous gate (precheck never passing) must be visible.
5992        static ONCE: std::sync::Once = std::sync::Once::new();
5993        ONCE.call_once(|| eprintln!("[spec-fa2] joined T=2 attention ENGAGED"));
5994        {
5995            let mut guard = self
5996                .decode_v2
5997                .lock()
5998                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5999            let ws = guard
6000                .get_mut(ws_index)
6001                .ok_or("step TP decode v2 workspace index out of range")?;
6002            if ws.fa2_cap < 2 || ws.fa2_q.len() != ranks {
6003                return Err("spec fa2 join without stashed columns".into());
6004            }
6005            let lq = ws.local_q_dim;
6006            let local_heads = (ws.heads / ranks).max(1);
6007            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
6008            let capacity = kv.physical_capacity();
6009            let (k_tok_bytes, v_tok_bytes) = (kv.k_tok_bytes(), kv.v_tok_bytes());
6010            // Arm the o-tcol slabs if the oproj door never ran this boot (same shapes).
6011            if ws.tcol_ocap < 2 || ws.tcol_gated.len() != ranks {
6012                ws.tcol_gated.clear();
6013                ws.tcol_opart.clear();
6014                for engine in &self.ranks {
6015                    let _m = engine.gpu.enter_main()?;
6016                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6017                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6018                }
6019                let root = &self.ranks[0];
6020                let _m = root.gpu.enter_main()?;
6021                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6022                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6023                ws.tcol_ocap = 32;
6024            }
6025            for rank in 0..ranks {
6026                let engine = &self.ranks[rank];
6027                let _main = engine.gpu.enter_main()?;
6028                let rank_cache = kv
6029                    .rank(rank)
6030                    .ok_or("spec fa2 join lost its KV cache rank")?;
6031                let k_ring = engine.view_u8_range(rank_cache.k(), 0, capacity * k_tok_bytes);
6032                let v_ring = engine.view_u8_range(rank_cache.v(), 0, capacity * v_tok_bytes);
6033                {
6034                    let StepTpDecodeV2Ws {
6035                        fa2_q,
6036                        fa2_gate,
6037                        fa2_gated,
6038                        ..
6039                    } = &mut *ws;
6040                    engine.fa_decode_dcw2(
6041                        &fa2_q[rank],
6042                        &k_ring,
6043                        &v_ring,
6044                        &mut fa2_gated[rank],
6045                        head_dim,
6046                        local_heads,
6047                        local_kv_heads,
6048                        rank_cache.len_d(),
6049                        rank_cache.base_d(),
6050                        window,
6051                        bucket_max,
6052                        scale,
6053                        k_tok_bytes,
6054                        v_tok_bytes,
6055                        &fa2_gate[rank],
6056                    )?;
6057                }
6058                // Both gated rows are contiguous [2, lq] — exactly columns 0..2 of the
6059                // o-tcol slab layout. One dtod, in rank-stream order behind the fa.
6060                let StepTpDecodeV2Ws {
6061                    fa2_gated,
6062                    tcol_gated,
6063                    ..
6064                } = &mut *ws;
6065                let mut dst = tcol_gated[rank].slice_mut(0..2 * lq);
6066                engine
6067                    .stream()
6068                    .memcpy_dtod(&fa2_gated[rank].slice(0..2 * lq), &mut dst)?;
6069            }
6070        }
6071        self.decode_v2_oproj_tcol(ws_index, e, o_m, 2)
6072    }
6073
6074    /// FULL T-ROW ATTENTION PASS over per-row session tables (batched serving): reads
6075    /// the tcol raw-projection slabs, runs ONE rope/append rows launch + ONE fa rows
6076    /// launch + ONE combine per rank (gate straight from the tcol gate slab), then the
6077    /// o_proj tcol join — the whole per-row attention loop in 3 launches/rank/layer.
6078    /// Per-(row, head) programs are the t=1 kernels verbatim; each row appends to and
6079    /// attends its OWN session. `session_parts[rank][row]` = {k_plane, v_plane, len_ptr,
6080    /// base_ptr}; `tab_keys[rank]` keys the per-rank combined-table cache (caller folds
6081    /// layer + session-set + base-arming into it); `stage_pos` stages the position slab
6082    /// (positions are constant across layers within a tick — stage on the first layer).
6083    #[allow(clippy::too_many_arguments)]
6084    pub(crate) fn decode_v2_rope_fa_rows(
6085        &self,
6086        ws_index: usize,
6087        e: &Engine,
6088        o_m: &ResidentStepBf16RowParallel,
6089        session_parts: &[Vec<[u64; 4]>],
6090        tab_keys: &[u64],
6091        positions: &[i32],
6092        stage_pos: bool,
6093        same_session: bool,
6094        q_norms: &[CudaSlice<f32>],
6095        k_norms: &[CudaSlice<f32>],
6096        rope_freqs: &[Option<&crate::CudaSlice<f32>>],
6097        t: usize,
6098        head_dim: usize,
6099        n_rot: usize,
6100        window: usize,
6101        max_ns: usize,
6102        scale: f32,
6103        k_tok_bytes: usize,
6104        v_tok_bytes: usize,
6105        eps: f32,
6106        rope_base: f32,
6107    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
6108        use cudarc::driver::DevicePtr;
6109        let ranks = self.ranks.len();
6110        if session_parts.len() != ranks || tab_keys.len() != ranks || positions.len() < t {
6111            return Err("rope fa rows geometry".into());
6112        }
6113        {
6114            let mut guard = self
6115                .decode_v2
6116                .lock()
6117                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6118            let ws = guard
6119                .get_mut(ws_index)
6120                .ok_or("step TP decode v2 workspace index out of range")?;
6121            if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
6122                return Err("rope fa rows without tcol slabs".into());
6123            }
6124            let lq = ws.local_q_dim;
6125            let lkv = ws.local_kv_dim;
6126            let lg = (ws.heads / ranks).max(1);
6127            let local_heads = (ws.heads / ranks).max(1);
6128            let local_kv_heads = (lkv / head_dim).max(1);
6129            // Arm the fa2/rope slabs (shared with the stash path).
6130            if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
6131                ws.fa2_q.clear();
6132                ws.fa2_gate.clear();
6133                ws.fa2_gated.clear();
6134                ws.rope_k_t.clear();
6135                ws.rope_ctr_t.clear();
6136                ws.rope_pos_t.clear();
6137                ws.rows_tab_t.clear();
6138                for engine in &self.ranks {
6139                    let _m = engine.gpu.enter_main()?;
6140                    ws.fa2_q.push(engine.uninit(32 * lq)?);
6141                    ws.fa2_gate.push(engine.uninit(32 * lg)?);
6142                    ws.fa2_gated.push(engine.uninit(32 * lq)?);
6143                    ws.rope_k_t.push(engine.uninit(32 * lkv)?);
6144                    ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
6145                    ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
6146                    ws.rows_tab_t
6147                        .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
6148                }
6149                ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
6150                ws.fa2_cap = 32;
6151            }
6152            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
6153                ws.tcol_gated.clear();
6154                ws.tcol_opart.clear();
6155                for engine in &self.ranks {
6156                    let _m = engine.gpu.enter_main()?;
6157                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6158                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6159                }
6160                let root = &self.ranks[0];
6161                let _m = root.gpu.enter_main()?;
6162                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6163                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6164                ws.tcol_ocap = 32;
6165            }
6166            for rank in 0..ranks {
6167                let engine = &self.ranks[rank];
6168                let _main = engine.gpu.enter_main()?;
6169                if stage_pos {
6170                    let host: Vec<i32> = positions[..t].to_vec();
6171                    let mut view = ws.rope_pos_t[rank].slice_mut(0..t);
6172                    engine.stream().memcpy_htod(&host, &mut view)?;
6173                }
6174                // Combined 6-word table {k, v, len, base, ctr, back}; ctr = this rank's
6175                // per-row counter slab. Built from the pointers the CALLER just read off
6176                // the live distributed cache, and RESTAGED into a persistent slab before
6177                // every launch (MEMRA_ROWS_TAB_RESTAGE, default ON).
6178                //
6179                // The `rows_tabs` memo this replaces was keyed by a hash of
6180                // (k pointer, base pointer, layer, t) but the table it handed back ALSO
6181                // carried the V and LEN pointers, and nothing invalidated it when a
6182                // session's KV cache was dropped. A later session whose K buffer landed on
6183                // a recycled address therefore hit a dead entry, and
6184                // `qk_norm_rope_append_inc_dcw_rows` WROTE this session's K/V rows through
6185                // the freed V/len pointers it still held while `fa_decode_dcw_rows` read
6186                // them back: a whole non-finite row when the freed pages were re-mapped,
6187                // CUDA_ERROR_ILLEGAL_ADDRESS when they were not. The row-table twin in
6188                // `step35_verify_fa_rows_join` was cured of exactly this in 8c8397e0b2
6189                // ("a process-lifetime map cannot prove allocation generation", Hermes
6190                // `11339f5cd3c132a3`); this fused rope+append+fa path was left out of it,
6191                // and MEMRA_FUSE_ROPE_APPEND=1 makes it the arm that actually runs.
6192                let ctr_base = {
6193                    let s = engine.stream();
6194                    let (p, _g) = ws.rope_ctr_t[rank].device_ptr(&s);
6195                    p as u64
6196                };
6197                let host = rows_tab_host(&session_parts[rank], ctr_base, same_session, t);
6198                // STALE-HIT RECEIPT (MEMRA_ROWS_TAB_STALE_SCAN=1, default OFF): replay the
6199                // retired key against the contents we are about to stage. `engaged` proves
6200                // this path executes at all; `STALE` proves the retired memo would have
6201                // handed a live launch another allocation's pointers, and names which word
6202                // moved. Diagnostic only: it never feeds a kernel.
6203                if rows_tab_stale_scan() {
6204                    if ws.rows_tab_shadow.len() != ranks {
6205                        ws.rows_tab_shadow = (0..ranks).map(|_| Default::default()).collect();
6206                    }
6207                    let n = ROWS_TAB_ENGAGED.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
6208                    if let Some(prev) = ws.rows_tab_shadow[rank].get(&tab_keys[rank]) {
6209                        if prev != &host {
6210                            let words = ["k", "v", "len", "base", "ctr", "back"];
6211                            let moved: Vec<String> = (0..host.len())
6212                                .filter(|&i| prev.get(i) != Some(&host[i]))
6213                                .map(|i| format!("{}[row{}]", words[i % 6], i / 6))
6214                                .collect();
6215                            let stale =
6216                                ROWS_TAB_STALE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
6217                            eprintln!(
6218                                "[rows-tab] STALE #{stale} lookup #{n} rank={rank} t={t} key={:#018x} moved={}: the retired memo would have launched this row on another allocation's pointers",
6219                                tab_keys[rank],
6220                                moved.join(",")
6221                            );
6222                        }
6223                    }
6224                    ws.rows_tab_shadow[rank].insert(tab_keys[rank], host.clone());
6225                }
6226                let legacy_memo = !rows_tab_restage_on();
6227                if legacy_memo && !ws.rows_tabs[rank].contains_key(&tab_keys[rank]) {
6228                    let tab = engine.stream().clone_htod(&host)?;
6229                    ws.rows_tabs[rank].insert(tab_keys[rank], tab);
6230                }
6231                if !legacy_memo {
6232                    let mut view = ws.rows_tab_t[rank].slice_mut(0..t * 6);
6233                    engine.stream().memcpy_htod(&host, &mut view)?;
6234                }
6235                let StepTpDecodeV2Ws {
6236                    tcol_q,
6237                    tcol_k,
6238                    tcol_v,
6239                    tcol_g,
6240                    fa2_q,
6241                    fa2_gated,
6242                    rope_k_t,
6243                    rope_pos_t,
6244                    rows_tabs,
6245                    rows_tab_t,
6246                    ..
6247                } = &mut *ws;
6248                let tab = if legacy_memo {
6249                    rows_tabs[rank]
6250                        .get(&tab_keys[rank])
6251                        .ok_or("rows tab memo lost its entry")?
6252                } else {
6253                    &rows_tab_t[rank]
6254                };
6255                engine.qk_norm_rope_append_inc_dcw_rows(
6256                    &tcol_q[rank],
6257                    &tcol_k[rank],
6258                    &tcol_v[rank],
6259                    &q_norms[rank],
6260                    &k_norms[rank],
6261                    &mut fa2_q[rank],
6262                    &mut rope_k_t[rank],
6263                    tab,
6264                    &rope_pos_t[rank],
6265                    same_session,
6266                    t,
6267                    lkv,
6268                    lkv,
6269                    k_tok_bytes,
6270                    v_tok_bytes,
6271                    head_dim,
6272                    n_rot,
6273                    local_heads,
6274                    local_kv_heads,
6275                    eps,
6276                    rope_base,
6277                    1.0,
6278                    rope_freqs[rank],
6279                )?;
6280                engine.fa_decode_dcw_rows(
6281                    &fa2_q[rank],
6282                    tab,
6283                    &mut fa2_gated[rank],
6284                    t,
6285                    head_dim,
6286                    local_heads,
6287                    local_kv_heads,
6288                    window,
6289                    max_ns,
6290                    scale,
6291                    k_tok_bytes,
6292                    v_tok_bytes,
6293                    &tcol_g[rank],
6294                )?;
6295                let StepTpDecodeV2Ws {
6296                    fa2_gated,
6297                    tcol_gated,
6298                    ..
6299                } = &mut *ws;
6300                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
6301                engine
6302                    .stream()
6303                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
6304            }
6305        }
6306        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
6307    }
6308
6309    /// T-ROW fa join over per-row session tables (the per-session distributed-KV
6310    /// primitive): after all t rows stashed q+gate (their appends landed in rank-stream
6311    /// order), ONE fa_decode_dcw_rows per rank walks every row's own ring with its own
6312    /// geometry — bit-identical per row to its per-row launch — then the o_proj tcol
6313    /// join lands the [t, o_out] `mixed` slab on `e`. `tabs[rank]` is the pre-staged
6314    /// device table on that rank.
6315    #[allow(clippy::too_many_arguments)]
6316    pub(crate) fn decode_v2_fa_rows_join(
6317        &self,
6318        ws_index: usize,
6319        e: &Engine,
6320        o_m: &ResidentStepBf16RowParallel,
6321        tabs: &[&crate::CudaSlice<u64>],
6322        t: usize,
6323        head_dim: usize,
6324        window: usize,
6325        max_ns: usize,
6326        scale: f32,
6327        k_tok_bytes: usize,
6328        v_tok_bytes: usize,
6329    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
6330        let ranks = self.ranks.len();
6331        if tabs.len() != ranks {
6332            return Err("fa rows join needs one table per rank".into());
6333        }
6334        {
6335            let mut guard = self
6336                .decode_v2
6337                .lock()
6338                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6339            let ws = guard
6340                .get_mut(ws_index)
6341                .ok_or("step TP decode v2 workspace index out of range")?;
6342            if ws.fa2_cap < t || ws.fa2_q.len() != ranks {
6343                return Err("fa rows join without stashed rows".into());
6344            }
6345            let lq = ws.local_q_dim;
6346            let local_heads = (ws.heads / ranks).max(1);
6347            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
6348            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
6349                ws.tcol_gated.clear();
6350                ws.tcol_opart.clear();
6351                for engine in &self.ranks {
6352                    let _m = engine.gpu.enter_main()?;
6353                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6354                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6355                }
6356                let root = &self.ranks[0];
6357                let _m = root.gpu.enter_main()?;
6358                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6359                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6360                ws.tcol_ocap = 32;
6361            }
6362            for rank in 0..ranks {
6363                let engine = &self.ranks[rank];
6364                let _main = engine.gpu.enter_main()?;
6365                {
6366                    let StepTpDecodeV2Ws {
6367                        fa2_q,
6368                        fa2_gate,
6369                        fa2_gated,
6370                        ..
6371                    } = &mut *ws;
6372                    engine.fa_decode_dcw_rows(
6373                        &fa2_q[rank],
6374                        tabs[rank],
6375                        &mut fa2_gated[rank],
6376                        t,
6377                        head_dim,
6378                        local_heads,
6379                        local_kv_heads,
6380                        window,
6381                        max_ns,
6382                        scale,
6383                        k_tok_bytes,
6384                        v_tok_bytes,
6385                        &fa2_gate[rank],
6386                    )?;
6387                }
6388                let StepTpDecodeV2Ws {
6389                    fa2_gated,
6390                    tcol_gated,
6391                    ..
6392                } = &mut *ws;
6393                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
6394                engine
6395                    .stream()
6396                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
6397            }
6398        }
6399        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
6400    }
6401
6402    /// MEMRA_TCOL_OPROJ stash: copy this column's per-rank `gated` rows into the o-tcol
6403    /// slabs (rank-stream ordered behind the attention kernels that produced them). The
6404    /// per-column finish choreography is skipped entirely; `decode_v2_oproj_tcol` joins
6405    /// every column afterwards.
6406    pub(crate) fn decode_v2_stash_gated(
6407        &self,
6408        ws: &mut StepTpDecodeV2Ws,
6409        e: &Engine,
6410        col: usize,
6411    ) -> Result<(), Box<dyn std::error::Error>> {
6412        let ranks = self.ranks.len();
6413        // 32, not 8: the slabs below have been 32 rows since the slab-width fix, and the walk now
6414        // runs chunks up to t=32 (the w=16 arm died here on a guard three widths staler than its
6415        // own allocation, 2026-08-27).
6416        if col >= 32 {
6417            return Err("decode_v2_stash_gated column out of range".into());
6418        }
6419        let lq = ws.local_q_dim;
6420        if ws.tcol_ocap == 0 || ws.tcol_gated.len() != ranks {
6421            ws.tcol_gated.clear();
6422            ws.tcol_opart.clear();
6423            for engine in &self.ranks {
6424                let _m = engine.gpu.enter_main()?;
6425                ws.tcol_gated.push(engine.uninit(32 * lq)?);
6426                ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6427            }
6428            let root = &self.ranks[0];
6429            let _m = root.gpu.enter_main()?;
6430            ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6431            ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6432            ws.tcol_ocap = 32;
6433        }
6434        for rank in 0..ranks {
6435            let engine = &self.ranks[rank];
6436            let _main = engine.gpu.enter_main()?;
6437            let mut dst = ws.tcol_gated[rank].slice_mut(col * lq..(col + 1) * lq);
6438            engine
6439                .stream()
6440                .memcpy_dtod(&ws.gated[rank].slice(0..lq), &mut dst)?;
6441            // The skipped finish's e-wait was ALSO the anti-dependency guard: it ordered
6442            // e's NEXT column's h/pos re-staging behind this column's rank-side raw pulls.
6443            // Record each rank here and make e wait — same protection, no o_proj work.
6444            ws.ev_rank[rank].record(&engine.stream())?;
6445        }
6446        {
6447            let _main = e.gpu.enter_main()?;
6448            for ev in ws.ev_rank.iter() {
6449                e.stream().wait(ev)?;
6450            }
6451        }
6452        Ok(())
6453    }
6454
6455    /// MEMRA_TCOL_OPROJ join: one weight-amortized b4_tcol per rank over the stashed
6456    /// `gated` slabs (per-column FP order == the t=1 b4 kernel), one peer pull of rank1's
6457    /// partial slab, one elementwise slab add on the root (independent elements — each
6458    /// column's add is the exact direct-join `add(p0, p1)`), then the joined `mixed` slab
6459    /// lands on `e`. Returns [t, o_out] on the model engine.
6460    pub(crate) fn decode_v2_oproj_tcol(
6461        &self,
6462        ws_index: usize,
6463        e: &Engine,
6464        o_m: &ResidentStepBf16RowParallel,
6465        t: usize,
6466    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6467        let ranks = self.ranks.len();
6468        let mut guard = self
6469            .decode_v2
6470            .lock()
6471            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6472        let ws = guard
6473            .get_mut(ws_index)
6474            .ok_or("step TP decode v2 workspace index out of range")?;
6475        if ranks != 2 || ws.blocks_per_rank != 4 || t == 0 || t > 32 || ws.tcol_ocap < t {
6476            return Err("decode_v2_oproj_tcol geometry".into());
6477        }
6478        for rank in 0..ranks {
6479            let engine = &self.ranks[rank];
6480            let _main = engine.gpu.enter_main()?;
6481            let mut weights = Vec::with_capacity(4);
6482            for block in 0..4 {
6483                let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
6484                    return Err("tcol o_proj requires bf16-resident O blocks".into());
6485                };
6486                weights.push(weight);
6487            }
6488            {
6489                let StepTpDecodeV2Ws {
6490                    tcol_gated,
6491                    tcol_opart,
6492                    local_q_dim,
6493                    o_block_cols,
6494                    o_out,
6495                    w8t_oaq,
6496                    w8t_oad,
6497                    w8t_oin,
6498                    w8t_cap,
6499                    ..
6500                } = &mut *ws;
6501                // MEMRA_TCOL_OPROJ_REF=1 (bisect): fill the partial slab via the t=1 b4
6502                // kernel per column — separates choreography bugs from tcol-kernel bugs.
6503                static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6504                let refk = *REFK
6505                    .get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ_REF").as_deref() == Ok("1"));
6506                if refk {
6507                    let lq = *local_q_dim;
6508                    let mut xr = engine.uninit(lq)?;
6509                    let mut yr = engine.uninit(*o_out)?;
6510                    for c in 0..t {
6511                        {
6512                            let mut dst = xr.slice_mut(0..lq);
6513                            engine.stream().memcpy_dtod(
6514                                &tcol_gated[rank].slice(c * lq..(c + 1) * lq),
6515                                &mut dst,
6516                            )?;
6517                        }
6518                        engine.matvec_bf16_b4_into(
6519                            [weights[0], weights[1], weights[2], weights[3]],
6520                            &xr,
6521                            &mut yr,
6522                            *o_block_cols,
6523                            *o_out,
6524                        )?;
6525                        let mut dst = tcol_opart[rank].slice_mut(c * *o_out..(c + 1) * *o_out);
6526                        engine
6527                            .stream()
6528                            .memcpy_dtod(&yr.slice(0..*o_out), &mut dst)?;
6529                    }
6530                } else if crate::step_tp_w8_on()
6531                    && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some())
6532                    && (4 * *o_block_cols) % 32 == 0
6533                {
6534                    // The verify walk's biggest single kernel: bf16 tcol o_proj was 24.8% of
6535                    // spec GPU time. Same planar q8_0 mirrors the decode arm uses, one launch
6536                    // over all t columns.
6537                    let in_f = 4 * *o_block_cols;
6538                    if *w8t_oin != in_f || *w8t_cap < t || w8t_oaq.len() != ranks {
6539                        w8t_oaq.clear();
6540                        w8t_oad.clear();
6541                        for e_rank in &self.ranks {
6542                            let _m = e_rank.gpu.enter_main()?;
6543                            w8t_oaq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
6544                            w8t_oad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
6545                        }
6546                        *w8t_oin = in_f;
6547                        *w8t_cap = (*w8t_cap).max(32);
6548                    }
6549                    engine.quantize_q8_1_into(
6550                        &tcol_gated[rank],
6551                        t,
6552                        in_f,
6553                        &mut w8t_oaq[rank],
6554                        &mut w8t_oad[rank],
6555                    )?;
6556                    engine.qmatvec_q8_0_b4_rp_t_into(
6557                        [
6558                            o_m.ranks[rank][0].q8.as_ref().unwrap(),
6559                            o_m.ranks[rank][1].q8.as_ref().unwrap(),
6560                            o_m.ranks[rank][2].q8.as_ref().unwrap(),
6561                            o_m.ranks[rank][3].q8.as_ref().unwrap(),
6562                        ],
6563                        &w8t_oaq[rank],
6564                        &w8t_oad[rank],
6565                        &mut tcol_opart[rank],
6566                        *o_block_cols,
6567                        *o_out,
6568                        t,
6569                    )?;
6570                } else {
6571                    engine.matvec_bf16_b4_tcol_into(
6572                        [weights[0], weights[1], weights[2], weights[3]],
6573                        &tcol_gated[rank],
6574                        &mut tcol_opart[rank],
6575                        *o_block_cols,
6576                        *o_out,
6577                        t,
6578                    )?;
6579                }
6580            }
6581            if rank != 0 {
6582                ws.ev_rank[rank].record(&engine.stream())?;
6583            }
6584        }
6585        let root = &self.ranks[0];
6586        {
6587            let _main = root.gpu.enter_main()?;
6588            for ev in ws.ev_rank.iter().skip(1) {
6589                root.stream().wait(ev)?;
6590            }
6591            {
6592                let StepTpDecodeV2Ws {
6593                    tcol_opart,
6594                    tcol_opeer,
6595                    tcol_omix,
6596                    o_out,
6597                    ..
6598                } = &mut *ws;
6599                let opeer = tcol_opeer.as_mut().ok_or("tcol o_proj slabs not armed")?;
6600                let omix = tcol_omix.as_mut().ok_or("tcol o_proj slabs not armed")?;
6601                {
6602                    let mut dst = opeer.slice_mut(0..t * *o_out);
6603                    root.stream()
6604                        .memcpy_dtod(&tcol_opart[1].slice(0..t * *o_out), &mut dst)?;
6605                }
6606                // Elementwise over the whole slab: per element identical to the per-column
6607                // direct-join add (independent lanes, same operand values).
6608                root.add(&tcol_opart[0], opeer, omix, t * *o_out)?;
6609            }
6610            ws.ev_oproj.record(&root.stream())?;
6611        }
6612        let _main = e.gpu.enter_main()?;
6613        e.stream().wait(&ws.ev_oproj)?;
6614        let mut out = e.uninit(t * ws.o_out)?;
6615        let omix = ws.tcol_omix.as_ref().ok_or("tcol o_proj slabs not armed")?;
6616        e.stream().memcpy_dtod(
6617            &omix.slice(0..t * ws.o_out),
6618            &mut out.slice_mut(0..t * ws.o_out),
6619        )?;
6620        Ok(out)
6621    }
6622
6623    pub(crate) fn decode_v2_input_qkv(
6624        &self,
6625        ws: &mut StepTpDecodeV2Ws,
6626        e: &Engine,
6627        h: &CudaSlice<f32>,
6628        pos_d: &CudaSlice<i32>,
6629        gate_raw: Option<&CudaSlice<f32>>,
6630        gate_shards: Option<StepTpGateShards<'_>>,
6631        decode_input: &mut ResidentReplicatedDeviceRows,
6632        q_m: &ResidentBf16ColumnParallel,
6633        k_m: &ResidentBf16ColumnParallel,
6634        v_m: &ResidentBf16ColumnParallel,
6635        q_norm: &[CudaSlice<f32>],
6636        k_norm: &[CudaSlice<f32>],
6637        head_dim: usize,
6638        n_rot: usize,
6639        rope_base: f32,
6640        rope_freqs: &[Option<&CudaSlice<f32>>],
6641        rms_eps: f32,
6642        defer_norm_rope: bool,
6643        tcol_col: Option<usize>,
6644    ) -> Result<(), Box<dyn std::error::Error>> {
6645        let ranks = self.ranks.len();
6646        validate_replicated_device_rows(&self.ranks, decode_input)?;
6647        if decode_input.tokens != 1
6648            || decode_input.width != q_m.in_features
6649            || pos_d.len() != 1
6650            || gate_raw.is_some_and(|gate| gate.len() != ws.heads)
6651            || gate_raw.is_none() != gate_shards.is_some()
6652            || gate_shards.as_ref().is_some_and(|shards| match shards {
6653                StepTpGateShards::F32(shards) => shards.len() != ranks,
6654                StepTpGateShards::Bf16(shards) => shards.len() != ranks,
6655            })
6656            || q_norm.len() != ranks
6657            || k_norm.len() != ranks
6658            || rope_freqs.len() != ranks
6659            || e.ctx().ordinal() != ws.e_device
6660        {
6661            return Err("step TP decode v2 input geometry mismatch".into());
6662        }
6663
6664        let qkv_fused = step_tp_qkv_fused_enabled()?;
6665        if gate_shards.is_some() && !qkv_fused {
6666            return Err("step TP decode v2 gate shards require MEMRA_STEP_TP_QKV_FUSED=1".into());
6667        }
6668        let values = decode_input.width;
6669        if h.len() != values {
6670            return Err(format!(
6671                "step TP decode v2 hidden width {} != replicated width {values}",
6672                h.len()
6673            )
6674            .into());
6675        }
6676
6677        if qkv_fused {
6678            // STAGE-BASED flow (graph increment A): h and pos land in fixed e-context stages
6679            // (one e-stream copy each), the entry event covers them, and every rank raw-copies
6680            // from the stages on its own stream — exactly the shape graph capture wraps.
6681            if ws.h_stage.is_none() {
6682                use cudarc::driver::DevicePtr;
6683                let _main = e.gpu.enter_main()?;
6684                let h_stage = e.uninit(values)?;
6685                let pos_stage = e.htod_i32(&[0])?;
6686                {
6687                    let stream = e.stream();
6688                    let (hp, _g0) = h_stage.device_ptr(&stream);
6689                    let (pp, _g1) = pos_stage.device_ptr(&stream);
6690                    ws.raw_h_stage = hp as u64;
6691                    ws.raw_pos_stage = pp as u64;
6692                }
6693                ws.h_stage = Some(h_stage);
6694                ws.pos_stage = Some(pos_stage);
6695                for rank in 0..ranks {
6696                    use cudarc::driver::DevicePtr;
6697                    let engine = &self.ranks[rank];
6698                    let _rmain = engine.gpu.enter_main()?;
6699                    let attn_in = engine.uninit(values)?;
6700                    let (dp, pp) = {
6701                        let stream = engine.stream();
6702                        let (dp, _g2) = attn_in.device_ptr(&stream);
6703                        let (pp, _g3) = ws.pos[rank].device_ptr(&stream);
6704                        (dp as u64, pp as u64)
6705                    };
6706                    ws.raw_attn_in.push(dp);
6707                    ws.raw_pos.push(pp);
6708                    ws.attn_in.push(attn_in);
6709                }
6710                {
6711                    use cudarc::driver::DevicePtr;
6712                    let root = &self.ranks[0];
6713                    let _rmain = root.gpu.enter_main()?;
6714                    let stream = root.stream();
6715                    let (a, _g) = ws.peer_partial.device_ptr(&stream);
6716                    let (b, _g) = ws.k_shadow.device_ptr(&stream);
6717                    let (c, _g) = ws.v_shadow.device_ptr(&stream);
6718                    ws.raw_peer_partial = a as u64;
6719                    ws.raw_k_shadow = b as u64;
6720                    ws.raw_v_shadow = c as u64;
6721                }
6722                {
6723                    use cudarc::driver::DevicePtr;
6724                    let rank1 = &self.ranks[1];
6725                    let _rmain = rank1.gpu.enter_main()?;
6726                    let stream = rank1.stream();
6727                    let (a, _g) = ws.o_partials[1][0].device_ptr(&stream);
6728                    let (b, _g) = ws.k[1].device_ptr(&stream);
6729                    let (c, _g) = ws.v_raw[1].device_ptr(&stream);
6730                    ws.raw_o_partial1 = a as u64;
6731                    ws.raw_k1 = b as u64;
6732                    ws.raw_v1 = c as u64;
6733                }
6734            }
6735            {
6736                let _main = e.gpu.enter_main()?;
6737                {
6738                    // (Always staged: a tcol column below the dcw floor falls back to the
6739                    // normal fused arm, which reads h through this stage.)
6740                    let h_stage = ws.h_stage.as_mut().expect("stage armed above");
6741                    let mut dst = h_stage.slice_mut(0..values);
6742                    e.stream().memcpy_dtod(&h.slice(0..values), &mut dst)?;
6743                }
6744                {
6745                    let pos_stage = ws.pos_stage.as_mut().expect("stage armed above");
6746                    let mut dst = pos_stage.slice_mut(0..1);
6747                    e.stream().memcpy_dtod(&pos_d.slice(0..1), &mut dst)?;
6748                }
6749                ws.ev_entry.record(&e.stream())?;
6750            }
6751            for rank in 0..ranks {
6752                let engine = &self.ranks[rank];
6753                let _main = engine.gpu.enter_main()?;
6754                engine.stream().wait(&ws.ev_entry)?;
6755            }
6756        } else {
6757            // Evented replicate flow (the pre-stage shape, kept for the non-fused class).
6758            {
6759                let _main = e.gpu.enter_main()?;
6760                if let Some(gate_raw) = gate_raw {
6761                    let mut gate_dst = ws.gate_e.slice_mut(0..ws.heads);
6762                    e.stream()
6763                        .memcpy_dtod(&gate_raw.slice(0..ws.heads), &mut gate_dst)?;
6764                }
6765                ws.ev_entry.record(&e.stream())?;
6766            }
6767            {
6768                let root = &self.ranks[0];
6769                let _main = root.gpu.enter_main()?;
6770                root.stream().wait(&ws.ev_entry)?;
6771                let mut destination = decode_input.ranks[0].slice_mut(0..values);
6772                root.stream()
6773                    .memcpy_dtod(&h.slice(0..values), &mut destination)?;
6774                ws.ev_refresh.record(&root.stream())?;
6775            }
6776            for rank in 1..ranks {
6777                let engine = &self.ranks[rank];
6778                let _main = engine.gpu.enter_main()?;
6779                engine.stream().wait(&ws.ev_refresh)?;
6780                let (root_rows, peer_rows) = decode_input.ranks.split_at_mut(rank);
6781                let mut destination = peer_rows[0].slice_mut(0..values);
6782                engine
6783                    .stream()
6784                    .memcpy_dtod(&root_rows[0].slice(0..values), &mut destination)?;
6785            }
6786        }
6787        for rank in 0..ranks {
6788            self.decode_v2_input_qkv_rank(
6789                ws,
6790                pos_d,
6791                decode_input,
6792                q_m,
6793                k_m,
6794                v_m,
6795                q_norm,
6796                k_norm,
6797                head_dim,
6798                n_rot,
6799                rope_base,
6800                rope_freqs,
6801                rms_eps,
6802                gate_shards.as_ref(),
6803                qkv_fused,
6804                defer_norm_rope,
6805                rank,
6806                tcol_col,
6807            )?;
6808        }
6809        Ok(())
6810    }
6811
6812    /// One rank's slice of `decode_v2_input_qkv` (projection, norm+rope, gate staging) — the
6813    /// per-device issue unit the whole-token graph captures on that rank's stream.
6814    #[allow(clippy::too_many_arguments)]
6815    pub(crate) fn decode_v2_input_qkv_rank(
6816        &self,
6817        ws: &mut StepTpDecodeV2Ws,
6818        pos_d: &CudaSlice<i32>,
6819        decode_input: &mut ResidentReplicatedDeviceRows,
6820        q_m: &ResidentBf16ColumnParallel,
6821        k_m: &ResidentBf16ColumnParallel,
6822        v_m: &ResidentBf16ColumnParallel,
6823        q_norm: &[CudaSlice<f32>],
6824        k_norm: &[CudaSlice<f32>],
6825        head_dim: usize,
6826        n_rot: usize,
6827        rope_base: f32,
6828        rope_freqs: &[Option<&CudaSlice<f32>>],
6829        rms_eps: f32,
6830        gate_shards: Option<&StepTpGateShards<'_>>,
6831        qkv_fused: bool,
6832        defer_norm_rope: bool,
6833        rank: usize,
6834        tcol_col: Option<usize>,
6835    ) -> Result<(), Box<dyn std::error::Error>> {
6836        let ranks = self.ranks.len();
6837        let local_heads = ws.local_q_dim / head_dim;
6838        let local_kv_heads = ws.local_kv_dim / head_dim;
6839        let engine = &self.ranks[rank];
6840        let _main = engine.gpu.enter_main()?;
6841        let ws_e_device = ws.e_device;
6842        // T-COLUMN SELECT (spec verify): the projections for this column were precomputed
6843        // by the weight-amortized tcol kernel — copy the column into the single-row buffers
6844        // (pure f32 moves, bit-exact) and skip the per-column matvec. Rope/norm/append run
6845        // below exactly as in the t=1 program.
6846        if qkv_fused && tcol_col.is_some() {
6847            let c = tcol_col.expect("checked");
6848            if ws.tcol_cap == 0 || ws.tcol_q.len() != ranks {
6849                return Err("tcol select without precompute".into());
6850            }
6851            // The select skips the matvec but NOT the position: rope/append below still
6852            // read this rank's pos buffer, which only the (skipped) stage path fills for
6853            // peer-device ranks. Stage it here or rank1 ropes at the previous position.
6854            if engine.ctx().ordinal() != ws_e_device {
6855                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
6856            }
6857            let StepTpDecodeV2Ws {
6858                tcol_q,
6859                tcol_k,
6860                tcol_v,
6861                tcol_g,
6862                q_raw,
6863                k_raw,
6864                v_raw,
6865                gate,
6866                local_q_dim,
6867                local_kv_dim,
6868                heads,
6869                ..
6870            } = &mut *ws;
6871            let lg = *heads / ranks;
6872            let stream = engine.stream();
6873            {
6874                let mut dst = q_raw[rank].slice_mut(0..*local_q_dim);
6875                stream.memcpy_dtod(
6876                    &tcol_q[rank].slice(c * *local_q_dim..(c + 1) * *local_q_dim),
6877                    &mut dst,
6878                )?;
6879            }
6880            {
6881                let mut dst = k_raw[rank].slice_mut(0..*local_kv_dim);
6882                stream.memcpy_dtod(
6883                    &tcol_k[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
6884                    &mut dst,
6885                )?;
6886            }
6887            {
6888                let mut dst = v_raw[rank].slice_mut(0..*local_kv_dim);
6889                stream.memcpy_dtod(
6890                    &tcol_v[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
6891                    &mut dst,
6892                )?;
6893            }
6894            if lg > 0 {
6895                let mut dst = gate[rank].slice_mut(0..lg);
6896                stream.memcpy_dtod(&tcol_g[rank].slice(c * lg..(c + 1) * lg), &mut dst)?;
6897            }
6898            if !defer_norm_rope {
6899                // Below the dcw floor (or a non-defer shape) the col-select cannot apply:
6900                // fall through and recompute this column's QKV from the REAL h row — the
6901                // caller always passes it. The slab copies above are dead stores.
6902            } else {
6903                return Ok(());
6904            }
6905        }
6906        if qkv_fused {
6907            // Stage-based input: raw copies from the fixed e-context stages (capture-safe;
6908            // eager ordering comes from the caller's ev_entry wait on this stream). The rank
6909            // SHARING e's device reads the stages directly — same context (probed), ordering
6910            // identical (ev_entry / graph edge), bytes identical: the copies are pure waste.
6911            let same_dev = engine.ctx().ordinal() == ws.e_device;
6912            if !same_dev {
6913                raw_copy_bytes(
6914                    ws.raw_attn_in[rank],
6915                    ws.raw_h_stage,
6916                    q_m.in_features * 4,
6917                    engine,
6918                )?;
6919                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
6920            }
6921            let StepTpDecodeV2Ws {
6922                q_raw,
6923                k_raw,
6924                v_raw,
6925                gate,
6926                gate_e,
6927                attn_in,
6928                h_stage,
6929                heads,
6930                local_q_dim,
6931                local_kv_dim,
6932                w8_aq,
6933                w8_ad,
6934                w8_in,
6935                ..
6936            } = &mut *ws;
6937            let input_ref: &CudaSlice<f32> = if same_dev {
6938                h_stage
6939                    .as_ref()
6940                    .ok_or("step TP decode v2 stage not armed")?
6941            } else {
6942                &attn_in[rank]
6943            };
6944            match (
6945                &q_m.ranks[rank].weight,
6946                &k_m.ranks[rank].weight,
6947                &v_m.ranks[rank].weight,
6948            ) {
6949                (
6950                    ResidentBf16Weight::F32(wq),
6951                    ResidentBf16Weight::F32(wk),
6952                    ResidentBf16Weight::F32(wv),
6953                ) => {
6954                    let (wg, out_g) = match &gate_shards {
6955                        Some(StepTpGateShards::F32(shards)) => (&shards[rank], *heads / ranks),
6956                        Some(StepTpGateShards::Bf16(_)) => {
6957                            return Err("step TP decode v2 gate shard class does not \
6958                                            match the F32 projections"
6959                                .into());
6960                        }
6961                        // out_g = 0: the kernel never reads wg; any resident buffer works.
6962                        None => (&*gate_e, 0),
6963                    };
6964                    engine.matvec_f32_qkv_into(
6965                        wq,
6966                        wk,
6967                        wv,
6968                        wg,
6969                        input_ref,
6970                        &mut q_raw[rank],
6971                        &mut k_raw[rank],
6972                        &mut v_raw[rank],
6973                        &mut gate[rank],
6974                        q_m.in_features,
6975                        *local_q_dim,
6976                        *local_kv_dim,
6977                        out_g,
6978                    )?;
6979                }
6980                (
6981                    ResidentBf16Weight::Bf16(wq),
6982                    ResidentBf16Weight::Bf16(wk),
6983                    ResidentBf16Weight::Bf16(wv),
6984                ) => {
6985                    let (wg, out_g) = match &gate_shards {
6986                        Some(StepTpGateShards::Bf16(shards)) => (&shards[rank], *heads / ranks),
6987                        Some(StepTpGateShards::F32(_)) => {
6988                            return Err("step TP decode v2 gate shard class does not \
6989                                            match the bf16 projections"
6990                                .into());
6991                        }
6992                        None => (wq, 0),
6993                    };
6994                    // MEMRA_STEP_TP_W8: q8_0 weights + q8_1 activation through mmvq instead of
6995                    // the fused bf16 qkvg. NUMERIC CLASS (int8 dp4a with per-32 scales, not a
6996                    // bf16 fma chain) — argmax-gated, never a bit-tape flip. Q, K and V each
6997                    // get their own launch because the fused kernel has no q8 twin; the gate
6998                    // rows stay bf16 (32 rows, ~0.3 MB, nothing to win and one less class to
6999                    // qualify). Measured motive: 23.0 us bf16 -> 14.0 us q8 at this shape.
7000                    let in_f = q_m.in_features;
7001                    let q8_ready = crate::step_tp_w8_on()
7002                        && q_m.ranks[rank].q8.is_some()
7003                        && k_m.ranks[rank].q8.is_some()
7004                        && v_m.ranks[rank].q8.is_some();
7005                    if q8_ready {
7006                        if *w8_in != in_f || w8_aq.len() != ranks {
7007                            w8_aq.clear();
7008                            w8_ad.clear();
7009                            for e_rank in &self.ranks {
7010                                let _m = e_rank.gpu.enter_main()?;
7011                                w8_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
7012                                w8_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
7013                            }
7014                            *w8_in = in_f;
7015                        }
7016                        engine.quantize_q8_1_into(
7017                            input_ref,
7018                            1,
7019                            in_f,
7020                            &mut w8_aq[rank],
7021                            &mut w8_ad[rank],
7022                        )?;
7023                        // ONE launch over the stacked q/k/v rows. The three-call version
7024                        // measured 79.52 vs 80.72 tok/s — SLOWER than the bf16 fused kernel —
7025                        // because three launches plus the activation quantize cost more than
7026                        // the halved weight bytes save. Bit-identical to those three calls.
7027                        engine.qmatvec_q8_0_qkv_rp_into(
7028                            q_m.ranks[rank].q8.as_ref().unwrap(),
7029                            k_m.ranks[rank].q8.as_ref().unwrap(),
7030                            v_m.ranks[rank].q8.as_ref().unwrap(),
7031                            &w8_aq[rank],
7032                            &w8_ad[rank],
7033                            &mut q_raw[rank],
7034                            &mut k_raw[rank],
7035                            &mut v_raw[rank],
7036                            in_f,
7037                            *local_q_dim,
7038                            *local_kv_dim,
7039                        )?;
7040                        if out_g > 0 {
7041                            engine.matvec_bf16_into(wg, input_ref, &mut gate[rank], in_f, out_g)?;
7042                        }
7043                    } else {
7044                        engine.matvec_bf16_qkvg_into(
7045                            wq,
7046                            wk,
7047                            wv,
7048                            wg,
7049                            input_ref,
7050                            &mut q_raw[rank],
7051                            &mut k_raw[rank],
7052                            &mut v_raw[rank],
7053                            &mut gate[rank],
7054                            q_m.in_features,
7055                            *local_q_dim,
7056                            *local_kv_dim,
7057                            out_g,
7058                        )?;
7059                    }
7060                }
7061                _ => {
7062                    return Err("step TP decode v2 QKV projections mix residency classes".into());
7063                }
7064            }
7065        } else {
7066            for (matrix, local_out, raw) in [
7067                (q_m, ws.local_q_dim, &mut ws.q_raw),
7068                (k_m, ws.local_kv_dim, &mut ws.k_raw),
7069                (v_m, ws.local_kv_dim, &mut ws.v_raw),
7070            ] {
7071                let ResidentBf16Weight::F32(values_w) = &matrix.ranks[rank].weight else {
7072                    return Err("step TP decode v2 lost its F32 projection residency".into());
7073                };
7074                let chunk_rows = matrix.canonical_chunk_rows.unwrap_or(local_out);
7075                engine.linear_f32_resident_canonical_rows_t1_into(
7076                    &decode_input.ranks[rank],
7077                    values_w,
7078                    &mut raw[rank],
7079                    matrix.in_features,
7080                    local_out,
7081                    chunk_rows,
7082                )?;
7083            }
7084        }
7085        if qkv_fused && defer_norm_rope {
7086            // FUSION #1 defers norm+rope to the caller's fused rope+append+inc launch.
7087        } else if qkv_fused {
7088            // Fused norm+rope: one launch; the position comes from the rank-local staged
7089            // copy (raw-copied above from the fixed e-context pos stage — capture-safe).
7090            let StepTpDecodeV2Ws {
7091                q_raw,
7092                k_raw,
7093                q,
7094                k,
7095                pos,
7096                pos_stage,
7097                ..
7098            } = &mut *ws;
7099            let same_dev = engine.ctx().ordinal() == ws_e_device;
7100            let pos_ref: &CudaSlice<i32> = if same_dev {
7101                pos_stage
7102                    .as_ref()
7103                    .ok_or("step TP decode v2 pos stage not armed")?
7104            } else {
7105                &pos[rank]
7106            };
7107            engine.qk_norm_rope_into(
7108                &q_raw[rank],
7109                &k_raw[rank],
7110                &q_norm[rank],
7111                &k_norm[rank],
7112                &mut q[rank],
7113                &mut k[rank],
7114                pos_ref,
7115                head_dim,
7116                n_rot,
7117                local_heads,
7118                local_kv_heads,
7119                rms_eps,
7120                rope_base,
7121                1.0,
7122                rope_freqs[rank],
7123            )?;
7124        } else {
7125            engine.rms_norm(
7126                &ws.q_raw[rank],
7127                &q_norm[rank],
7128                &mut ws.q[rank],
7129                head_dim,
7130                local_heads,
7131                rms_eps,
7132            )?;
7133            engine.rms_norm(
7134                &ws.k_raw[rank],
7135                &k_norm[rank],
7136                &mut ws.k[rank],
7137                head_dim,
7138                local_kv_heads,
7139                rms_eps,
7140            )?;
7141            {
7142                let mut pos_dst = ws.pos[rank].slice_mut(0..1);
7143                engine
7144                    .stream()
7145                    .memcpy_dtod(&pos_d.slice(0..1), &mut pos_dst)?;
7146            }
7147            engine.rope_neox2(
7148                &mut ws.q[rank],
7149                &mut ws.k[rank],
7150                &ws.pos[rank],
7151                head_dim,
7152                n_rot,
7153                local_heads,
7154                local_kv_heads,
7155                1,
7156                rope_base,
7157                1.0,
7158                rope_freqs[rank],
7159            )?;
7160        }
7161        if gate_shards.is_none() {
7162            let gate_start = rank * (ws.heads / ranks);
7163            let mut gate_dst = ws.gate[rank].slice_mut(0..ws.heads / ranks);
7164            engine.stream().memcpy_dtod(
7165                &ws.gate_e.slice(gate_start..gate_start + ws.heads / ranks),
7166                &mut gate_dst,
7167            )?;
7168        }
7169        Ok(())
7170    }
7171
7172    /// One rank's O-partial slice of `decode_v2_finish` — the per-device issue unit the
7173    /// whole-token graph captures on that rank's stream (the rank-done event stays with the
7174    /// eager caller; graphs order via parent edges instead).
7175    pub(crate) fn decode_v2_finish_rank_partial(
7176        &self,
7177        ws: &mut StepTpDecodeV2Ws,
7178        o_m: &ResidentStepBf16RowParallel,
7179        o_fused: bool,
7180        rank: usize,
7181    ) -> Result<(), Box<dyn std::error::Error>> {
7182        let engine = &self.ranks[rank];
7183        let _main = engine.gpu.enter_main()?;
7184        if o_fused {
7185            let StepTpDecodeV2Ws {
7186                gated,
7187                o_partials,
7188                o_block_cols,
7189                o_out,
7190                w8o_aq,
7191                w8o_ad,
7192                w8o_in,
7193                ..
7194            } = &mut *ws;
7195            let all_f32 = o_m.ranks[rank]
7196                .iter()
7197                .all(|block| matches!(block.weight, ResidentBf16Weight::F32(_)));
7198            if all_f32 {
7199                let mut weights = Vec::with_capacity(4);
7200                for block in 0..4 {
7201                    let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
7202                        unreachable!("all_f32 checked above");
7203                    };
7204                    weights.push(weight);
7205                }
7206                engine.matvec_f32_b4_into(
7207                    [weights[0], weights[1], weights[2], weights[3]],
7208                    &gated[rank],
7209                    &mut o_partials[rank][0],
7210                    *o_block_cols,
7211                    *o_out,
7212                )?;
7213            } else if crate::step_tp_w8_on() && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some()) {
7214                // MEMRA_STEP_TP_W8, o_proj half: quantize the gated attention output once and
7215                // run all four HEAD_SPLIT blocks in one q8 launch. Measured motive: bf16 b4 is
7216                // 24.2 us/layer against 11.7 for the q8 shape — the largest decode line left
7217                // after the QKV arm banked +2.9%.
7218                let in_f = 4 * *o_block_cols;
7219                if *w8o_in != in_f || w8o_aq.len() != self.ranks.len() {
7220                    w8o_aq.clear();
7221                    w8o_ad.clear();
7222                    for e_rank in &self.ranks {
7223                        let _m = e_rank.gpu.enter_main()?;
7224                        w8o_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
7225                        w8o_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
7226                    }
7227                    *w8o_in = in_f;
7228                }
7229                engine.quantize_q8_1_into(
7230                    &gated[rank],
7231                    1,
7232                    in_f,
7233                    &mut w8o_aq[rank],
7234                    &mut w8o_ad[rank],
7235                )?;
7236                engine.qmatvec_q8_0_b4_rp_into(
7237                    [
7238                        o_m.ranks[rank][0].q8.as_ref().unwrap(),
7239                        o_m.ranks[rank][1].q8.as_ref().unwrap(),
7240                        o_m.ranks[rank][2].q8.as_ref().unwrap(),
7241                        o_m.ranks[rank][3].q8.as_ref().unwrap(),
7242                    ],
7243                    &w8o_aq[rank],
7244                    &w8o_ad[rank],
7245                    &mut o_partials[rank][0],
7246                    *o_block_cols,
7247                    *o_out,
7248                )?;
7249            } else {
7250                let mut weights = Vec::with_capacity(4);
7251                for block in 0..4 {
7252                    let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
7253                        return Err("step TP decode v2 O projections mix residency classes".into());
7254                    };
7255                    weights.push(weight);
7256                }
7257                engine.matvec_bf16_b4_into(
7258                    [weights[0], weights[1], weights[2], weights[3]],
7259                    &gated[rank],
7260                    &mut o_partials[rank][0],
7261                    *o_block_cols,
7262                    *o_out,
7263                )?;
7264            }
7265        } else {
7266            for block in 0..ws.blocks_per_rank {
7267                let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
7268                    return Err("step TP decode v2 lost its F32 O residency".into());
7269                };
7270                let x =
7271                    ws.gated[rank].slice(block * ws.o_block_cols..(block + 1) * ws.o_block_cols);
7272                let w = weight.slice(0..weight.len());
7273                let mut y = ws.o_partials[rank][block].slice_mut(0..ws.o_out);
7274                engine.linear_t1_into(&x, &w, &mut y, ws.o_block_cols, ws.o_out)?;
7275            }
7276        }
7277        Ok(())
7278    }
7279
7280    /// v2 phase 2: canonical-block O reduction on the root device plus the K/V shadow gathers,
7281    /// returning a fresh model-engine output ordered behind `ev_oproj` on `e`'s stream.
7282    ///
7283    /// The caller must have queued every rank's attention work (reading `ws.gated`, `ws.k`,
7284    /// `ws.v_raw`) on the rank streams before this call. Reduction order is identical to
7285    /// `step_bf16_row_parallel_resident_native`: zeros, then rank 0's blocks, then each peer
7286    /// rank's blocks, one `add` per block.
7287    pub(crate) fn decode_v2_finish(
7288        &self,
7289        ws: &mut StepTpDecodeV2Ws,
7290        e: &Engine,
7291        o_m: &ResidentStepBf16RowParallel,
7292    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7293        let ranks = self.ranks.len();
7294        if e.ctx().ordinal() != ws.e_device {
7295            return Err("step TP decode v2 finish engine changed".into());
7296        }
7297        // MEMRA_STEP_TP_QKV_FUSED extends to the O path: one matvec_f32_b4 launch per rank
7298        // (in-order canonical block accumulation per element) and a single peer-copy + add on
7299        // the root, replacing 4 cuBLASLt launches per rank + the 4-copy/8-add chain. Same
7300        // numeric-class door and gate as the fused QKV projection.
7301        let o_fused = step_tp_qkv_fused_enabled()? && ws.blocks_per_rank == 4 && ranks == 2;
7302
7303        // Per-rank O block partials on the owning rank's stream (serial after the attention
7304        // kernels the driver queued there), then the rank-done event for root's peer reads.
7305        for rank in 0..ranks {
7306            self.decode_v2_finish_rank_partial(ws, o_m, o_fused, rank)?;
7307            if rank == 0 {
7308                // root == rank0: its own stream order covers the partial; only peers need
7309                // the record/wait pair (host-op diet, matches the routes-arm skip).
7310                continue;
7311            }
7312            let engine = &self.ranks[rank];
7313            let _main = engine.gpu.enter_main()?;
7314            ws.ev_rank[rank].record(&engine.stream())?;
7315        }
7316
7317        // Root reduce in canonical order + shadow gathers, all on the root stream.
7318        let root = &self.ranks[0];
7319        #[allow(unused_assignments)]
7320        let mut final_in_a = false;
7321        {
7322            let _main = root.gpu.enter_main()?;
7323            for ev in ws.ev_rank.iter().skip(1) {
7324                root.stream().wait(ev)?;
7325            }
7326            if o_fused && oproj_direct_on() && ranks == 2 && no_local_shadow_on() {
7327                // DIRECT JOIN: rank1's partial already sits in root memory (P2P kernel
7328                // stores; visibility guaranteed by the ev_rank[1] wait above), rank0's
7329                // partial is root-stream-ordered — record ONE event and let the model
7330                // engine do the single add itself, straight into its own output row.
7331                // Same operands, same add order as finish_root_fused: BIT-IDENTICAL.
7332                ws.ev_oproj.record(&root.stream())?;
7333                let _main = e.gpu.enter_main()?;
7334                e.stream().wait(&ws.ev_oproj)?;
7335                let mut output = e.uninit(ws.o_out)?;
7336                if oproj_tail_on() && oproj_tail_eligible() {
7337                    // M2: defer the add into the residual+norm consumer (waits stay HERE;
7338                    // only the arithmetic moves). `output` is returned unwritten.
7339                    use cudarc::driver::DevicePtr;
7340                    let stream = e.stream();
7341                    let (p0, _g0) = ws.o_partials[0][0].device_ptr(&stream);
7342                    let (p1, _g1) = ws.o_partials[1][0].device_ptr(&stream);
7343                    set_oproj_tail((p0 as u64, p1 as u64));
7344                    return Ok(output);
7345                }
7346                e.add(
7347                    &ws.o_partials[0][0],
7348                    &ws.o_partials[1][0],
7349                    &mut output,
7350                    ws.o_out,
7351                )?;
7352                return Ok(output);
7353            }
7354            if o_fused {
7355                self.decode_v2_finish_root_fused(ws)?;
7356                ws.ev_oproj.record(&root.stream())?;
7357                let _main = e.gpu.enter_main()?;
7358                e.stream().wait(&ws.ev_oproj)?;
7359                let mut output = e.uninit(ws.o_out)?;
7360                e.stream().memcpy_dtod(
7361                    &ws.reduce_a.slice(0..ws.o_out),
7362                    &mut output.slice_mut(0..ws.o_out),
7363                )?;
7364                return Ok(output);
7365            }
7366            let mut first = true;
7367            let mut current_is_a = false;
7368            for rank in 0..ranks {
7369                for block in 0..ws.blocks_per_rank {
7370                    let use_peer = rank != 0;
7371                    if use_peer {
7372                        root.stream()
7373                            .memcpy_dtod(&ws.o_partials[rank][block], &mut ws.peer_partial)?;
7374                    }
7375                    // add(prev, partial) -> the other reduce buffer, exactly one add per block
7376                    match (first, current_is_a, use_peer) {
7377                        (true, _, true) => {
7378                            root.add(&ws.zeros, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
7379                        }
7380                        (true, _, false) => root.add(
7381                            &ws.zeros,
7382                            &ws.o_partials[0][block],
7383                            &mut ws.reduce_a,
7384                            ws.o_out,
7385                        )?,
7386                        (false, true, true) => {
7387                            root.add(&ws.reduce_a, &ws.peer_partial, &mut ws.reduce_b, ws.o_out)?
7388                        }
7389                        (false, true, false) => root.add(
7390                            &ws.reduce_a,
7391                            &ws.o_partials[0][block],
7392                            &mut ws.reduce_b,
7393                            ws.o_out,
7394                        )?,
7395                        (false, false, true) => {
7396                            root.add(&ws.reduce_b, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
7397                        }
7398                        (false, false, false) => root.add(
7399                            &ws.reduce_b,
7400                            &ws.o_partials[0][block],
7401                            &mut ws.reduce_a,
7402                            ws.o_out,
7403                        )?,
7404                    }
7405                    current_is_a = first || !current_is_a;
7406                    first = false;
7407                }
7408            }
7409            final_in_a = current_is_a;
7410
7411            for rank in 0..ranks {
7412                let start = rank * ws.local_kv_dim;
7413                let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
7414                root.stream().memcpy_dtod(&ws.k[rank], &mut k_dst)?;
7415                let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
7416                root.stream().memcpy_dtod(&ws.v_raw[rank], &mut v_dst)?;
7417            }
7418            ws.ev_oproj.record(&root.stream())?;
7419        }
7420
7421        // Model-engine output: e waits the root event, then copies the reduced row into a
7422        // fresh e-context buffer (same ownership contract as v1's `e.htod`). The same wait
7423        // orders the driver's shadow append (it reads ws.k_shadow/ws.v_shadow on e's stream).
7424        let _main = e.gpu.enter_main()?;
7425        e.stream().wait(&ws.ev_oproj)?;
7426        let mut output = e.uninit(ws.o_out)?;
7427        let source = if final_in_a {
7428            &ws.reduce_a
7429        } else {
7430            &ws.reduce_b
7431        };
7432        e.stream().memcpy_dtod(
7433            &source.slice(0..ws.o_out),
7434            &mut output.slice_mut(0..ws.o_out),
7435        )?;
7436        Ok(output)
7437    }
7438
7439    pub fn run_routed_experts(
7440        &self,
7441        experts: &ResidentExpertParallel,
7442        input: &[f32],
7443        tokens: usize,
7444        selected: &[usize],
7445        route_weights: &[f32],
7446        experts_per_token: usize,
7447        activation_limit: Option<f32>,
7448    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7449        validate_step_expert_activation_limit(activation_limit)?;
7450        validate_ep_residency(&self.ranks, experts)?;
7451        validate_activations(input, tokens, experts.input_width)?;
7452        let pairs = tokens
7453            .checked_mul(experts_per_token)
7454            .ok_or("EP route count overflow")?;
7455        if selected.len() != pairs || route_weights.len() != pairs {
7456            return Err(format!(
7457                "EP routes selected={} weights={} != tokens {tokens} x experts/token \
7458                 {experts_per_token} ({pairs})",
7459                selected.len(),
7460                route_weights.len(),
7461            )
7462            .into());
7463        }
7464        if !route_weights.iter().all(|weight| weight.is_finite()) {
7465            return Err("EP route weights contain a non-finite value".into());
7466        }
7467        if self.native_p2p {
7468            return self.run_routed_experts_native(
7469                experts,
7470                input,
7471                tokens,
7472                selected,
7473                route_weights,
7474                experts_per_token,
7475                activation_limit,
7476            );
7477        }
7478
7479        let mut output = vec![0.0f32; tokens * experts.input_width];
7480        let per_rank = experts.expert_count / experts.ranks.len();
7481        for token in 0..tokens {
7482            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
7483            for slot in 0..experts_per_token {
7484                let pair = token * experts_per_token + slot;
7485                let expert = selected[pair];
7486                if expert >= experts.expert_count {
7487                    return Err(format!(
7488                        "EP selected expert {expert} outside 0..{}",
7489                        experts.expert_count
7490                    )
7491                    .into());
7492                }
7493                let owner = expert / per_rank;
7494                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
7495                let rank = &experts.ranks[owner];
7496                let engine = &self.ranks[owner];
7497                let gate =
7498                    run_resident_bank_expert(engine, &rank.gate, local_expert, input_row, 1)?;
7499                let up = run_resident_bank_expert(engine, &rank.up, local_expert, input_row, 1)?;
7500                let activated: Vec<f32> = gate
7501                    .iter()
7502                    .zip(&up)
7503                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
7504                    .collect();
7505                debug_assert_eq!(activated.len(), experts.expert_width);
7506                let down =
7507                    run_resident_bank_expert(engine, &rank.down, local_expert, &activated, 1)?;
7508                let weight = route_weights[pair];
7509                for (sum, value) in output
7510                    [token * experts.input_width..(token + 1) * experts.input_width]
7511                    .iter_mut()
7512                    .zip(down)
7513                {
7514                    *sum += weight * value;
7515                }
7516            }
7517        }
7518        Ok(output)
7519    }
7520
7521    fn run_routed_experts_native(
7522        &self,
7523        experts: &ResidentExpertParallel,
7524        input: &[f32],
7525        tokens: usize,
7526        selected: &[usize],
7527        route_weights: &[f32],
7528        experts_per_token: usize,
7529        activation_limit: Option<f32>,
7530    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7531        if !self.native_p2p || self.ranks.len() < 2 {
7532            return Err("native EP execution requires at least two P2P ranks".into());
7533        }
7534        if self.ep_device_arithmetic {
7535            return self.run_routed_experts_native_device(
7536                experts,
7537                input,
7538                tokens,
7539                selected,
7540                route_weights,
7541                experts_per_token,
7542                activation_limit,
7543            );
7544        }
7545        let mut output = vec![0.0f32; tokens * experts.input_width];
7546        let per_rank = experts.expert_count / experts.ranks.len();
7547        for token in 0..tokens {
7548            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
7549            let mut rank_inputs = (0..self.ranks.len())
7550                .map(|_| None)
7551                .collect::<Vec<Option<CudaSlice<f32>>>>();
7552            rank_inputs[0] = Some({
7553                let root = &self.ranks[0];
7554                let _main = root.gpu.enter_main()?;
7555                root.htod(input_row)?
7556            });
7557
7558            for slot in 0..experts_per_token {
7559                let pair = token * experts_per_token + slot;
7560                let expert = selected[pair];
7561                if expert >= experts.expert_count {
7562                    return Err(format!(
7563                        "EP selected expert {expert} outside 0..{}",
7564                        experts.expert_count
7565                    )
7566                    .into());
7567                }
7568                let owner = expert / per_rank;
7569                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
7570                if rank_inputs[owner].is_none() {
7571                    let peer_input = {
7572                        let root_input = rank_inputs[0]
7573                            .as_ref()
7574                            .ok_or("native EP lost its root input")?;
7575                        let engine = &self.ranks[owner];
7576                        let _main = engine.gpu.enter_main()?;
7577                        let mut peer_input = engine.uninit(experts.input_width)?;
7578                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
7579                        peer_input
7580                    };
7581                    rank_inputs[owner] = Some(peer_input);
7582                }
7583
7584                let rank = &experts.ranks[owner];
7585                let engine = &self.ranks[owner];
7586                let owner_input = rank_inputs[owner]
7587                    .as_ref()
7588                    .ok_or("native EP owner input is absent after dispatch")?;
7589                let gate = run_resident_bank_expert_device(
7590                    engine,
7591                    &rank.gate,
7592                    local_expert,
7593                    owner_input,
7594                    1,
7595                )?;
7596                let up = run_resident_bank_expert_device(
7597                    engine,
7598                    &rank.up,
7599                    local_expert,
7600                    owner_input,
7601                    1,
7602                )?;
7603                let (gate, up) = {
7604                    let _main = engine.gpu.enter_main()?;
7605                    (engine.dtoh(&gate)?, engine.dtoh(&up)?)
7606                };
7607                let activated = gate
7608                    .iter()
7609                    .zip(&up)
7610                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
7611                    .collect::<Vec<_>>();
7612                debug_assert_eq!(activated.len(), experts.expert_width);
7613                let activated = {
7614                    let _main = engine.gpu.enter_main()?;
7615                    engine.htod(&activated)?
7616                };
7617                let down = run_resident_bank_expert_device(
7618                    engine,
7619                    &rank.down,
7620                    local_expert,
7621                    &activated,
7622                    1,
7623                )?;
7624                let down = if owner == 0 {
7625                    let _main = engine.gpu.enter_main()?;
7626                    engine.dtoh(&down)?
7627                } else {
7628                    let root = &self.ranks[0];
7629                    let _main = root.gpu.enter_main()?;
7630                    let mut root_down = root.uninit(experts.input_width)?;
7631                    root.stream().memcpy_dtod(&down, &mut root_down)?;
7632                    root.dtoh(&root_down)?
7633                };
7634                let weight = route_weights[pair];
7635                for (sum, value) in output
7636                    [token * experts.input_width..(token + 1) * experts.input_width]
7637                    .iter_mut()
7638                    .zip(down)
7639                {
7640                    *sum += weight * value;
7641                }
7642            }
7643        }
7644        Ok(output)
7645    }
7646
7647    fn run_routed_experts_native_device(
7648        &self,
7649        experts: &ResidentExpertParallel,
7650        input: &[f32],
7651        tokens: usize,
7652        selected: &[usize],
7653        route_weights: &[f32],
7654        experts_per_token: usize,
7655        activation_limit: Option<f32>,
7656    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7657        if !self.native_p2p || !self.ep_device_arithmetic || self.ranks.len() < 2 {
7658            return Err(
7659                "device-resident EP arithmetic requires at least two native P2P ranks".into(),
7660            );
7661        }
7662        let mut output = Vec::with_capacity(tokens * experts.input_width);
7663        let per_rank = experts.expert_count / experts.ranks.len();
7664        let root = &self.ranks[0];
7665        for token in 0..tokens {
7666            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
7667            let mut rank_inputs = (0..self.ranks.len())
7668                .map(|_| None)
7669                .collect::<Vec<Option<CudaSlice<f32>>>>();
7670            rank_inputs[0] = Some({
7671                let _main = root.gpu.enter_main()?;
7672                root.htod(input_row)?
7673            });
7674            let mut root_output = {
7675                let _main = root.gpu.enter_main()?;
7676                root.zeros(experts.input_width)?
7677            };
7678            let mut remote_down_keepalive = Vec::new();
7679
7680            for slot in 0..experts_per_token {
7681                let pair = token * experts_per_token + slot;
7682                let expert = selected[pair];
7683                if expert >= experts.expert_count {
7684                    return Err(format!(
7685                        "EP selected expert {expert} outside 0..{}",
7686                        experts.expert_count
7687                    )
7688                    .into());
7689                }
7690                let owner = expert / per_rank;
7691                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
7692                if rank_inputs[owner].is_none() {
7693                    let peer_input = {
7694                        let root_input = rank_inputs[0]
7695                            .as_ref()
7696                            .ok_or("native EP lost its root input")?;
7697                        let engine = &self.ranks[owner];
7698                        let _main = engine.gpu.enter_main()?;
7699                        let mut peer_input = engine.uninit(experts.input_width)?;
7700                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
7701                        peer_input
7702                    };
7703                    rank_inputs[owner] = Some(peer_input);
7704                }
7705
7706                let rank = &experts.ranks[owner];
7707                let engine = &self.ranks[owner];
7708                let owner_input = rank_inputs[owner]
7709                    .as_ref()
7710                    .ok_or("native EP owner input is absent after dispatch")?;
7711                let gate = run_resident_bank_expert_device(
7712                    engine,
7713                    &rank.gate,
7714                    local_expert,
7715                    owner_input,
7716                    1,
7717                )?;
7718                let up = run_resident_bank_expert_device(
7719                    engine,
7720                    &rank.up,
7721                    local_expert,
7722                    owner_input,
7723                    1,
7724                )?;
7725                let activated = {
7726                    let _main = engine.gpu.enter_main()?;
7727                    let mut activated = engine.uninit(experts.expert_width)?;
7728                    if let Some(limit) = activation_limit {
7729                        engine.silu_clamped_mul_host_expf(
7730                            &gate,
7731                            &up,
7732                            limit,
7733                            &mut activated,
7734                            experts.expert_width,
7735                        )?;
7736                    } else {
7737                        engine.silu_mul_host_expf(
7738                            &gate,
7739                            &up,
7740                            &mut activated,
7741                            experts.expert_width,
7742                        )?;
7743                    }
7744                    activated
7745                };
7746                let down = run_resident_bank_expert_device(
7747                    engine,
7748                    &rank.down,
7749                    local_expert,
7750                    &activated,
7751                    1,
7752                )?;
7753                let root_down = if owner == 0 {
7754                    down
7755                } else {
7756                    let _main = root.gpu.enter_main()?;
7757                    let mut root_down = root.uninit(experts.input_width)?;
7758                    root.stream().memcpy_dtod(&down, &mut root_down)?;
7759                    // The peer copy runs on the root stream. Keep its remote source alive until
7760                    // the final root readback synchronizes that stream; otherwise async free can
7761                    // recycle the owner's allocation while cuMemcpyPeerAsync is still reading it.
7762                    remote_down_keepalive.push(down);
7763                    root_down
7764                };
7765                let _main = root.gpu.enter_main()?;
7766                let mut destination = root_output.slice_mut(0..experts.input_width);
7767                root.axpy_host_into(
7768                    &root_down.slice(0..root_down.len()),
7769                    route_weights[pair],
7770                    &mut destination,
7771                    experts.input_width,
7772                )?;
7773            }
7774
7775            let _main = root.gpu.enter_main()?;
7776            let root_output = root.dtoh(&root_output)?;
7777            drop(remote_down_keepalive);
7778            output.extend(root_output);
7779        }
7780        Ok(output)
7781    }
7782}
7783
7784fn validate_column_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
7785    if matrix.out_features % tp != 0 {
7786        return Err(format!(
7787            "column-parallel out_features {} is not divisible by TP={tp}",
7788            matrix.out_features
7789        ));
7790    }
7791    let local_out = matrix.out_features / tp;
7792    if local_out % FP8_BLOCK != 0 {
7793        return Err(format!(
7794            "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
7795             E4M3 scale block"
7796        ));
7797    }
7798    Ok(())
7799}
7800
7801fn step_bf16_canonical_chunk_rows(out_features: usize, tp: usize) -> Result<usize, String> {
7802    if !matches!(tp, 1 | 2 | 4 | 8) {
7803        return Err(format!(
7804            "Step BF16 canonical projection requires TP1/TP2/TP4/TP8, got TP={tp}"
7805        ));
7806    }
7807    if out_features == 0 || out_features % PRODUCT_MAX_CARDS != 0 {
7808        return Err(format!(
7809            "Step BF16 output width {out_features} is not divisible by the TP8 product envelope"
7810        ));
7811    }
7812    let canonical_rows = out_features / PRODUCT_MAX_CARDS;
7813    let local_out = out_features / tp;
7814    if local_out % canonical_rows != 0 {
7815        return Err(format!(
7816            "Step BF16 TP={tp} output shard {local_out} is not divisible by canonical \
7817             {canonical_rows}-row chunks"
7818        ));
7819    }
7820    Ok(canonical_rows)
7821}
7822
7823fn step_bf16_canonical_chunk_cols(in_features: usize, tp: usize) -> Result<usize, String> {
7824    if !matches!(tp, 1 | 2 | 4 | 8) {
7825        return Err(format!(
7826            "Step BF16 canonical row projection requires TP1/TP2/TP4/TP8, got TP={tp}"
7827        ));
7828    }
7829    if in_features == 0 || in_features % PRODUCT_MAX_CARDS != 0 {
7830        return Err(format!(
7831            "Step BF16 input width {in_features} is not divisible by the TP8 product envelope"
7832        ));
7833    }
7834    let canonical_cols = in_features / PRODUCT_MAX_CARDS;
7835    let local_in = in_features / tp;
7836    if local_in % canonical_cols != 0 {
7837        return Err(format!(
7838            "Step BF16 TP={tp} input shard {local_in} is not divisible by canonical \
7839             {canonical_cols}-column chunks"
7840        ));
7841    }
7842    Ok(canonical_cols)
7843}
7844
7845fn validate_row_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
7846    if matrix.in_features % tp != 0 {
7847        return Err(format!(
7848            "row-parallel in_features {} is not divisible by TP={tp}",
7849            matrix.in_features
7850        ));
7851    }
7852    let local_in = matrix.in_features / tp;
7853    if local_in % FP8_BLOCK != 0 {
7854        return Err(format!(
7855            "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
7856             E4M3 scale block"
7857        ));
7858    }
7859    Ok(())
7860}
7861
7862fn upload_rank(
7863    engine: &Engine,
7864    matrix: E4m3BlockMatrix<'_>,
7865) -> Result<ResidentE4m3Rank, Box<dyn std::error::Error>> {
7866    let _main = engine.gpu.enter_main()?;
7867    matrix.validate()?;
7868    Ok(ResidentE4m3Rank {
7869        codes: engine.htod_bytes(matrix.codes)?,
7870        scales: engine.htod(matrix.scales)?,
7871        out_features: matrix.out_features,
7872        in_features: matrix.in_features,
7873    })
7874}
7875
7876fn upload_bf16_rank(
7877    engine: &Engine,
7878    matrix: Bf16Matrix<'_>,
7879    f32_mirror: bool,
7880) -> Result<ResidentBf16Rank, Box<dyn std::error::Error>> {
7881    let _main = engine.gpu.enter_main()?;
7882    matrix.validate()?;
7883    let bytes = engine.htod_bytes(matrix.bytes)?;
7884    let weight = if f32_mirror {
7885        let values = matrix
7886            .out_features
7887            .checked_mul(matrix.in_features)
7888            .ok_or("resident BF16 mirror element count overflow")?;
7889        ResidentBf16Weight::F32(engine.bf16_to_f32(&bytes.slice(0..bytes.len()), values)?)
7890    } else {
7891        ResidentBf16Weight::Bf16(bytes)
7892    };
7893    // MEMRA_STEP_TP_W8: encode the q8_0 decode mirror once, here, while the bf16 bytes are
7894    // already resident. Rows whose in_features is not a multiple of 32 have no q8_0 form and
7895    // simply keep the bf16 program (the decode arm checks for the mirror, never assumes it).
7896    let q8 = if crate::step_tp_w8_on() && matrix.in_features % 32 == 0 {
7897        if let ResidentBf16Weight::Bf16(bytes) = &weight {
7898            // Two steps, because the mmvq rp kernel does NOT read ggml-interleaved 34-byte
7899            // blocks: it reads a PLANAR mirror (all quants, then all half scales — the
7900            // q4_0/NVFP4 rp convention). The encoder writes the interleaved form and
7901            // `build_q8_rp4_raw` — the same kernel the GGUF loader uses — splits it into
7902            // planes. Skipping the split is what made the first W8 gate return zeros
7903            // (verify-prefill argmax=0, maxdiff=0.000e0).
7904            let row_bytes = Engine::q8_0_row_bytes(matrix.in_features);
7905            let mut interleaved = engine.alloc_u8_uninit(matrix.out_features * row_bytes)?;
7906            engine.encode_q8_0_from_bf16(
7907                bytes,
7908                &mut interleaved,
7909                matrix.in_features,
7910                matrix.out_features,
7911            )?;
7912            let mirror =
7913                engine.build_q8_rp4_raw(&interleaved, matrix.in_features, matrix.out_features)?;
7914            Some(mirror)
7915        } else {
7916            None
7917        }
7918    } else {
7919        None
7920    };
7921    Ok(ResidentBf16Rank {
7922        weight,
7923        out_features: matrix.out_features,
7924        in_features: matrix.in_features,
7925        q8,
7926    })
7927}
7928
7929fn upload_expert_bank_rank(
7930    engine: &Engine,
7931    bank: E4m3ExpertBank<'_>,
7932    expert_range: Range<usize>,
7933) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
7934    let _main = engine.gpu.enter_main()?;
7935    bank.validate()?;
7936    if expert_range.start >= expert_range.end || expert_range.end > bank.expert_count {
7937        return Err(format!(
7938            "invalid EP expert range {expert_range:?} for {} experts",
7939            bank.expert_count
7940        )
7941        .into());
7942    }
7943    let code_stride = bank.out_features * bank.in_features;
7944    let scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * bank.in_features.div_ceil(FP8_BLOCK);
7945    Ok(ResidentE4m3ExpertBankRank {
7946        codes: engine.htod_bytes(
7947            &bank.codes[expert_range.start * code_stride..expert_range.end * code_stride],
7948        )?,
7949        scales: engine.htod(
7950            &bank.scales[expert_range.start * scale_stride..expert_range.end * scale_stride],
7951        )?,
7952        expert_range,
7953        out_features: bank.out_features,
7954        in_features: bank.in_features,
7955        code_stride,
7956        scale_stride,
7957        k_blocks: None,
7958    })
7959}
7960
7961fn validate_column_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
7962    if bank.out_features % tp != 0 {
7963        return Err(format!(
7964            "TP expert output width {} is not divisible by TP={tp}",
7965            bank.out_features
7966        ));
7967    }
7968    let local_out = bank.out_features / tp;
7969    if local_out % FP8_BLOCK != 0 {
7970        return Err(format!(
7971            "TP expert output shard {local_out} cuts through a {FP8_BLOCK}-row E4M3 scale block"
7972        ));
7973    }
7974    Ok(())
7975}
7976
7977fn validate_row_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
7978    if bank.in_features % tp != 0 {
7979        return Err(format!(
7980            "TP expert input width {} is not divisible by TP={tp}",
7981            bank.in_features
7982        ));
7983    }
7984    let local_in = bank.in_features / tp;
7985    if local_in % FP8_BLOCK != 0 {
7986        return Err(format!(
7987            "TP expert input shard {local_in} cuts through a {FP8_BLOCK}-column E4M3 scale block"
7988        ));
7989    }
7990    Ok(())
7991}
7992
7993fn upload_column_bank_rank(
7994    engine: &Engine,
7995    bank: E4m3ExpertBank<'_>,
7996    tp: usize,
7997    rank: usize,
7998) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
7999    let _main = engine.gpu.enter_main()?;
8000    let packed = pack_column_bank_rank(bank, tp, rank)?;
8001    Ok(ResidentE4m3ExpertBankRank {
8002        codes: engine.htod_bytes(&packed.codes)?,
8003        scales: engine.htod(&packed.scales)?,
8004        expert_range: packed.expert_range,
8005        out_features: packed.out_features,
8006        in_features: packed.in_features,
8007        code_stride: packed.code_stride,
8008        scale_stride: packed.scale_stride,
8009        k_blocks: packed.k_blocks,
8010    })
8011}
8012
8013fn pack_column_bank_rank(
8014    bank: E4m3ExpertBank<'_>,
8015    tp: usize,
8016    rank: usize,
8017) -> Result<PackedE4m3ExpertBankRank, String> {
8018    bank.validate()?;
8019    validate_column_bank_shape(bank, tp)?;
8020    if rank >= tp {
8021        return Err(format!("TP rank {rank} outside 0..{tp}"));
8022    }
8023    let local_out = bank.out_features / tp;
8024    let full_code_stride = bank.out_features * bank.in_features;
8025    let local_code_stride = local_out * bank.in_features;
8026    let scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8027    let full_scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * scale_cols;
8028    let local_scale_rows = local_out / FP8_BLOCK;
8029    let local_scale_stride = local_scale_rows * scale_cols;
8030    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8031    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8032    let row_start = rank * local_out;
8033    let scale_row_start = rank * local_scale_rows;
8034    for expert in 0..bank.expert_count {
8035        let code_start = expert * full_code_stride + row_start * bank.in_features;
8036        codes.extend_from_slice(&bank.codes[code_start..code_start + local_code_stride]);
8037        let scale_start = expert * full_scale_stride + scale_row_start * scale_cols;
8038        scales.extend_from_slice(&bank.scales[scale_start..scale_start + local_scale_stride]);
8039    }
8040    Ok(PackedE4m3ExpertBankRank {
8041        codes,
8042        scales,
8043        expert_range: 0..bank.expert_count,
8044        out_features: local_out,
8045        in_features: bank.in_features,
8046        code_stride: local_code_stride,
8047        scale_stride: local_scale_stride,
8048        k_blocks: None,
8049    })
8050}
8051
8052fn upload_row_bank_rank(
8053    engine: &Engine,
8054    bank: E4m3ExpertBank<'_>,
8055    tp: usize,
8056    rank: usize,
8057) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8058    let _main = engine.gpu.enter_main()?;
8059    let packed = pack_row_bank_rank(bank, tp, rank)?;
8060    Ok(ResidentE4m3ExpertBankRank {
8061        codes: engine.htod_bytes(&packed.codes)?,
8062        scales: engine.htod(&packed.scales)?,
8063        expert_range: packed.expert_range,
8064        out_features: packed.out_features,
8065        in_features: packed.in_features,
8066        code_stride: packed.code_stride,
8067        scale_stride: packed.scale_stride,
8068        k_blocks: packed.k_blocks,
8069    })
8070}
8071
8072fn pack_row_bank_rank(
8073    bank: E4m3ExpertBank<'_>,
8074    tp: usize,
8075    rank: usize,
8076) -> Result<PackedE4m3ExpertBankRank, String> {
8077    bank.validate()?;
8078    validate_row_bank_shape(bank, tp)?;
8079    if rank >= tp {
8080        return Err(format!("TP rank {rank} outside 0..{tp}"));
8081    }
8082    let local_in = bank.in_features / tp;
8083    let full_code_stride = bank.out_features * bank.in_features;
8084    let local_code_stride = bank.out_features * local_in;
8085    let full_scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8086    let local_scale_cols = local_in / FP8_BLOCK;
8087    let scale_rows = bank.out_features.div_ceil(FP8_BLOCK);
8088    let full_scale_stride = scale_rows * full_scale_cols;
8089    let local_scale_stride = scale_rows * local_scale_cols;
8090    let global_block_start = rank * local_scale_cols;
8091    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8092    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8093    for expert in 0..bank.expert_count {
8094        let expert_code_start = expert * full_code_stride;
8095        let expert_scale_start = expert * full_scale_stride;
8096        for local_block in 0..local_scale_cols {
8097            let global_block = global_block_start + local_block;
8098            let column_start = global_block * FP8_BLOCK;
8099            for row in 0..bank.out_features {
8100                let start = expert_code_start + row * bank.in_features + column_start;
8101                codes.extend_from_slice(&bank.codes[start..start + FP8_BLOCK]);
8102            }
8103            for row in 0..scale_rows {
8104                scales.push(bank.scales[expert_scale_start + row * full_scale_cols + global_block]);
8105            }
8106        }
8107    }
8108    Ok(PackedE4m3ExpertBankRank {
8109        codes,
8110        scales,
8111        expert_range: 0..bank.expert_count,
8112        out_features: bank.out_features,
8113        in_features: local_in,
8114        code_stride: local_code_stride,
8115        scale_stride: local_scale_stride,
8116        k_blocks: Some(local_scale_cols),
8117    })
8118}
8119
8120fn validate_resident_ranks(engines: &[Engine], ranks: &[ResidentE4m3Rank]) -> Result<(), String> {
8121    if engines.len() != ranks.len() {
8122        return Err(format!(
8123            "resident TP rank count {} != runtime rank count {}",
8124            ranks.len(),
8125            engines.len()
8126        ));
8127    }
8128    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
8129        let device = engine.ctx().ordinal();
8130        if matrix.codes.ordinal() != device || matrix.scales.ordinal() != device {
8131            return Err(format!(
8132                "resident TP rank {rank} is not owned by runtime device {device}"
8133            ));
8134        }
8135    }
8136    Ok(())
8137}
8138
8139fn validate_tp_bank_residency(
8140    engines: &[Engine],
8141    experts: &ResidentTpExpertBank,
8142) -> Result<(), String> {
8143    if engines.len() != experts.gate.len()
8144        || engines.len() != experts.up.len()
8145        || engines.len() != experts.down.len()
8146    {
8147        return Err(format!(
8148            "resident TP expert-bank rank counts gate={} up={} down={} != runtime {}",
8149            experts.gate.len(),
8150            experts.up.len(),
8151            experts.down.len(),
8152            engines.len()
8153        ));
8154    }
8155    for (rank, engine) in engines.iter().enumerate() {
8156        let device = engine.ctx().ordinal();
8157        for (projection, bank) in [
8158            ("gate", &experts.gate[rank]),
8159            ("up", &experts.up[rank]),
8160            ("down", &experts.down[rank]),
8161        ] {
8162            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
8163                return Err(format!(
8164                    "resident TP rank {rank} {projection} bank is not owned by runtime device \
8165                     {device}"
8166                ));
8167            }
8168        }
8169    }
8170    Ok(())
8171}
8172
8173fn validate_ep_residency(
8174    engines: &[Engine],
8175    experts: &ResidentExpertParallel,
8176) -> Result<(), String> {
8177    if engines.len() != experts.ranks.len() {
8178        return Err(format!(
8179            "resident EP rank count {} != runtime rank count {}",
8180            experts.ranks.len(),
8181            engines.len()
8182        ));
8183    }
8184    for (rank, (engine, resident)) in engines.iter().zip(&experts.ranks).enumerate() {
8185        let device = engine.ctx().ordinal();
8186        for (projection, bank) in [
8187            ("gate", &resident.gate),
8188            ("up", &resident.up),
8189            ("down", &resident.down),
8190        ] {
8191            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
8192                return Err(format!(
8193                    "resident EP rank {rank} {projection} bank is not owned by runtime device \
8194                     {device}"
8195                ));
8196            }
8197        }
8198    }
8199    Ok(())
8200}
8201
8202fn run_rank(
8203    engine: &Engine,
8204    matrix: E4m3BlockMatrix<'_>,
8205    activations: &[f32],
8206    tokens: usize,
8207) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8208    let _main = engine.gpu.enter_main()?;
8209    let codes = engine.htod_bytes(matrix.codes)?;
8210    let scales = engine.htod(matrix.scales)?;
8211    let activations = engine.htod(activations)?;
8212    let output = engine.qmatvec_mmq_fp8_blk(
8213        &codes,
8214        &scales,
8215        &activations,
8216        tokens,
8217        matrix.in_features,
8218        matrix.out_features,
8219    )?;
8220    engine.dtoh(&output)
8221}
8222
8223fn run_resident_rank(
8224    engine: &Engine,
8225    matrix: &ResidentE4m3Rank,
8226    activations: &[f32],
8227    tokens: usize,
8228) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8229    let _main = engine.gpu.enter_main()?;
8230    let activations = engine.htod(activations)?;
8231    let output = engine.qmatvec_mmq_fp8_blk(
8232        &matrix.codes,
8233        &matrix.scales,
8234        &activations,
8235        tokens,
8236        matrix.in_features,
8237        matrix.out_features,
8238    )?;
8239    engine.dtoh(&output)
8240}
8241
8242fn run_resident_bf16_rank(
8243    engine: &Engine,
8244    matrix: &ResidentBf16Rank,
8245    activations: &[f32],
8246    tokens: usize,
8247    canonical_chunk_rows: Option<usize>,
8248) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8249    let _main = engine.gpu.enter_main()?;
8250    let activations = engine.htod(activations)?;
8251    let output = run_resident_bf16_rank_device(
8252        engine,
8253        matrix,
8254        &activations,
8255        tokens,
8256        canonical_chunk_rows,
8257        false,
8258    )?;
8259    engine.dtoh(&output)
8260}
8261
8262fn run_resident_bf16_rank_device(
8263    engine: &Engine,
8264    matrix: &ResidentBf16Rank,
8265    activations: &CudaSlice<f32>,
8266    tokens: usize,
8267    canonical_chunk_rows: Option<usize>,
8268    strided_chunk_output: bool,
8269) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
8270    let _main = engine.gpu.enter_main()?;
8271    if activations.ordinal() != engine.ctx().ordinal() {
8272        return Err(format!(
8273            "resident BF16 activation device {} != rank device {}",
8274            activations.ordinal(),
8275            engine.ctx().ordinal()
8276        )
8277        .into());
8278    }
8279    if activations.len() != tokens * matrix.in_features {
8280        return Err(format!(
8281            "resident BF16 activation count {} != {tokens}x{}",
8282            activations.len(),
8283            matrix.in_features
8284        )
8285        .into());
8286    }
8287    match (&matrix.weight, canonical_chunk_rows) {
8288        (ResidentBf16Weight::Bf16(bytes), Some(rows)) => engine
8289            .linear_bf16_resident_canonical_rows(
8290                activations,
8291                bytes,
8292                tokens,
8293                matrix.in_features,
8294                matrix.out_features,
8295                rows,
8296            ),
8297        (ResidentBf16Weight::Bf16(bytes), None) => engine.linear_bf16_resident(
8298            activations,
8299            bytes,
8300            tokens,
8301            matrix.in_features,
8302            matrix.out_features,
8303        ),
8304        (ResidentBf16Weight::F32(values), Some(rows)) if strided_chunk_output => engine
8305            .linear_f32_resident_canonical_rows_strided(
8306                activations,
8307                values,
8308                tokens,
8309                matrix.in_features,
8310                matrix.out_features,
8311                rows,
8312            ),
8313        (ResidentBf16Weight::F32(values), Some(rows)) => engine.linear_f32_resident_canonical_rows(
8314            activations,
8315            values,
8316            tokens,
8317            matrix.in_features,
8318            matrix.out_features,
8319            rows,
8320        ),
8321        (ResidentBf16Weight::F32(values), None) => engine.linear(
8322            activations,
8323            values,
8324            tokens,
8325            matrix.in_features,
8326            matrix.out_features,
8327        ),
8328    }
8329}
8330
8331fn validate_resident_bf16_ranks(
8332    engines: &[Engine],
8333    ranks: &[ResidentBf16Rank],
8334) -> Result<(), String> {
8335    if engines.len() != ranks.len() {
8336        return Err(format!(
8337            "resident BF16 TP rank count {} != runtime rank count {}",
8338            ranks.len(),
8339            engines.len(),
8340        ));
8341    }
8342    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
8343        let device = engine.ctx().ordinal();
8344        if matrix.weight.ordinal() != device {
8345            return Err(format!(
8346                "resident BF16 TP rank {rank} is not owned by runtime device {device}"
8347            ));
8348        }
8349    }
8350    Ok(())
8351}
8352
8353fn validate_step_bf16_row_residency(
8354    engines: &[Engine],
8355    matrix: &ResidentStepBf16RowParallel,
8356) -> Result<(), String> {
8357    if engines.len() != matrix.ranks.len() {
8358        return Err(format!(
8359            "resident Step BF16 row rank count {} != runtime rank count {}",
8360            matrix.ranks.len(),
8361            engines.len(),
8362        ));
8363    }
8364    let canonical_cols = step_bf16_canonical_chunk_cols(matrix.in_features, engines.len())?;
8365    if matrix.canonical_chunk_cols != canonical_cols {
8366        return Err(format!(
8367            "resident Step BF16 row canonical columns {} != registered {canonical_cols}",
8368            matrix.canonical_chunk_cols
8369        ));
8370    }
8371    let blocks_per_rank = PRODUCT_MAX_CARDS / engines.len();
8372    for (rank, (engine, blocks)) in engines.iter().zip(&matrix.ranks).enumerate() {
8373        if blocks.len() != blocks_per_rank {
8374            return Err(format!(
8375                "resident Step BF16 row rank {rank} has {} blocks, expected {blocks_per_rank}",
8376                blocks.len()
8377            ));
8378        }
8379        let device = engine.ctx().ordinal();
8380        for (block, resident) in blocks.iter().enumerate() {
8381            if resident.weight.ordinal() != device
8382                || resident.in_features != canonical_cols
8383                || resident.out_features != matrix.out_features
8384            {
8385                return Err(format!(
8386                    "resident Step BF16 row rank {rank} block {block} has inconsistent \
8387                     device or geometry"
8388                ));
8389            }
8390        }
8391    }
8392    Ok(())
8393}
8394
8395fn validate_replicated_device_rows(
8396    engines: &[Engine],
8397    rows: &ResidentReplicatedDeviceRows,
8398) -> Result<(), String> {
8399    let rank_lengths = rows
8400        .ranks
8401        .iter()
8402        .map(|rank_rows| rank_rows.len())
8403        .collect::<Vec<_>>();
8404    replicated_device_row_values(rows.tokens, rows.width, engines.len(), &rank_lengths)?;
8405    if rows
8406        .ranks
8407        .iter()
8408        .zip(engines)
8409        .any(|(rank_rows, engine)| rank_rows.ordinal() != engine.ctx().ordinal())
8410    {
8411        return Err("replicated device rows are owned by the wrong CUDA contexts".into());
8412    }
8413    Ok(())
8414}
8415
8416fn replicated_device_row_values(
8417    tokens: usize,
8418    width: usize,
8419    expected_ranks: usize,
8420    rank_lengths: &[usize],
8421) -> Result<usize, String> {
8422    let values = tokens
8423        .checked_mul(width)
8424        .ok_or("replicated device row size overflow")?;
8425    if tokens == 0
8426        || width == 0
8427        || expected_ranks == 0
8428        || rank_lengths.len() != expected_ranks
8429        || rank_lengths.iter().any(|&rank_len| rank_len != values)
8430    {
8431        return Err(format!(
8432            "replicated device rows have inconsistent geometry tokens={} width={} ranks={}/{}",
8433            tokens,
8434            width,
8435            rank_lengths.len(),
8436            expected_ranks
8437        ));
8438    }
8439    Ok(values)
8440}
8441
8442fn replicated_device_row_source_values(
8443    tokens: usize,
8444    width: usize,
8445    source_len: usize,
8446    source_device: usize,
8447    root_device: usize,
8448) -> Result<usize, String> {
8449    let values = tokens
8450        .checked_mul(width)
8451        .ok_or("replicated device row size overflow")?;
8452    if tokens == 0 || width == 0 || source_len != values || source_device != root_device {
8453        return Err(format!(
8454            "replicated device row source has inconsistent geometry/device \
8455             tokens={tokens} width={width} source={source_len}@{source_device} root={root_device}"
8456        ));
8457    }
8458    Ok(values)
8459}
8460
8461fn bf16_column_shard(
8462    matrix: Bf16Matrix<'_>,
8463    tp: usize,
8464    rank: usize,
8465) -> Result<Bf16Matrix<'_>, String> {
8466    matrix.validate()?;
8467    if tp == 0 || rank >= tp || matrix.out_features % tp != 0 {
8468        return Err(format!(
8469            "invalid BF16 column shard out={} TP={tp} rank={rank}",
8470            matrix.out_features
8471        ));
8472    }
8473    let local_out = matrix.out_features / tp;
8474    let row_bytes = matrix.in_features * 2;
8475    let start = rank * local_out * row_bytes;
8476    Ok(Bf16Matrix {
8477        bytes: &matrix.bytes[start..start + local_out * row_bytes],
8478        out_features: local_out,
8479        in_features: matrix.in_features,
8480    })
8481}
8482
8483fn bf16_row_shard(matrix: Bf16Matrix<'_>, tp: usize, rank: usize) -> Result<Vec<u8>, String> {
8484    matrix.validate()?;
8485    if tp == 0 || rank >= tp || matrix.in_features % tp != 0 {
8486        return Err(format!(
8487            "invalid BF16 row shard in={} TP={tp} rank={rank}",
8488            matrix.in_features
8489        ));
8490    }
8491    let local_in = matrix.in_features / tp;
8492    let mut bytes = Vec::with_capacity(matrix.out_features * local_in * 2);
8493    for row in 0..matrix.out_features {
8494        let start = (row * matrix.in_features + rank * local_in) * 2;
8495        bytes.extend_from_slice(&matrix.bytes[start..start + local_in * 2]);
8496    }
8497    Ok(bytes)
8498}
8499
8500fn bf16_row_block(
8501    matrix: Bf16Matrix<'_>,
8502    col_start: usize,
8503    block_cols: usize,
8504) -> Result<Vec<u8>, String> {
8505    matrix.validate()?;
8506    let col_end = col_start
8507        .checked_add(block_cols)
8508        .ok_or("BF16 row block column overflow")?;
8509    if block_cols == 0 || col_end > matrix.in_features {
8510        return Err(format!(
8511            "invalid BF16 row block columns {col_start}..{col_end} for input width {}",
8512            matrix.in_features
8513        ));
8514    }
8515    let mut bytes = Vec::with_capacity(matrix.out_features * block_cols * 2);
8516    for row in 0..matrix.out_features {
8517        let start = (row * matrix.in_features + col_start) * 2;
8518        bytes.extend_from_slice(&matrix.bytes[start..start + block_cols * 2]);
8519    }
8520    Ok(bytes)
8521}
8522
8523fn run_resident_bank_expert(
8524    engine: &Engine,
8525    bank: &ResidentE4m3ExpertBankRank,
8526    local_expert: usize,
8527    activations: &[f32],
8528    tokens: usize,
8529) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8530    let _main = engine.gpu.enter_main()?;
8531    if bank.k_blocks.is_some() {
8532        return Err("block-major TP row bank requires canonical block execution".into());
8533    }
8534    let local_count = bank.expert_range.end - bank.expert_range.start;
8535    if local_expert >= local_count {
8536        return Err(format!(
8537            "local EP expert {local_expert} outside 0..{local_count} for range {:?}",
8538            bank.expert_range
8539        )
8540        .into());
8541    }
8542    validate_activations(activations, tokens, bank.in_features)?;
8543    let activations = engine.htod(activations)?;
8544    let weight = bank
8545        .codes
8546        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
8547    let scales = bank
8548        .scales
8549        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
8550    let input = activations.slice(0..activations.len());
8551    let output = engine.qmatvec_mmq_fp8_blk_view(
8552        &weight,
8553        &scales,
8554        &input,
8555        tokens,
8556        bank.in_features,
8557        bank.out_features,
8558    )?;
8559    engine.dtoh(&output)
8560}
8561
8562fn run_resident_bank_expert_block(
8563    engine: &Engine,
8564    bank: &ResidentE4m3ExpertBankRank,
8565    local_expert: usize,
8566    block: usize,
8567    activations: &[f32],
8568) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8569    let _main = engine.gpu.enter_main()?;
8570    let local_count = bank.expert_range.end - bank.expert_range.start;
8571    if local_expert >= local_count {
8572        return Err(format!(
8573            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
8574            bank.expert_range
8575        )
8576        .into());
8577    }
8578    let blocks = bank
8579        .k_blocks
8580        .ok_or("TP row bank is not packed in native K-block order")?;
8581    if block >= blocks {
8582        return Err(format!("TP row block {block} outside 0..{blocks}").into());
8583    }
8584    validate_activations(activations, 1, FP8_BLOCK)?;
8585    let block_code_stride = bank.out_features * FP8_BLOCK;
8586    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
8587    if bank.in_features != blocks * FP8_BLOCK
8588        || bank.code_stride != blocks * block_code_stride
8589        || bank.scale_stride != blocks * block_scale_stride
8590    {
8591        return Err("TP row bank block-major geometry is inconsistent".into());
8592    }
8593
8594    let expert_code_start = local_expert * bank.code_stride;
8595    let expert_scale_start = local_expert * bank.scale_stride;
8596    let weight = bank.codes.slice(
8597        expert_code_start + block * block_code_stride
8598            ..expert_code_start + (block + 1) * block_code_stride,
8599    );
8600    let scales = bank.scales.slice(
8601        expert_scale_start + block * block_scale_stride
8602            ..expert_scale_start + (block + 1) * block_scale_stride,
8603    );
8604    let activations = engine.htod(activations)?;
8605    let input = activations.slice(0..activations.len());
8606    let output = engine.qmatvec_mmq_fp8_blk_view(
8607        &weight,
8608        &scales,
8609        &input,
8610        1,
8611        FP8_BLOCK,
8612        bank.out_features,
8613    )?;
8614    engine.dtoh(&output)
8615}
8616
8617fn run_resident_bank_expert_device(
8618    engine: &Engine,
8619    bank: &ResidentE4m3ExpertBankRank,
8620    local_expert: usize,
8621    activations: &CudaSlice<f32>,
8622    tokens: usize,
8623) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
8624    let _main = engine.gpu.enter_main()?;
8625    if bank.k_blocks.is_some() {
8626        return Err("block-major TP row bank requires canonical block execution".into());
8627    }
8628    let local_count = bank.expert_range.end - bank.expert_range.start;
8629    if local_expert >= local_count {
8630        return Err(format!(
8631            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
8632            bank.expert_range
8633        )
8634        .into());
8635    }
8636    let expected = tokens
8637        .checked_mul(bank.in_features)
8638        .ok_or("native TP activation size overflow")?;
8639    if activations.len() != expected || activations.ordinal() != engine.ctx().ordinal() {
8640        return Err(format!(
8641            "native TP activation len/device {}/{} != expected {expected}/{}",
8642            activations.len(),
8643            activations.ordinal(),
8644            engine.ctx().ordinal()
8645        )
8646        .into());
8647    }
8648    let weight = bank
8649        .codes
8650        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
8651    let scales = bank
8652        .scales
8653        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
8654    let input = activations.slice(0..activations.len());
8655    engine.qmatvec_mmq_fp8_blk_view(
8656        &weight,
8657        &scales,
8658        &input,
8659        tokens,
8660        bank.in_features,
8661        bank.out_features,
8662    )
8663}
8664
8665fn run_resident_bank_expert_block_device(
8666    engine: &Engine,
8667    bank: &ResidentE4m3ExpertBankRank,
8668    local_expert: usize,
8669    block: usize,
8670    activations: &cudarc::driver::CudaView<'_, f32>,
8671) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
8672    let _main = engine.gpu.enter_main()?;
8673    let local_count = bank.expert_range.end - bank.expert_range.start;
8674    if local_expert >= local_count {
8675        return Err(format!(
8676            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
8677            bank.expert_range
8678        )
8679        .into());
8680    }
8681    let blocks = bank
8682        .k_blocks
8683        .ok_or("native TP row bank is not packed in checkpoint-block order")?;
8684    if block >= blocks {
8685        return Err(format!("native TP row block {block} outside 0..{blocks}").into());
8686    }
8687    let activation_device = activations.stream().context().ordinal();
8688    if activations.len() != FP8_BLOCK || activation_device != engine.ctx().ordinal() {
8689        return Err(format!(
8690            "native TP block activation len/device {}/{} != expected {FP8_BLOCK}/{}",
8691            activations.len(),
8692            activation_device,
8693            engine.ctx().ordinal()
8694        )
8695        .into());
8696    }
8697    let block_code_stride = bank.out_features * FP8_BLOCK;
8698    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
8699    if bank.in_features != blocks * FP8_BLOCK
8700        || bank.code_stride != blocks * block_code_stride
8701        || bank.scale_stride != blocks * block_scale_stride
8702    {
8703        return Err("native TP row bank block-major geometry is inconsistent".into());
8704    }
8705    let expert_code_start = local_expert * bank.code_stride;
8706    let expert_scale_start = local_expert * bank.scale_stride;
8707    let weight = bank.codes.slice(
8708        expert_code_start + block * block_code_stride
8709            ..expert_code_start + (block + 1) * block_code_stride,
8710    );
8711    let scales = bank.scales.slice(
8712        expert_scale_start + block * block_scale_stride
8713            ..expert_scale_start + (block + 1) * block_scale_stride,
8714    );
8715    engine.qmatvec_mmq_fp8_blk_view(
8716        &weight,
8717        &scales,
8718        activations,
8719        1,
8720        FP8_BLOCK,
8721        bank.out_features,
8722    )
8723}
8724
8725fn configure_native_p2p(
8726    ranks: &[Engine],
8727    devices: &[usize],
8728) -> Result<(), Box<dyn std::error::Error>> {
8729    if ranks.len() != devices.len() || ranks.len() < 2 {
8730        return Err("native TP P2P setup requires matching multi-rank devices".into());
8731    }
8732    for (rank, (&device, engine)) in devices.iter().zip(ranks).enumerate() {
8733        if engine.ctx().ordinal() != device {
8734            return Err(format!(
8735                "native TP rank {rank} context device {} != requested device {device}",
8736                engine.ctx().ordinal()
8737            )
8738            .into());
8739        }
8740    }
8741
8742    for src in 0..ranks.len() {
8743        for dst in 0..ranks.len() {
8744            if src == dst {
8745                continue;
8746            }
8747            let mut can_access = 0;
8748            unsafe {
8749                cudarc::driver::sys::cuDeviceCanAccessPeer(
8750                    &mut can_access,
8751                    ranks[src].ctx().cu_device(),
8752                    ranks[dst].ctx().cu_device(),
8753                )
8754                .result()?;
8755            }
8756            if can_access == 0 {
8757                return Err(format!(
8758                    "native TP requires P2P, but dev{} cannot access dev{}",
8759                    devices[src], devices[dst]
8760                )
8761                .into());
8762            }
8763            ranks[src].ctx().bind_to_thread()?;
8764            let rc =
8765                unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(ranks[dst].ctx().cu_ctx(), 0) };
8766            use cudarc::driver::sys::cudaError_enum as E;
8767            if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
8768                return Err(format!(
8769                    "native TP cuCtxEnablePeerAccess(dev{} -> dev{}) failed: {rc:?}",
8770                    devices[src], devices[dst]
8771                )
8772                .into());
8773            }
8774        }
8775    }
8776
8777    for &owner in devices {
8778        for &accessor in devices {
8779            if owner == accessor {
8780                continue;
8781            }
8782            let device = cudarc::driver::result::device::get(owner as i32)?;
8783            let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
8784            unsafe {
8785                cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
8786            }
8787            let desc = cudarc::driver::sys::CUmemAccessDesc {
8788                location: cudarc::driver::sys::CUmemLocation {
8789                    type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
8790                    id: accessor as i32,
8791                },
8792                flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
8793            };
8794            let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
8795            if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
8796                return Err(format!(
8797                    "native TP cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: \
8798                     {rc:?}"
8799                )
8800                .into());
8801            }
8802        }
8803    }
8804
8805    for src in 0..ranks.len() {
8806        for dst in 0..ranks.len() {
8807            if src == dst {
8808                continue;
8809            }
8810            for &words in NATIVE_P2P_PROBE_WORDS {
8811                let expected = (0..words)
8812                    .map(|index| {
8813                        (index as u32)
8814                            .wrapping_mul(0x9e37_79b9)
8815                            .wrapping_add(((src as u32) << 16) | dst as u32)
8816                    })
8817                    .collect::<Vec<_>>();
8818                let poison = expected.iter().map(|value| !value).collect::<Vec<_>>();
8819                let source = ranks[src].htod_u32_v(&expected)?;
8820                let mut destination = ranks[dst].htod_u32_v(&poison)?;
8821                ranks[dst].stream().memcpy_dtod(&source, &mut destination)?;
8822                let actual = ranks[dst].dtoh_u32(&destination)?;
8823                if actual != expected {
8824                    let mismatches = actual
8825                        .iter()
8826                        .zip(&expected)
8827                        .filter(|(actual, expected)| actual != expected)
8828                        .count();
8829                    return Err(format!(
8830                        "native TP peer probe dev{}->dev{} failed at {} bytes: \
8831                         {mismatches}/{} words differ",
8832                        devices[src],
8833                        devices[dst],
8834                        words * std::mem::size_of::<u32>(),
8835                        expected.len()
8836                    )
8837                    .into());
8838                }
8839            }
8840        }
8841    }
8842    ranks[0].ctx().bind_to_thread()?;
8843    eprintln!(
8844        "[tp] native peer byte-integrity probe PASS: devices={devices:?} \
8845         directions={} byte_ladder={:?} mismatches=0",
8846        ranks.len() * (ranks.len() - 1),
8847        NATIVE_P2P_PROBE_WORDS
8848            .iter()
8849            .map(|words| words * std::mem::size_of::<u32>())
8850            .collect::<Vec<_>>(),
8851    );
8852    Ok(())
8853}
8854
8855fn validate_activations(
8856    activations: &[f32],
8857    tokens: usize,
8858    in_features: usize,
8859) -> Result<(), String> {
8860    let expected = tokens
8861        .checked_mul(in_features)
8862        .ok_or_else(|| "activation size overflow".to_string())?;
8863    if activations.len() != expected {
8864        return Err(format!(
8865            "activation count {} != {tokens}x{in_features} ({expected})",
8866            activations.len()
8867        ));
8868    }
8869    if !activations.iter().all(|value| value.is_finite()) {
8870        return Err("activations contain a non-finite value".to_string());
8871    }
8872    Ok(())
8873}
8874
8875fn column_shard(
8876    matrix: E4m3BlockMatrix<'_>,
8877    tp: usize,
8878    rank: usize,
8879) -> Result<E4m3BlockMatrix<'_>, String> {
8880    let local_out = matrix.out_features / tp;
8881    let row_start = rank * local_out;
8882    let code_start = row_start * matrix.in_features;
8883    let code_end = code_start + local_out * matrix.in_features;
8884    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
8885    let local_scale_rows = local_out / FP8_BLOCK;
8886    let scale_start = rank * local_scale_rows * scale_cols;
8887    let scale_end = scale_start + local_scale_rows * scale_cols;
8888    Ok(E4m3BlockMatrix {
8889        codes: &matrix.codes[code_start..code_end],
8890        scales: &matrix.scales[scale_start..scale_end],
8891        out_features: local_out,
8892        in_features: matrix.in_features,
8893    })
8894}
8895
8896fn row_shard(
8897    matrix: E4m3BlockMatrix<'_>,
8898    tp: usize,
8899    rank: usize,
8900) -> Result<(Vec<u8>, Vec<f32>), String> {
8901    let local_in = matrix.in_features / tp;
8902    let col_start = rank * local_in;
8903    let mut codes = Vec::with_capacity(matrix.out_features * local_in);
8904    for row in 0..matrix.out_features {
8905        let start = row * matrix.in_features + col_start;
8906        codes.extend_from_slice(&matrix.codes[start..start + local_in]);
8907    }
8908
8909    let scale_rows = matrix.out_features.div_ceil(FP8_BLOCK);
8910    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
8911    let local_scale_cols = local_in / FP8_BLOCK;
8912    let scale_col_start = rank * local_scale_cols;
8913    let mut scales = Vec::with_capacity(scale_rows * local_scale_cols);
8914    for row in 0..scale_rows {
8915        let start = row * scale_cols + scale_col_start;
8916        scales.extend_from_slice(&matrix.scales[start..start + local_scale_cols]);
8917    }
8918    Ok((codes, scales))
8919}
8920
8921fn activation_shard(
8922    activations: &[f32],
8923    tokens: usize,
8924    in_features: usize,
8925    tp: usize,
8926    rank: usize,
8927) -> Vec<f32> {
8928    let local_in = in_features / tp;
8929    let col_start = rank * local_in;
8930    let mut shard = Vec::with_capacity(tokens * local_in);
8931    for token in 0..tokens {
8932        let start = token * in_features + col_start;
8933        shard.extend_from_slice(&activations[start..start + local_in]);
8934    }
8935    shard
8936}
8937
8938// ─── Step NVFP4 expert TP program (official Step-3.7-Flash-NVFP4 checkpoint class) ─────────────
8939//
8940// The routed experts of the NVFP4 checkpoint are modelopt-packed: e2m1 codes (2/byte), per-16
8941// UE4M3 sub-scales, and a per-EXPERT `weight_scale_2` f32 macro (~1e-5..1e-4, LOAD-BEARING).
8942// Rank compute repacks each shard host-side into memra block_nvfp4 rows (nibble reorder only —
8943// value-exact, see nvfp4_repack.rs) and runs the proven `qmatvec_nvfp4_fast` dp4a kernel; the
8944// activation q8_1 quantization uses per-32 blocks, and every shard cut here is 64-aligned, so a
8945// rank-local partial is bit-identical to the corresponding slice of the unsharded kernel.
8946//
8947// MACRO CANONICAL ORDER: the macro multiplies each assembled f32 output exactly ONCE — after the
8948// column gather (gate/up) and after the FULL row-parallel reduce (down), never per-partial.
8949// `(a + b) * m` and `a * m + b * m` differ in f32, so applying it per-rank would break the
8950// TP1-vs-TP2 bit gate. Every entry point below follows this order.
8951//
8952// TP2 shard legality is NVFP4-native: column parallelism splits whole output rows (scale rows
8953// ride along, nothing cuts), row parallelism splits input columns at 64-element superblock
8954// boundaries (16-element scale groups nest inside). The 128-block E4M3 constraint does not apply.
8955
8956/// One expert's modelopt NVFP4 projection: packed codes + per-16 UE4M3 scale bytes + macro.
8957#[derive(Clone, Copy)]
8958pub struct Nvfp4BlockMatrix<'a> {
8959    pub codes: &'a [u8],  // [out_features, in_features/2] packed e2m1, row-major
8960    pub scales: &'a [u8], // [out_features, in_features/16] UE4M3 bytes, row-major
8961    pub macro_scale: f32, // per-expert weight_scale_2 dequant multiplier
8962    pub out_features: usize,
8963    pub in_features: usize,
8964}
8965
8966impl Nvfp4BlockMatrix<'_> {
8967    pub fn validate(&self) -> Result<(), String> {
8968        if self.in_features == 0 || self.out_features == 0 {
8969            return Err("NVFP4 matrix has a zero dimension".to_string());
8970        }
8971        if self.in_features % 64 != 0 {
8972            return Err(format!(
8973                "NVFP4 in_features {} is not 64-aligned (memra block_nvfp4 superblock)",
8974                self.in_features
8975            ));
8976        }
8977        if self.codes.len() != self.out_features * self.in_features / 2 {
8978            return Err(format!(
8979                "NVFP4 code bytes {} != {}x{}/2",
8980                self.codes.len(),
8981                self.out_features,
8982                self.in_features
8983            ));
8984        }
8985        if self.scales.len() != self.out_features * self.in_features / 16 {
8986            return Err(format!(
8987                "NVFP4 scale bytes {} != {}x{}/16",
8988                self.scales.len(),
8989                self.out_features,
8990                self.in_features
8991            ));
8992        }
8993        if !self.macro_scale.is_finite() || self.macro_scale <= 0.0 {
8994            return Err(format!(
8995                "NVFP4 macro scale {} is not finite-positive",
8996                self.macro_scale
8997            ));
8998        }
8999        Ok(())
9000    }
9001}
9002
9003/// Stacked modelopt NVFP4 expert bank (host view over the checkpoint bytes).
9004#[derive(Clone, Copy)]
9005pub struct Nvfp4ExpertBank<'a> {
9006    pub codes: &'a [u8],   // [expert_count, out_features, in_features/2]
9007    pub scales: &'a [u8],  // [expert_count, out_features, in_features/16]
9008    pub macros: &'a [f32], // [expert_count] weight_scale_2
9009    pub expert_count: usize,
9010    pub out_features: usize,
9011    pub in_features: usize,
9012}
9013
9014impl Nvfp4ExpertBank<'_> {
9015    pub fn validate(&self) -> Result<(), String> {
9016        if self.expert_count == 0 {
9017            return Err("NVFP4 expert bank is empty".to_string());
9018        }
9019        if self.macros.len() != self.expert_count {
9020            return Err(format!(
9021                "NVFP4 bank macros {} != expert count {}",
9022                self.macros.len(),
9023                self.expert_count
9024            ));
9025        }
9026        self.expert(0).map(|_| ())
9027    }
9028
9029    pub fn expert(&self, expert: usize) -> Result<Nvfp4BlockMatrix<'_>, String> {
9030        if expert >= self.expert_count {
9031            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
9032        }
9033        let code_stride = self.out_features * self.in_features / 2;
9034        let scale_stride = self.out_features * self.in_features / 16;
9035        if self.codes.len() != self.expert_count * code_stride
9036            || self.scales.len() != self.expert_count * scale_stride
9037        {
9038            return Err("NVFP4 bank byte extents do not match the declared geometry".to_string());
9039        }
9040        let matrix = Nvfp4BlockMatrix {
9041            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
9042            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
9043            macro_scale: self.macros[expert],
9044            out_features: self.out_features,
9045            in_features: self.in_features,
9046        };
9047        matrix.validate()?;
9048        Ok(matrix)
9049    }
9050}
9051
9052/// One rank's resident repacked NVFP4 shard: memra block_nvfp4 rows on device.
9053pub struct ResidentNvfp4Rank {
9054    blocks: crate::CudaSlice<u8>,
9055    macro_scale: f32,
9056    out_features: usize,
9057    in_features: usize,
9058    row_bytes: usize,
9059}
9060
9061pub struct ResidentNvfp4ColumnParallel {
9062    ranks: Vec<ResidentNvfp4Rank>,
9063    pub out_features: usize,
9064    pub in_features: usize,
9065}
9066
9067pub struct ResidentNvfp4RowParallel {
9068    ranks: Vec<ResidentNvfp4Rank>,
9069    pub out_features: usize,
9070    pub in_features: usize,
9071}
9072
9073pub struct ResidentTpNvfp4Expert {
9074    gate: ResidentNvfp4ColumnParallel,
9075    up: ResidentNvfp4ColumnParallel,
9076    down: ResidentNvfp4RowParallel,
9077    pub input_width: usize,
9078    pub expert_width: usize,
9079}
9080
9081/// One rank's resident NVFP4 expert bank shard: one repacked block buffer PER expert (per-expert
9082/// device allocations keep this increment off any new strided-kernel API; the strided twin is a
9083/// later perf rung, mirroring the FP8 bank's history).
9084pub struct ResidentNvfp4ColumnBankRank {
9085    /// Contiguous per-rank expert bank: `expert_count` repacked shards of `expert_bytes` each.
9086    /// Contiguity is what lets the device-routes program cover every selected expert with ONE
9087    /// launch (`qmatvec_nvfp4_dp4a_sel` indexes `sel[t] * expert_bytes`).
9088    bank: crate::CudaSlice<u8>,
9089    expert_bytes: usize,
9090    local_out: usize,
9091    in_features: usize,
9092    row_bytes: usize,
9093}
9094
9095impl ResidentNvfp4ColumnBankRank {
9096    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
9097        self.bank
9098            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
9099    }
9100}
9101
9102/// Canonical row-shard count for the NVFP4 down projection. The down reduction ALWAYS executes
9103/// as exactly this many input-column windows summed in shard order, at every world size: a
9104/// single full-width dot and a two-half-dots-plus-add differ in f32 parenthesization, so pinning
9105/// the shard grid (not the world size) is what makes the TP1-oracle-vs-TP2 bit gate meaningful.
9106/// This is the NVFP4 twin of the FP8 bank's canonical checkpoint-block reduction.
9107pub const NVFP4_CANONICAL_ROW_SHARDS: usize = 2;
9108
9109pub struct ResidentNvfp4RowBankRank {
9110    /// Contiguous per-shard expert bank (see `ResidentNvfp4ColumnBankRank::bank`).
9111    bank: crate::CudaSlice<u8>,
9112    expert_bytes: usize,
9113    device_rank: usize, // index into the runtime's rank engines this canonical shard lives on
9114    out_features: usize,
9115    local_in: usize,
9116    row_bytes: usize,
9117}
9118
9119impl ResidentNvfp4RowBankRank {
9120    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
9121        self.bank
9122            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
9123    }
9124}
9125
9126impl ResidentNvfp4TensorParallel {
9127    pub(crate) fn device_workspace_handle(
9128        &self,
9129    ) -> &std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>> {
9130        &self.device_workspace
9131    }
9132}
9133
9134pub struct ResidentNvfp4TensorParallel {
9135    gate: Vec<ResidentNvfp4ColumnBankRank>,
9136    up: Vec<ResidentNvfp4ColumnBankRank>,
9137    down: Vec<ResidentNvfp4RowBankRank>,
9138    macros_gate: Vec<f32>,
9139    macros_up: Vec<f32>,
9140    macros_down: Vec<f32>,
9141    /// Per-rank device copies of the gate/up macro-scales (E f32 each), indexed by the
9142    /// batched SwiGLU kernel via the selection array. Down macros stay host-side — they fold
9143    /// into the route-weight axpy scalar.
9144    macros_gate_dev: Vec<crate::CudaSlice<f32>>,
9145    macros_up_dev: Vec<crate::CudaSlice<f32>>,
9146    macros_down_dev: Vec<crate::CudaSlice<f32>>,
9147    pub expert_count: usize,
9148    pub input_width: usize,
9149    pub expert_width: usize,
9150    /// Lazily-built persistent decode workspace (device routes program). Interior mutability
9151    /// mirrors StepEpGroupedDecode: the forward holds the bank behind a shared reference.
9152    device_workspace: std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>>,
9153    /// Grouped-prime per-rank slot-major pointer tables (gate/up/down x n_expert), built once.
9154    /// The banks are resident and never move, so rebuilding + re-uploading 3*n_expert u64s per
9155    /// rank per LAYER was pure per-call host churn on the prime path.
9156    prime_tables: std::sync::Mutex<Vec<crate::CudaSlice<u64>>>,
9157    /// MEMRA_STEP_NVFP4_EP2: the rank banks above hold WHOLE experts (owner = id & 1,
9158    /// slot = id >> 1) at full width instead of TP shards. Consumers must branch on this;
9159    /// shard-semantics paths refuse loudly.
9160    pub(crate) ep2: bool,
9161}
9162
9163/// Persistent per-call device buffers for the NVFP4 device routes program: one gate/up output,
9164/// one down partial, and one shard accumulator per rank, plus root combine staging. Reused every
9165/// (token, layer) call so the decode loop performs zero output allocations.
9166/// A stitched multi-device parent graph for one layer's device-routed expert program, plus
9167/// the children it was built from (retained: AddChildGraphNode clones, but the probe retains
9168/// conservatively) and the persistent e-context input staging its copies read.
9169struct RoutesGraph {
9170    exec: cudarc::driver::sys::CUgraphExec,
9171    parent: cudarc::driver::sys::CUgraph,
9172    _children: Vec<cudarc::driver::CudaGraph>,
9173}
9174// SAFETY: the raw handles are only used from the single decode thread; CUDA graph handles are
9175// context-agnostic process handles.
9176unsafe impl Send for RoutesGraph {}
9177
9178impl Drop for RoutesGraph {
9179    fn drop(&mut self) {
9180        unsafe {
9181            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
9182            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
9183        }
9184    }
9185}
9186
9187impl Nvfp4DeviceRoutesWorkspace {
9188    pub(crate) fn in_stage_handle(&self) -> Option<&crate::CudaSlice<f32>> {
9189        self.in_stage_e.as_ref()
9190    }
9191    pub(crate) fn in_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
9192        self.in_stage_e.as_mut()
9193    }
9194    pub(crate) fn out_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
9195        self.out_stage_e.as_mut()
9196    }
9197    /// Arm the e-context stages + router staging pair when absent (token-graph entry).
9198    pub(crate) fn arm_stages(
9199        &mut self,
9200        e: &Engine,
9201        width: usize,
9202        n_sel: usize,
9203    ) -> Result<(), Box<dyn std::error::Error>> {
9204        let _main = e.gpu.enter_main()?;
9205        if self.in_stage_e.is_none() {
9206            self.in_stage_e = Some(e.htod(&vec![0.0f32; width])?);
9207            self.out_stage_e = Some(e.htod(&vec![0.0f32; width])?);
9208        }
9209        if self.dev_route_e.is_none() {
9210            self.dev_route_e = Some((
9211                e.htod_i32(&vec![0i32; n_sel])?,
9212                e.htod(&vec![0.0f32; n_sel])?,
9213            ));
9214        }
9215        Ok(())
9216    }
9217
9218    /// Split-borrow: the routes input (shared) + output (mut) stages together.
9219    pub(crate) fn in_and_out_stages_mut(
9220        &mut self,
9221    ) -> Option<(&crate::CudaSlice<f32>, &mut crate::CudaSlice<f32>)> {
9222        match (self.in_stage_e.as_ref(), self.out_stage_e.as_mut()) {
9223            (Some(input), Some(output)) => Some((input, output)),
9224            _ => None,
9225        }
9226    }
9227    pub(crate) fn dev_route_e_mut(
9228        &mut self,
9229    ) -> Option<(&mut crate::CudaSlice<i32>, &mut crate::CudaSlice<f32>)> {
9230        self.dev_route_e.as_mut().map(|(a, b)| (a, b))
9231    }
9232}
9233
9234pub struct Nvfp4DeviceRoutesWorkspace {
9235    /// [n_sel, local_out] batched gate/up outputs and the SwiGLU q8_1 pair; [n_sel, width]
9236    /// down partials. Sized for `n_sel` selected experts per token (pinned at first call).
9237    gate_out: Vec<crate::CudaSlice<f32>>,
9238    up_out: Vec<crate::CudaSlice<f32>>,
9239    act_q: Vec<crate::CudaSlice<i8>>,
9240    act_d: Vec<crate::CudaSlice<f32>>,
9241    sel: Vec<crate::CudaSlice<i32>>,
9242    partial: Vec<crate::CudaSlice<f32>>,
9243    accumulator: Vec<crate::CudaSlice<f32>>,
9244    /// Per-rank folded combine weights (route_weight x down macro), one htod per call.
9245    combine_w: Vec<crate::CudaSlice<f32>>,
9246    /// Device-routed extension: per-rank raw route weights (the down-macro fold happens
9247    /// in-kernel via sel + macros_down_dev).
9248    route_w: Vec<crate::CudaSlice<f32>>,
9249    /// Persistent q8_1 pair of the shared layer input (one quantize per rank per call, no
9250    /// per-call allocation).
9251    in_q: Vec<crate::CudaSlice<i8>>,
9252    in_d: Vec<crate::CudaSlice<f32>>,
9253    /// e-context staging for the device router outputs (persistent — rank streams peer-read
9254    /// them, so the router's fresh outputs are copied here on e's stream first; the pp.rs
9255    /// never-free discipline).
9256    dev_route_e: Option<(crate::CudaSlice<i32>, crate::CudaSlice<f32>)>,
9257    /// Prestage door state: input pull + quantize already issued for this layer's call
9258    /// (nvfp4_routes_prestage), so the routed run skips them. Reset per call.
9259    prestaged: bool,
9260    /// Peer-router door state: rank1's sel/route_w were computed locally in prestage;
9261    /// the routed run skips rank1's sel pull. Reset per call.
9262    rank1_routed: bool,
9263    /// Doorbell fences (MEMRA_FENCE_MEMOPS): raw cuMemAlloc'd [rank1_flag, root_flag]
9264    /// u32 pair in ROOT memory (async-pool memory is memop-INELIGIBLE — receipted
9265    /// CUDA_ERROR_INVALID_VALUE) + the host-side monotonic ticket. 0 = unarmed.
9266    fence_flags_raw: u64,
9267    fence_ticket: u32,
9268    /// Prestage input fence, recorded on e after the input's producer.
9269    ev_input: Option<(CudaEvent, usize)>,
9270    /// Graph-door staging: persistent e-context input row + output row (fixed addresses the
9271    /// captured copies read/write), and the per-layer stitched parent.
9272    in_stage_e: Option<crate::CudaSlice<f32>>,
9273    out_stage_e: Option<crate::CudaSlice<f32>>,
9274    routes_graph: Option<RoutesGraph>,
9275    /// Token-graph raw pointer sets (armed once by routes_arm_raw).
9276    raw_dev_route_e: Option<(u64, u64)>,
9277    raw_combine: Option<(u64, u64, u64, u64)>,
9278    raw_input: Vec<u64>,
9279    raw_sel: Vec<u64>,
9280    raw_route_w: Vec<u64>,
9281    remote: crate::CudaSlice<f32>,
9282    combined: crate::CudaSlice<f32>,
9283    n_sel: usize,
9284    /// Device-IO extension (lazily built by `run_tensor_parallel_routes_nvfp4_device_io`):
9285    /// persistent per-rank input rows plus the evented ordering pair — the pp.rs
9286    /// BoundarySlot discipline, same as the v2 attention workspace.
9287    input: Vec<crate::CudaSlice<f32>>,
9288    ev_rank: Vec<CudaEvent>,
9289    ev_done: Option<CudaEvent>,
9290    ev_entry: Option<(CudaEvent, usize)>,
9291}
9292
9293/// One rank's whole-expert NVFP4 residency (expert-parallel ownership).
9294struct ResidentNvfp4EpRank {
9295    gate: Vec<crate::CudaSlice<u8>>,
9296    up: Vec<crate::CudaSlice<u8>>,
9297    down: Vec<crate::CudaSlice<u8>>,
9298    #[allow(dead_code)]
9299    expert_range: Range<usize>,
9300}
9301
9302pub struct ResidentNvfp4ExpertParallel {
9303    ranks: Vec<ResidentNvfp4EpRank>,
9304    macros_gate: Vec<f32>,
9305    macros_up: Vec<f32>,
9306    macros_down: Vec<f32>,
9307    pub expert_count: usize,
9308    pub input_width: usize,
9309    pub expert_width: usize,
9310    gate_row_bytes: usize,
9311    down_row_bytes: usize,
9312}
9313
9314fn nvfp4_repack_matrix(matrix: Nvfp4BlockMatrix<'_>) -> Vec<u8> {
9315    memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
9316        matrix.codes,
9317        matrix.scales,
9318        matrix.out_features,
9319        matrix.in_features,
9320    )
9321}
9322
9323fn nvfp4_row_bytes(in_features: usize) -> usize {
9324    in_features / 64 * 36 // memra block_nvfp4: 64 elems -> 36 bytes (4 UE4M3 + 32 packed e2m1)
9325}
9326
9327/// MEMRA_NO_LOCAL_SHADOW=1: skip the per-layer local-KV shadow gathers and appends in the
9328/// eager v2 decode (lengths still advance) — the graph door proved contents-stale local KV
9329/// is decode-identical (12/12). The local contents feed spec/MTP scratch only.
9330/// MEMRA_FUSE_ROPE_APPEND=1: fuse qk norms + rope + dcw KV append + len inc into one
9331/// launch per rank per layer (bit-identical; identity-gated). dcw path only.
9332pub(crate) fn fuse_rope_append_on() -> bool {
9333    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
9334    *ON.get_or_init(|| std::env::var("MEMRA_FUSE_ROPE_APPEND").as_deref() == Ok("1"))
9335}
9336
9337pub(crate) fn no_local_shadow_on() -> bool {
9338    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
9339    *ON.get_or_init(|| std::env::var("MEMRA_NO_LOCAL_SHADOW").as_deref() == Ok("1"))
9340}
9341
9342/// Permute one repacked block_nvfp4 matrix (out_features rows of `nvfp4_row_bytes(in_f)`)
9343/// into the slot-major row layout the EP2 kernels read: per row, slot g's 16 qs bytes at
9344/// g*16, then the two UE4M3 scale bytes per slot at nslots*16 + g*2. Row byte count
9345/// unchanged. This layout USED to be an env door (`MEMRA_NVFP4_BANK_V2`, removed 2026-08-29
9346/// after its ON arm changed generated text in serving, see
9347/// research/step37-bankv2-removal-20260829); it survives ONLY as the fixed layout of the
9348/// EP2 whole-expert banks, whose `*_ep` kernels read it unconditionally.
9349fn nvfp4_matrix_v2_permute(v1: &[u8], out_features: usize, in_features: usize) -> Vec<u8> {
9350    let row_bytes = nvfp4_row_bytes(in_features);
9351    assert_eq!(v1.len(), out_features * row_bytes, "v2 permute geometry");
9352    let n_slots = in_features / 32;
9353    let mut out = Vec::with_capacity(v1.len());
9354    for row in 0..out_features {
9355        let r = &v1[row * row_bytes..(row + 1) * row_bytes];
9356        for g in 0..n_slots {
9357            let (sblk, h) = (g / 2, g % 2);
9358            let b = &r[sblk * 36..sblk * 36 + 36];
9359            out.extend_from_slice(&b[4 + 16 * h..4 + 16 * h + 16]);
9360        }
9361        for g in 0..n_slots {
9362            let (sblk, h) = (g / 2, g % 2);
9363            let b = &r[sblk * 36..sblk * 36 + 36];
9364            out.push(b[2 * h]);
9365            out.push(b[2 * h + 1]);
9366        }
9367    }
9368    out
9369}
9370
9371/// Repack one expert shard for the contiguous banks. `slot_major` is true ONLY for the EP2
9372/// whole-expert banks, whose `*_ep` kernels read the slot-major permutation; the TP
9373/// column/row shard banks stay in the block_nvfp4 v1 layout every other kernel reads.
9374fn nvfp4_repack_bank_matrix(matrix: Nvfp4BlockMatrix<'_>, slot_major: bool) -> Vec<u8> {
9375    let (out_features, in_features) = (matrix.out_features, matrix.in_features);
9376    let v1 = nvfp4_repack_matrix(matrix);
9377    if slot_major {
9378        nvfp4_matrix_v2_permute(&v1, out_features, in_features)
9379    } else {
9380        v1
9381    }
9382}
9383
9384/// Column shard: whole output rows per rank (codes and scales are row-major, so both slices are
9385/// contiguous borrows). The macro rides unchanged — it is applied post-gather by the caller.
9386fn nvfp4_column_shard<'a>(
9387    matrix: Nvfp4BlockMatrix<'a>,
9388    tp: usize,
9389    rank: usize,
9390) -> Result<Nvfp4BlockMatrix<'a>, String> {
9391    if matrix.out_features % tp != 0 {
9392        return Err(format!(
9393            "NVFP4 column-parallel out_features {} is not divisible by TP={tp}",
9394            matrix.out_features
9395        ));
9396    }
9397    let local_out = matrix.out_features / tp;
9398    let code_row = matrix.in_features / 2;
9399    let scale_row = matrix.in_features / 16;
9400    Ok(Nvfp4BlockMatrix {
9401        codes: &matrix.codes[rank * local_out * code_row..(rank + 1) * local_out * code_row],
9402        scales: &matrix.scales[rank * local_out * scale_row..(rank + 1) * local_out * scale_row],
9403        macro_scale: matrix.macro_scale,
9404        out_features: local_out,
9405        in_features: matrix.in_features,
9406    })
9407}
9408
9409/// Row shard: input-column windows per rank, 64-superblock aligned. Owned buffers: each output
9410/// row contributes one contiguous byte window, gathered across rows.
9411fn nvfp4_row_shard(
9412    matrix: Nvfp4BlockMatrix<'_>,
9413    tp: usize,
9414    rank: usize,
9415) -> Result<(Vec<u8>, Vec<u8>, usize), String> {
9416    if matrix.in_features % tp != 0 {
9417        return Err(format!(
9418            "NVFP4 row-parallel in_features {} is not divisible by TP={tp}",
9419            matrix.in_features
9420        ));
9421    }
9422    let local_in = matrix.in_features / tp;
9423    if local_in % 64 != 0 {
9424        return Err(format!(
9425            "NVFP4 row-parallel input shard {local_in} cuts through a 64-element superblock"
9426        ));
9427    }
9428    let code_row = matrix.in_features / 2;
9429    let scale_row = matrix.in_features / 16;
9430    let local_code = local_in / 2;
9431    let local_scale = local_in / 16;
9432    let mut codes = Vec::with_capacity(matrix.out_features * local_code);
9433    let mut scales = Vec::with_capacity(matrix.out_features * local_scale);
9434    for row in 0..matrix.out_features {
9435        let code_start = row * code_row + rank * local_code;
9436        codes.extend_from_slice(&matrix.codes[code_start..code_start + local_code]);
9437        let scale_start = row * scale_row + rank * local_scale;
9438        scales.extend_from_slice(&matrix.scales[scale_start..scale_start + local_scale]);
9439    }
9440    Ok((codes, scales, local_in))
9441}
9442
9443/// Rank compute leaf: repack modelopt -> block_nvfp4, upload, run the proven dp4a kernel. The
9444/// macro is NOT applied here — callers apply it once at the canonical post-gather/post-reduce
9445/// point (see the section header).
9446fn run_rank_nvfp4(
9447    engine: &Engine,
9448    matrix: Nvfp4BlockMatrix<'_>,
9449    activations: &[f32],
9450    tokens: usize,
9451) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9452    matrix.validate()?;
9453    validate_activations(activations, tokens, matrix.in_features)?;
9454    let _main = engine.gpu.enter_main()?;
9455    let blocks = engine.htod_bytes(&nvfp4_repack_matrix(matrix))?;
9456    let activations = engine.htod(activations)?;
9457    let output = engine.qmatvec_nvfp4_fast(
9458        &blocks.slice(0..blocks.len()),
9459        &activations,
9460        tokens,
9461        matrix.in_features,
9462        matrix.out_features,
9463        nvfp4_row_bytes(matrix.in_features),
9464    )?;
9465    engine.dtoh(&output)
9466}
9467
9468fn upload_rank_nvfp4(
9469    engine: &Engine,
9470    matrix: Nvfp4BlockMatrix<'_>,
9471) -> Result<ResidentNvfp4Rank, Box<dyn std::error::Error>> {
9472    matrix.validate()?;
9473    let _main = engine.gpu.enter_main()?;
9474    Ok(ResidentNvfp4Rank {
9475        blocks: engine.htod_bytes(&nvfp4_repack_matrix(matrix))?,
9476        macro_scale: matrix.macro_scale,
9477        out_features: matrix.out_features,
9478        in_features: matrix.in_features,
9479        row_bytes: nvfp4_row_bytes(matrix.in_features),
9480    })
9481}
9482
9483fn run_resident_rank_nvfp4(
9484    engine: &Engine,
9485    rank: &ResidentNvfp4Rank,
9486    activations: &[f32],
9487    tokens: usize,
9488) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9489    validate_activations(activations, tokens, rank.in_features)?;
9490    let _main = engine.gpu.enter_main()?;
9491    let activations = engine.htod(activations)?;
9492    let output = engine.qmatvec_nvfp4_fast(
9493        &rank.blocks.slice(0..rank.blocks.len()),
9494        &activations,
9495        tokens,
9496        rank.in_features,
9497        rank.out_features,
9498        rank.row_bytes,
9499    )?;
9500    engine.dtoh(&output)
9501}
9502
9503fn apply_macro(values: &mut [f32], macro_scale: f32) {
9504    for value in values.iter_mut() {
9505        *value *= macro_scale;
9506    }
9507}
9508
9509impl TpE4m3HostBounce {
9510    /// Unsharded NVFP4 projection on rank 0 (compatibility oracle). Macro applied post-kernel.
9511    pub fn full_nvfp4(
9512        &self,
9513        matrix: Nvfp4BlockMatrix<'_>,
9514        activations: &[f32],
9515        tokens: usize,
9516    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9517        let mut output = run_rank_nvfp4(&self.ranks[0], matrix, activations, tokens)?;
9518        apply_macro(&mut output, matrix.macro_scale);
9519        Ok(output)
9520    }
9521
9522    /// Column-parallel NVFP4 projection: output rows partition across ranks, host gather in rank
9523    /// order, macro applied ONCE post-gather.
9524    pub fn column_parallel_nvfp4(
9525        &self,
9526        matrix: Nvfp4BlockMatrix<'_>,
9527        activations: &[f32],
9528        tokens: usize,
9529    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
9530        matrix.validate()?;
9531        validate_activations(activations, tokens, matrix.in_features)?;
9532        let tp = self.ranks.len();
9533        let local_out = matrix.out_features / tp;
9534        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
9535        let mut rank_outputs = Vec::with_capacity(tp);
9536        for (rank_index, rank) in self.ranks.iter().enumerate() {
9537            let shard = nvfp4_column_shard(matrix, tp, rank_index)?;
9538            let output = run_rank_nvfp4(rank, shard, activations, tokens)?;
9539            let row_start = rank_index * local_out;
9540            for token in 0..tokens {
9541                gathered[token * matrix.out_features + row_start
9542                    ..token * matrix.out_features + row_start + local_out]
9543                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
9544            }
9545            rank_outputs.push(output);
9546        }
9547        apply_macro(&mut gathered, matrix.macro_scale);
9548        Ok(ColumnParallelResult {
9549            gathered,
9550            rank_outputs,
9551        })
9552    }
9553
9554    /// Row-parallel NVFP4 projection: input columns partition at 64-superblock boundaries,
9555    /// rank-local partials reduce in stable rank order, macro applied ONCE post-reduce.
9556    pub fn row_parallel_nvfp4(
9557        &self,
9558        matrix: Nvfp4BlockMatrix<'_>,
9559        activations: &[f32],
9560        tokens: usize,
9561    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
9562        matrix.validate()?;
9563        validate_activations(activations, tokens, matrix.in_features)?;
9564        let tp = self.ranks.len();
9565        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
9566        let mut rank_partials = Vec::with_capacity(tp);
9567        for (rank_index, rank) in self.ranks.iter().enumerate() {
9568            let (codes, scales, local_in) = nvfp4_row_shard(matrix, tp, rank_index)?;
9569            let local_activations =
9570                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
9571            let shard = Nvfp4BlockMatrix {
9572                codes: &codes,
9573                scales: &scales,
9574                macro_scale: matrix.macro_scale,
9575                out_features: matrix.out_features,
9576                in_features: local_in,
9577            };
9578            let partial = run_rank_nvfp4(rank, shard, &local_activations, tokens)?;
9579            for (sum, value) in reduced.iter_mut().zip(&partial) {
9580                *sum += *value;
9581            }
9582            rank_partials.push(partial);
9583        }
9584        apply_macro(&mut reduced, matrix.macro_scale);
9585        Ok(RowParallelResult {
9586            reduced,
9587            rank_partials,
9588        })
9589    }
9590
9591    pub fn upload_expert_nvfp4(
9592        &self,
9593        gate: Nvfp4BlockMatrix<'_>,
9594        up: Nvfp4BlockMatrix<'_>,
9595        down: Nvfp4BlockMatrix<'_>,
9596    ) -> Result<ResidentTpNvfp4Expert, Box<dyn std::error::Error>> {
9597        if gate.in_features != up.in_features || gate.out_features != up.out_features {
9598            return Err("NVFP4 TP expert gate/up dimensions differ".into());
9599        }
9600        if down.in_features != gate.out_features || down.out_features != gate.in_features {
9601            return Err(format!(
9602                "NVFP4 TP expert down {}x{} does not invert gate/up {}x{}",
9603                down.out_features, down.in_features, gate.out_features, gate.in_features
9604            )
9605            .into());
9606        }
9607        let tp = self.ranks.len();
9608        let mut gate_ranks = Vec::with_capacity(tp);
9609        let mut up_ranks = Vec::with_capacity(tp);
9610        let mut down_ranks = Vec::with_capacity(tp);
9611        for (rank_index, engine) in self.ranks.iter().enumerate() {
9612            gate_ranks.push(upload_rank_nvfp4(
9613                engine,
9614                nvfp4_column_shard(gate, tp, rank_index)?,
9615            )?);
9616            up_ranks.push(upload_rank_nvfp4(
9617                engine,
9618                nvfp4_column_shard(up, tp, rank_index)?,
9619            )?);
9620            let (codes, scales, local_in) = nvfp4_row_shard(down, tp, rank_index)?;
9621            down_ranks.push(upload_rank_nvfp4(
9622                engine,
9623                Nvfp4BlockMatrix {
9624                    codes: &codes,
9625                    scales: &scales,
9626                    macro_scale: down.macro_scale,
9627                    out_features: down.out_features,
9628                    in_features: local_in,
9629                },
9630            )?);
9631        }
9632        Ok(ResidentTpNvfp4Expert {
9633            gate: ResidentNvfp4ColumnParallel {
9634                ranks: gate_ranks,
9635                out_features: gate.out_features,
9636                in_features: gate.in_features,
9637            },
9638            up: ResidentNvfp4ColumnParallel {
9639                ranks: up_ranks,
9640                out_features: up.out_features,
9641                in_features: up.in_features,
9642            },
9643            down: ResidentNvfp4RowParallel {
9644                ranks: down_ranks,
9645                out_features: down.out_features,
9646                in_features: down.in_features,
9647            },
9648            input_width: gate.in_features,
9649            expert_width: gate.out_features,
9650        })
9651    }
9652
9653    fn column_parallel_resident_nvfp4(
9654        &self,
9655        matrix: &ResidentNvfp4ColumnParallel,
9656        activations: &[f32],
9657        tokens: usize,
9658    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9659        validate_activations(activations, tokens, matrix.in_features)?;
9660        let local_out = matrix.out_features / self.ranks.len();
9661        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
9662        let mut macro_scale = None;
9663        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
9664            let output = run_resident_rank_nvfp4(engine, shard, activations, tokens)?;
9665            let row_start = rank_index * local_out;
9666            for token in 0..tokens {
9667                gathered[token * matrix.out_features + row_start
9668                    ..token * matrix.out_features + row_start + local_out]
9669                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
9670            }
9671            macro_scale = Some(shard.macro_scale);
9672        }
9673        apply_macro(
9674            &mut gathered,
9675            macro_scale.ok_or("NVFP4 column-parallel matrix has no ranks")?,
9676        );
9677        Ok(gathered)
9678    }
9679
9680    fn row_parallel_resident_nvfp4(
9681        &self,
9682        matrix: &ResidentNvfp4RowParallel,
9683        activations: &[f32],
9684        tokens: usize,
9685    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9686        validate_activations(activations, tokens, matrix.in_features)?;
9687        let tp = self.ranks.len();
9688        let local_in = matrix.in_features / tp;
9689        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
9690        let mut macro_scale = None;
9691        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
9692            if shard.in_features != local_in {
9693                return Err(format!(
9694                    "NVFP4 resident row shard in_features {} != expected {local_in}",
9695                    shard.in_features
9696                )
9697                .into());
9698            }
9699            let local_activations =
9700                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
9701            let partial = run_resident_rank_nvfp4(engine, shard, &local_activations, tokens)?;
9702            for (sum, value) in reduced.iter_mut().zip(&partial) {
9703                *sum += *value;
9704            }
9705            macro_scale = Some(shard.macro_scale);
9706        }
9707        apply_macro(
9708            &mut reduced,
9709            macro_scale.ok_or("NVFP4 row-parallel matrix has no ranks")?,
9710        );
9711        Ok(reduced)
9712    }
9713
9714    pub fn run_expert_nvfp4(
9715        &self,
9716        expert: &ResidentTpNvfp4Expert,
9717        input: &[f32],
9718        tokens: usize,
9719    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9720        validate_activations(input, tokens, expert.input_width)?;
9721        let gate = self.column_parallel_resident_nvfp4(&expert.gate, input, tokens)?;
9722        let up = self.column_parallel_resident_nvfp4(&expert.up, input, tokens)?;
9723        let activated: Vec<f32> = gate
9724            .iter()
9725            .zip(&up)
9726            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
9727            .collect();
9728        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
9729        self.row_parallel_resident_nvfp4(&expert.down, &activated, tokens)
9730    }
9731
9732    /// Upload every expert's TP shards resident (one repacked block buffer per expert per rank).
9733    pub fn upload_tensor_parallel_nvfp4(
9734        &self,
9735        gate: Nvfp4ExpertBank<'_>,
9736        up: Nvfp4ExpertBank<'_>,
9737        down: Nvfp4ExpertBank<'_>,
9738    ) -> Result<ResidentNvfp4TensorParallel, Box<dyn std::error::Error>> {
9739        gate.validate()?;
9740        up.validate()?;
9741        down.validate()?;
9742        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
9743            return Err("NVFP4 TP gate/up/down expert counts differ".into());
9744        }
9745        if gate.in_features != up.in_features || gate.out_features != up.out_features {
9746            return Err("NVFP4 TP gate/up dimensions differ".into());
9747        }
9748        if down.in_features != gate.out_features || down.out_features != gate.in_features {
9749            return Err(format!(
9750                "NVFP4 TP down {}x{} does not invert gate/up {}x{}",
9751                down.out_features, down.in_features, gate.out_features, gate.in_features
9752            )
9753            .into());
9754        }
9755        let tp = self.ranks.len();
9756        if gate.out_features % tp != 0 {
9757            return Err(format!(
9758                "NVFP4 TP expert output width {} is not divisible by TP={tp}",
9759                gate.out_features
9760            )
9761            .into());
9762        }
9763        if down.in_features % NVFP4_CANONICAL_ROW_SHARDS != 0
9764            || (down.in_features / NVFP4_CANONICAL_ROW_SHARDS) % 64 != 0
9765        {
9766            return Err(format!(
9767                "NVFP4 TP expert input width {} does not split into 64-aligned canonical \
9768                 shards ({NVFP4_CANONICAL_ROW_SHARDS})",
9769                down.in_features
9770            )
9771            .into());
9772        }
9773        if tp > NVFP4_CANONICAL_ROW_SHARDS {
9774            return Err(format!(
9775                "NVFP4 TP world {tp} exceeds the canonical row-shard grid \
9776                 ({NVFP4_CANONICAL_ROW_SHARDS})"
9777            )
9778            .into());
9779        }
9780
9781        let ep2 = step_nvfp4_ep2_on() && tp == 2;
9782        let mut gate_ranks = Vec::with_capacity(tp);
9783        let mut up_ranks = Vec::with_capacity(tp);
9784        let mut macros_gate_dev = Vec::with_capacity(tp);
9785        let mut macros_up_dev = Vec::with_capacity(tp);
9786        let mut macros_down_dev = Vec::with_capacity(tp);
9787        for (rank_index, engine) in self.ranks.iter().enumerate() {
9788            let _main = engine.gpu.enter_main()?;
9789            // Contiguous per-rank banks: repack every expert shard into one host buffer, one
9790            // upload. Contiguity feeds the batched selected-experts launch; per-expert bytes
9791            // are unchanged (same repack).
9792            // EP2: this rank holds the FULL matrices of the experts it owns (id & 1 ==
9793            // rank_index), stacked at slot id >> 1 — same total bytes as the shard bank.
9794            let mut gate_host: Vec<u8> = Vec::new();
9795            let mut up_host: Vec<u8> = Vec::new();
9796            let mut owned = 0usize;
9797            for expert in 0..gate.expert_count {
9798                if ep2 {
9799                    if expert % 2 != rank_index {
9800                        continue;
9801                    }
9802                    owned += 1;
9803                    gate_host
9804                        .extend_from_slice(&nvfp4_repack_bank_matrix(gate.expert(expert)?, true));
9805                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(up.expert(expert)?, true));
9806                } else {
9807                    let gate_shard = nvfp4_column_shard(gate.expert(expert)?, tp, rank_index)?;
9808                    gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(gate_shard, false));
9809                    let up_shard = nvfp4_column_shard(up.expert(expert)?, tp, rank_index)?;
9810                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(up_shard, false));
9811                }
9812            }
9813            let bank_experts = if ep2 { owned } else { gate.expert_count };
9814            let gate_expert_bytes = gate_host.len() / bank_experts.max(1);
9815            let up_expert_bytes = up_host.len() / bank_experts.max(1);
9816            let local_out = if ep2 {
9817                gate.out_features
9818            } else {
9819                gate.out_features / tp
9820            };
9821            gate_ranks.push(ResidentNvfp4ColumnBankRank {
9822                bank: engine.htod_bytes(&gate_host)?,
9823                expert_bytes: gate_expert_bytes,
9824                local_out,
9825                in_features: gate.in_features,
9826                row_bytes: nvfp4_row_bytes(gate.in_features),
9827            });
9828            up_ranks.push(ResidentNvfp4ColumnBankRank {
9829                bank: engine.htod_bytes(&up_host)?,
9830                expert_bytes: up_expert_bytes,
9831                local_out,
9832                in_features: up.in_features,
9833                row_bytes: nvfp4_row_bytes(up.in_features),
9834            });
9835            macros_gate_dev.push(engine.htod(gate.macros)?);
9836            macros_up_dev.push(engine.htod(up.macros)?);
9837            macros_down_dev.push(engine.htod(down.macros)?);
9838        }
9839        // Down: canonical shard grid, NOT the world size (see NVFP4_CANONICAL_ROW_SHARDS).
9840        // Shard s lives on rank s % world, so TP1 holds both shards and TP2 one each, while the
9841        // execution and reduction order stay identical.
9842        let mut down_ranks = Vec::with_capacity(NVFP4_CANONICAL_ROW_SHARDS);
9843        for shard_index in 0..NVFP4_CANONICAL_ROW_SHARDS {
9844            let device_rank = shard_index % tp;
9845            let engine = &self.ranks[device_rank];
9846            let _main = engine.gpu.enter_main()?;
9847            let mut down_host: Vec<u8> = Vec::new();
9848            let mut owned = 0usize;
9849            for expert in 0..down.expert_count {
9850                let down_matrix = down.expert(expert)?;
9851                if ep2 {
9852                    // EP2: shard_index doubles as the owner rank; full-width down matrices
9853                    // of the owned experts, stacked at slot id >> 1.
9854                    if expert % 2 != device_rank {
9855                        continue;
9856                    }
9857                    owned += 1;
9858                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(down_matrix, true));
9859                } else {
9860                    let (codes, scales, local_in) =
9861                        nvfp4_row_shard(down_matrix, NVFP4_CANONICAL_ROW_SHARDS, shard_index)?;
9862                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(
9863                        Nvfp4BlockMatrix {
9864                            codes: &codes,
9865                            scales: &scales,
9866                            macro_scale: down_matrix.macro_scale,
9867                            out_features: down_matrix.out_features,
9868                            in_features: local_in,
9869                        },
9870                        false,
9871                    ));
9872                }
9873            }
9874            let bank_experts = if ep2 { owned } else { down.expert_count };
9875            let down_expert_bytes = down_host.len() / bank_experts.max(1);
9876            let local_in = if ep2 {
9877                down.in_features
9878            } else {
9879                down.in_features / NVFP4_CANONICAL_ROW_SHARDS
9880            };
9881            down_ranks.push(ResidentNvfp4RowBankRank {
9882                bank: engine.htod_bytes(&down_host)?,
9883                expert_bytes: down_expert_bytes,
9884                device_rank,
9885                out_features: down.out_features,
9886                local_in,
9887                row_bytes: nvfp4_row_bytes(local_in),
9888            });
9889        }
9890        Ok(ResidentNvfp4TensorParallel {
9891            gate: gate_ranks,
9892            up: up_ranks,
9893            down: down_ranks,
9894            macros_gate: gate.macros.to_vec(),
9895            macros_up: up.macros.to_vec(),
9896            macros_down: down.macros.to_vec(),
9897            macros_gate_dev,
9898            macros_up_dev,
9899            macros_down_dev,
9900            expert_count: gate.expert_count,
9901            input_width: gate.in_features,
9902            expert_width: gate.out_features,
9903            device_workspace: std::sync::Mutex::new(None),
9904            prime_tables: std::sync::Mutex::new(Vec::new()),
9905            ep2,
9906        })
9907    }
9908
9909    /// EP2 host-canonical: the whole expert executes on its owning rank at full width
9910    /// (owner = expert & 1, bank slot = expert >> 1). Per-row program == the column-bank
9911    /// path's kernel, so gate/up are bit-equal to the TP layout.
9912    fn run_full_bank_expert_nvfp4(
9913        &self,
9914        ranks: &[ResidentNvfp4ColumnBankRank],
9915        macros: &[f32],
9916        expert: usize,
9917        input: &[f32],
9918    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9919        let owner = expert & 1;
9920        let slot = expert >> 1;
9921        let bank = ranks
9922            .get(owner)
9923            .ok_or("NVFP4 EP2 column bank missing owner rank")?;
9924        let engine = &self.ranks[owner];
9925        let _main = engine.gpu.enter_main()?;
9926        let activations = engine.htod(input)?;
9927        // EP2 banks are ALWAYS slot-major (see nvfp4_repack_bank_matrix), so the oracle
9928        // must be the slot-major reader.
9929        let output = engine.qmatvec_nvfp4_fast_v2(
9930            &bank.expert(slot),
9931            &activations,
9932            1,
9933            bank.in_features,
9934            bank.local_out,
9935            bank.row_bytes,
9936        )?;
9937        let mut out = engine.dtoh(&output)?;
9938        apply_macro(&mut out, macros[expert]);
9939        Ok(out)
9940    }
9941
9942    /// EP2 host-canonical down: one full-width dot on the owner (NUMERIC-CLASS vs the
9943    /// canonical 2-shard sum — the parenthesization this door declares).
9944    fn run_full_down_expert_nvfp4(
9945        &self,
9946        shards: &[ResidentNvfp4RowBankRank],
9947        macros: &[f32],
9948        expert: usize,
9949        input: &[f32],
9950    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9951        let owner = expert & 1;
9952        let slot = expert >> 1;
9953        let shard = shards
9954            .get(owner)
9955            .ok_or("NVFP4 EP2 down bank missing owner rank")?;
9956        let engine = &self.ranks[owner];
9957        let _main = engine.gpu.enter_main()?;
9958        let activations = engine.htod(input)?;
9959        // EP2 down banks are ALWAYS slot-major (see nvfp4_repack_bank_matrix).
9960        let output = engine.qmatvec_nvfp4_fast_v2(
9961            &shard.expert(slot),
9962            &activations,
9963            1,
9964            shard.local_in,
9965            shard.out_features,
9966            shard.row_bytes,
9967        )?;
9968        let mut out = engine.dtoh(&output)?;
9969        apply_macro(&mut out, macros[expert]);
9970        Ok(out)
9971    }
9972
9973    fn run_column_bank_expert_nvfp4(
9974        &self,
9975        ranks: &[ResidentNvfp4ColumnBankRank],
9976        macros: &[f32],
9977        expert: usize,
9978        input: &[f32],
9979    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9980        let local_out = ranks
9981            .first()
9982            .ok_or("NVFP4 TP column bank has no ranks")?
9983            .local_out;
9984        let mut gathered = vec![0.0f32; local_out * ranks.len()];
9985        for (rank_index, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
9986            let _main = engine.gpu.enter_main()?;
9987            let activations = engine.htod(input)?;
9988            let output = engine.qmatvec_nvfp4_fast(
9989                &bank.expert(expert),
9990                &activations,
9991                1,
9992                bank.in_features,
9993                bank.local_out,
9994                bank.row_bytes,
9995            )?;
9996            let output = engine.dtoh(&output)?;
9997            gathered[rank_index * local_out..(rank_index + 1) * local_out].copy_from_slice(&output);
9998        }
9999        apply_macro(&mut gathered, macros[expert]);
10000        Ok(gathered)
10001    }
10002
10003    /// Canonical-shard row reduction: iterate the FIXED shard grid in shard order (each shard
10004    /// executes on its owning rank engine), so the reduction parenthesization is identical at
10005    /// every world size — that identity is what the TP1-oracle-vs-TP2 bit gate proves.
10006    fn run_row_bank_expert_nvfp4(
10007        &self,
10008        shards: &[ResidentNvfp4RowBankRank],
10009        macros: &[f32],
10010        expert: usize,
10011        input: &[f32],
10012    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10013        let out_features = shards
10014            .first()
10015            .ok_or("NVFP4 TP row bank has no canonical shards")?
10016            .out_features;
10017        let in_features = shards.iter().map(|shard| shard.local_in).sum::<usize>();
10018        let mut reduced = vec![0.0f32; out_features];
10019        for (shard_index, shard) in shards.iter().enumerate() {
10020            let engine = self
10021                .ranks
10022                .get(shard.device_rank)
10023                .ok_or("NVFP4 canonical shard names a rank outside this runtime")?;
10024            let _main = engine.gpu.enter_main()?;
10025            let local_activations =
10026                activation_shard(input, 1, in_features, shards.len(), shard_index);
10027            let activations = engine.htod(&local_activations)?;
10028            let output = engine.qmatvec_nvfp4_fast(
10029                &shard.expert(expert),
10030                &activations,
10031                1,
10032                shard.local_in,
10033                shard.out_features,
10034                shard.row_bytes,
10035            )?;
10036            let partial = engine.dtoh(&output)?;
10037            for (sum, value) in reduced.iter_mut().zip(&partial) {
10038                *sum += *value;
10039            }
10040        }
10041        apply_macro(&mut reduced, macros[expert]);
10042        Ok(reduced)
10043    }
10044
10045    /// Upload whole experts per owning rank (NVFP4 expert-parallel: the layout the clamped tail
10046    /// layers require — clamp semantics do not distribute across a tensor shard). Each owned
10047    /// expert keeps its full gate/up/down as one repacked block buffer on its owner.
10048    pub fn upload_expert_parallel_nvfp4(
10049        &self,
10050        gate: Nvfp4ExpertBank<'_>,
10051        up: Nvfp4ExpertBank<'_>,
10052        down: Nvfp4ExpertBank<'_>,
10053    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
10054        gate.validate()?;
10055        up.validate()?;
10056        down.validate()?;
10057        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
10058            return Err("NVFP4 EP gate/up/down expert counts differ".into());
10059        }
10060        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10061            return Err("NVFP4 EP gate/up dimensions differ".into());
10062        }
10063        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10064            return Err(format!(
10065                "NVFP4 EP down {}x{} does not invert gate/up {}x{}",
10066                down.out_features, down.in_features, gate.out_features, gate.in_features
10067            )
10068            .into());
10069        }
10070        let world = self.ranks.len();
10071        if gate.expert_count % world != 0 {
10072            return Err(format!(
10073                "NVFP4 EP expert count {} is not divisible by {world} ranks",
10074                gate.expert_count
10075            )
10076            .into());
10077        }
10078        let experts_per_rank = gate.expert_count / world;
10079        let mut ranks = Vec::with_capacity(world);
10080        for (rank_index, engine) in self.ranks.iter().enumerate() {
10081            let _main = engine.gpu.enter_main()?;
10082            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
10083            let mut gate_experts = Vec::with_capacity(experts_per_rank);
10084            let mut up_experts = Vec::with_capacity(experts_per_rank);
10085            let mut down_experts = Vec::with_capacity(experts_per_rank);
10086            for expert in expert_range.clone() {
10087                gate_experts.push(engine.htod_bytes(&nvfp4_repack_matrix(gate.expert(expert)?))?);
10088                up_experts.push(engine.htod_bytes(&nvfp4_repack_matrix(up.expert(expert)?))?);
10089                down_experts.push(engine.htod_bytes(&nvfp4_repack_matrix(down.expert(expert)?))?);
10090            }
10091            ranks.push(ResidentNvfp4EpRank {
10092                gate: gate_experts,
10093                up: up_experts,
10094                down: down_experts,
10095                expert_range,
10096            });
10097        }
10098        Ok(ResidentNvfp4ExpertParallel {
10099            ranks,
10100            macros_gate: gate.macros.to_vec(),
10101            macros_up: up.macros.to_vec(),
10102            macros_down: down.macros.to_vec(),
10103            expert_count: gate.expert_count,
10104            input_width: gate.in_features,
10105            expert_width: gate.out_features,
10106            gate_row_bytes: nvfp4_row_bytes(gate.in_features),
10107            down_row_bytes: nvfp4_row_bytes(down.in_features),
10108        })
10109    }
10110
10111    /// Routed NVFP4 expert-parallel program, host-canonical: every selected expert executes WHOLE
10112    /// on its owning rank (gate -> up -> clamped-or-plain SwiGLU on host -> down), each projection
10113    /// macro applied once post-kernel, route-weighted accumulate on the host in slot order. The
10114    /// activation uses `step_expert_activation_host`, so the clamped tail layers keep the official
10115    /// contract. Exactness-first; no throughput claim.
10116    #[allow(clippy::too_many_arguments)]
10117    pub fn run_routed_experts_nvfp4(
10118        &self,
10119        experts: &ResidentNvfp4ExpertParallel,
10120        input: &[f32],
10121        tokens: usize,
10122        selected: &[usize],
10123        route_weights: &[f32],
10124        experts_per_token: usize,
10125        activation_limit: Option<f32>,
10126    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10127        validate_activations(input, tokens, experts.input_width)?;
10128        let pairs = tokens
10129            .checked_mul(experts_per_token)
10130            .ok_or("NVFP4 EP route count overflow")?;
10131        if selected.len() != pairs || route_weights.len() != pairs {
10132            return Err(format!(
10133                "NVFP4 EP routes selected={} weights={} != tokens {tokens} x experts/token \
10134                 {experts_per_token} ({pairs})",
10135                selected.len(),
10136                route_weights.len(),
10137            )
10138            .into());
10139        }
10140        if !route_weights.iter().all(|weight| weight.is_finite()) {
10141            return Err("NVFP4 EP route weights contain a non-finite value".into());
10142        }
10143        let experts_per_rank = experts.expert_count / experts.ranks.len();
10144        let mut output = vec![0.0f32; tokens * experts.input_width];
10145        for token in 0..tokens {
10146            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
10147            for slot in 0..experts_per_token {
10148                let pair = token * experts_per_token + slot;
10149                let expert = selected[pair];
10150                if expert >= experts.expert_count {
10151                    return Err(format!(
10152                        "NVFP4 EP selected expert {expert} outside 0..{}",
10153                        experts.expert_count
10154                    )
10155                    .into());
10156                }
10157                let owner = expert / experts_per_rank;
10158                let local = expert - owner * experts_per_rank;
10159                let rank = &experts.ranks[owner];
10160                let engine = &self.ranks[owner];
10161                let _main = engine.gpu.enter_main()?;
10162                let device_input = engine.htod(input_row)?;
10163                let gate_out = engine.qmatvec_nvfp4_fast(
10164                    &rank.gate[local].slice(0..rank.gate[local].len()),
10165                    &device_input,
10166                    1,
10167                    experts.input_width,
10168                    experts.expert_width,
10169                    experts.gate_row_bytes,
10170                )?;
10171                let up_out = engine.qmatvec_nvfp4_fast(
10172                    &rank.up[local].slice(0..rank.up[local].len()),
10173                    &device_input,
10174                    1,
10175                    experts.input_width,
10176                    experts.expert_width,
10177                    experts.gate_row_bytes,
10178                )?;
10179                let mut gate_host = engine.dtoh(&gate_out)?;
10180                let mut up_host = engine.dtoh(&up_out)?;
10181                apply_macro(&mut gate_host, experts.macros_gate[expert]);
10182                apply_macro(&mut up_host, experts.macros_up[expert]);
10183                let activated: Vec<f32> = gate_host
10184                    .iter()
10185                    .zip(&up_host)
10186                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
10187                    .collect();
10188                let device_activated = engine.htod(&activated)?;
10189                let down_out = engine.qmatvec_nvfp4_fast(
10190                    &rank.down[local].slice(0..rank.down[local].len()),
10191                    &device_activated,
10192                    1,
10193                    experts.expert_width,
10194                    experts.input_width,
10195                    experts.down_row_bytes,
10196                )?;
10197                let mut down_host = engine.dtoh(&down_out)?;
10198                apply_macro(&mut down_host, experts.macros_down[expert]);
10199                let weight = route_weights[pair];
10200                for (sum, value) in output
10201                    [token * experts.input_width..(token + 1) * experts.input_width]
10202                    .iter_mut()
10203                    .zip(down_host)
10204                {
10205                    *sum += weight * value;
10206                }
10207            }
10208        }
10209        Ok(output)
10210    }
10211
10212    /// Device-resident routed NVFP4 expert program (decode shape, t=1 rows). The geometry gift
10213    /// this exploits: gate/up column halves land on the SAME rank that owns the matching down
10214    /// canonical shard (act[rank r] is exactly down-shard r's input-column window), so the whole
10215    /// expert interior — gate, up, macro-scaled SwiGLU, down partial, route-weighted accumulate —
10216    /// runs rank-local with ZERO cross-rank transfer. Per (token, layer): one input upload per
10217    /// rank, one fenced peer copy of the remote accumulator, one root add, one readback.
10218    ///
10219    /// Numeric class: device silu (silu_mul_scaled) with gate/up macros folded as gs/us and the
10220    /// down macro folded into the accumulate scalar (weight * macro_down — exact, both are
10221    /// per-expert constants). This matches the owning-stage MoE dev-path semantics, NOT the
10222    /// host-canonical program bit-for-bit; gate it with argmax + relative bounds against the
10223    /// host-canonical oracle, and with repeat determinism against itself.
10224    /// Clamped layers refuse (they stay on the EP program).
10225    pub fn run_tensor_parallel_routes_nvfp4_device(
10226        &self,
10227        experts: &ResidentNvfp4TensorParallel,
10228        input: &[f32],
10229        selected: &[usize],
10230        route_weights: &[f32],
10231        experts_per_token: usize,
10232        activation_limit: Option<f32>,
10233    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10234        validate_activations(input, 1, experts.input_width)?;
10235        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
10236            return Err(format!(
10237                "NVFP4 device routes selected={} weights={} != experts/token {experts_per_token}",
10238                selected.len(),
10239                route_weights.len(),
10240            )
10241            .into());
10242        }
10243        if !route_weights.iter().all(|weight| weight.is_finite()) {
10244            return Err("NVFP4 device route weights contain a non-finite value".into());
10245        }
10246        let world = self.ranks.len();
10247        if world != NVFP4_CANONICAL_ROW_SHARDS {
10248            return Err(format!(
10249                "NVFP4 device routes require world == canonical shard grid \
10250                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
10251            )
10252            .into());
10253        }
10254        let local_out = if experts.ep2 {
10255            experts.expert_width
10256        } else {
10257            experts.expert_width / world
10258        };
10259
10260        // MEMRA_STEP_TP_TIMING=1: cumulative wall-clock of this program, printed every 430 calls
10261        // (~one 43-layer decode step's worth) so a bench run decomposes expert-program time vs
10262        // everything else without Nsight.
10263        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10264        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10265        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
10266        let started = timing.then(std::time::Instant::now);
10267
10268        let n_sel = experts_per_token;
10269        let mut workspace_guard = experts
10270            .device_workspace
10271            .lock()
10272            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
10273        if workspace_guard.is_none() {
10274            let mut gate_out = Vec::with_capacity(world);
10275            let mut up_out = Vec::with_capacity(world);
10276            let mut act_q = Vec::with_capacity(world);
10277            let mut act_d = Vec::with_capacity(world);
10278            let mut sel = Vec::with_capacity(world);
10279            let mut partial = Vec::with_capacity(world);
10280            let mut accumulator = Vec::with_capacity(world);
10281            let mut combine_w = Vec::with_capacity(world);
10282            let mut route_w = Vec::with_capacity(world);
10283            let mut in_q = Vec::with_capacity(world);
10284            let mut in_d = Vec::with_capacity(world);
10285            let mut input = Vec::with_capacity(world);
10286            let mut ev_rank = Vec::with_capacity(world);
10287            let moe_direct = moe_direct_on();
10288            for (rank, engine) in self.ranks.iter().enumerate() {
10289                let _main = engine.gpu.enter_main()?;
10290                gate_out.push(engine.uninit(n_sel * local_out)?);
10291                up_out.push(engine.uninit(n_sel * local_out)?);
10292                act_q.push(engine.uninit_i8(n_sel * local_out)?);
10293                act_d.push(engine.uninit(n_sel * local_out / 32)?);
10294                sel.push(engine.htod_i32(&vec![0i32; n_sel])?);
10295                partial.push(engine.uninit(n_sel * experts.input_width)?);
10296                // Direct join: peer accumulators live on ROOT (single P2P store pass).
10297                if moe_direct && rank != 0 {
10298                    let root = &self.ranks[0];
10299                    let _root_main = root.gpu.enter_main()?;
10300                    accumulator.push(root.zeros(experts.input_width)?);
10301                } else {
10302                    accumulator.push(engine.zeros(experts.input_width)?);
10303                }
10304                combine_w.push(engine.htod(&vec![0.0f32; n_sel])?);
10305                route_w.push(engine.htod(&vec![0.0f32; n_sel])?);
10306                in_q.push(engine.uninit_i8(experts.input_width)?);
10307                in_d.push(engine.uninit(experts.input_width / 32)?);
10308                input.push(engine.uninit(experts.input_width)?);
10309                ev_rank.push(engine.ctx().new_event(None)?);
10310            }
10311            let root = &self.ranks[0];
10312            let _main = root.gpu.enter_main()?;
10313            *workspace_guard = Some(Nvfp4DeviceRoutesWorkspace {
10314                prestaged: false,
10315                rank1_routed: false,
10316                ev_input: None,
10317                fence_flags_raw: 0,
10318                fence_ticket: 0,
10319                gate_out,
10320                up_out,
10321                act_q,
10322                act_d,
10323                sel,
10324                partial,
10325                accumulator,
10326                combine_w,
10327                route_w,
10328                in_q,
10329                in_d,
10330                dev_route_e: None,
10331                in_stage_e: None,
10332                out_stage_e: None,
10333                routes_graph: None,
10334                raw_dev_route_e: None,
10335                raw_combine: None,
10336                raw_input: Vec::new(),
10337                raw_sel: Vec::new(),
10338                raw_route_w: Vec::new(),
10339                remote: root.uninit(experts.input_width)?,
10340                combined: root.uninit(experts.input_width)?,
10341                n_sel,
10342                input,
10343                ev_rank,
10344                ev_done: Some(root.ctx().new_event(None)?),
10345                ev_entry: None,
10346            });
10347        }
10348        let workspace = workspace_guard
10349            .as_mut()
10350            .expect("NVFP4 device routes workspace initialized above");
10351        // EP2 uses this call only as the workspace-arming warmup (the prejoin path drives
10352        // decode); its host-routed sweep semantics do not apply to whole-expert banks.
10353        if experts.ep2 {
10354            return Ok(vec![0.0f32; experts.input_width]);
10355        }
10356        if workspace.n_sel != n_sel {
10357            return Err(format!(
10358                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
10359                workspace.n_sel
10360            )
10361            .into());
10362        }
10363        for &expert in selected {
10364            if expert >= experts.expert_count {
10365                return Err(format!(
10366                    "NVFP4 device selected expert {expert} outside 0..{}",
10367                    experts.expert_count
10368                )
10369                .into());
10370            }
10371        }
10372        let sel_i32 = selected
10373            .iter()
10374            .map(|&expert| expert as i32)
10375            .collect::<Vec<_>>();
10376
10377        // BATCHED program (2026-08-20): per rank, ONE launch per sweep (gate, up, SwiGLU,
10378        // down) covers every selected expert via the selection array and the contiguous bank —
10379        // the per-expert launch loop was pure host latency (~100 sequential launches/layer,
10380        // 291us wall for ~35us of arithmetic). Per (expert, row) the kernels are bit-identical
10381        // to the per-expert forms, and the route-weight axpy chain keeps its exact sequential
10382        // accumulation order — the program's values are unchanged.
10383        for (rank_index, engine) in self.ranks.iter().enumerate() {
10384            let _main = engine.gpu.enter_main()?;
10385            let device_input = engine.htod(input)?;
10386            let Nvfp4DeviceRoutesWorkspace { in_q, in_d, .. } = &mut *workspace;
10387            engine.quantize_q8_1_into(
10388                &device_input,
10389                1,
10390                experts.input_width,
10391                &mut in_q[rank_index],
10392                &mut in_d[rank_index],
10393            )?;
10394            // device_input frees on this rank's stream after the quantize — same-stream order.
10395        }
10396        self.nvfp4_routes_batched_sweeps(
10397            experts,
10398            workspace,
10399            selected,
10400            route_weights,
10401            &sel_i32,
10402            local_out,
10403            n_sel,
10404            activation_limit,
10405            false,
10406        )?;
10407
10408        // Combine: fence the remote shard's producer stream, peer-copy its accumulator to root,
10409        // reduce in canonical shard order, read back once.
10410        let root = &self.ranks[0];
10411        for engine in &self.ranks[1..] {
10412            let _main = engine.gpu.enter_main()?;
10413            engine.stream().synchronize()?;
10414        }
10415        let _main = root.gpu.enter_main()?;
10416        root.stream()
10417            .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
10418        root.add(
10419            &workspace.accumulator[0],
10420            &workspace.remote,
10421            &mut workspace.combined,
10422            experts.input_width,
10423        )?;
10424        let output = root.dtoh(&workspace.combined)?;
10425        if let Some(started) = started {
10426            use std::sync::atomic::Ordering;
10427            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
10428                + started.elapsed().as_nanos() as u64;
10429            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
10430            if calls % 430 == 0 {
10431                eprintln!(
10432                    "[nvfp4-dev-routes-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
10433                    ns as f64 / 1.0e6,
10434                    ns as f64 / calls as f64 / 1.0e3,
10435                );
10436            }
10437        }
10438        Ok(output)
10439    }
10440
10441    /// The shared batched sweeps of the device routes program: per rank, upload the selection,
10442    /// reset the accumulator, run the gate/up/SwiGLU/down batched launches, then the
10443    /// route-weight axpy chain in exact sequential per-pair order. Every op queues on the
10444    /// owning rank's stream; callers own input acquisition and the combine.
10445    #[allow(clippy::too_many_arguments)]
10446    fn nvfp4_routes_batched_sweeps(
10447        &self,
10448        experts: &ResidentNvfp4TensorParallel,
10449        workspace: &mut Nvfp4DeviceRoutesWorkspace,
10450        selected: &[usize],
10451        route_weights: &[f32],
10452        sel_i32: &[i32],
10453        local_out: usize,
10454        n_sel: usize,
10455        activation_limit: Option<f32>,
10456        device_routed: bool,
10457    ) -> Result<(), Box<dyn std::error::Error>> {
10458        for rank_index in 0..self.ranks.len() {
10459            self.nvfp4_routes_batched_sweeps_rank(
10460                experts,
10461                workspace,
10462                selected,
10463                route_weights,
10464                sel_i32,
10465                local_out,
10466                n_sel,
10467                activation_limit,
10468                device_routed,
10469                rank_index,
10470            )?;
10471        }
10472        Ok(())
10473    }
10474
10475    /// One rank's sweeps (the per-rank body of `nvfp4_routes_batched_sweeps`) — separated so
10476    /// the graph door can capture each rank's segment on its own stream.
10477    #[allow(clippy::too_many_arguments)]
10478    fn nvfp4_routes_batched_sweeps_rank(
10479        &self,
10480        experts: &ResidentNvfp4TensorParallel,
10481        workspace: &mut Nvfp4DeviceRoutesWorkspace,
10482        selected: &[usize],
10483        route_weights: &[f32],
10484        sel_i32: &[i32],
10485        local_out: usize,
10486        n_sel: usize,
10487        activation_limit: Option<f32>,
10488        device_routed: bool,
10489        rank_index: usize,
10490    ) -> Result<(), Box<dyn std::error::Error>> {
10491        {
10492            let engine = &self.ranks[rank_index];
10493            let _main = engine.gpu.enter_main()?;
10494            // EP2: whole-expert full-width sweep, owner-guarded; down+combine fused writes
10495            // this rank's slot-ordered partial straight into its accumulator (the join is
10496            // unchanged). Device-routed only — the host-routed arm and the graph door refuse
10497            // at the caller.
10498            if experts.ep2 {
10499                if !device_routed {
10500                    return Err("NVFP4 EP2 banks support the device-routed decode arm only".into());
10501                }
10502                let gate_bank = &experts.gate[rank_index];
10503                let up_bank = &experts.up[rank_index];
10504                if gate_bank.local_out != experts.expert_width
10505                    || gate_bank.expert_bytes != up_bank.expert_bytes
10506                {
10507                    return Err("NVFP4 EP2 bank geometry drifted".into());
10508                }
10509                {
10510                    let Nvfp4DeviceRoutesWorkspace {
10511                        sel,
10512                        gate_out,
10513                        up_out,
10514                        in_q,
10515                        in_d,
10516                        ..
10517                    } = &mut *workspace;
10518                    engine.qmatvec_nvfp4_sel_gu_ep_into(
10519                        &gate_bank.bank,
10520                        &up_bank.bank,
10521                        &sel[rank_index],
10522                        &in_q[rank_index],
10523                        &in_d[rank_index],
10524                        &mut gate_out[rank_index],
10525                        &mut up_out[rank_index],
10526                        n_sel,
10527                        gate_bank.in_features,
10528                        gate_bank.local_out,
10529                        gate_bank.row_bytes,
10530                        gate_bank.expert_bytes,
10531                        rank_index,
10532                    )?;
10533                }
10534                {
10535                    let Nvfp4DeviceRoutesWorkspace {
10536                        gate_out,
10537                        up_out,
10538                        sel,
10539                        act_q,
10540                        act_d,
10541                        ..
10542                    } = &mut *workspace;
10543                    engine.silu_mul_scaled_q8_1_sel_ep_into(
10544                        &gate_out[rank_index],
10545                        &up_out[rank_index],
10546                        &experts.macros_gate_dev[rank_index],
10547                        &experts.macros_up_dev[rank_index],
10548                        &sel[rank_index],
10549                        activation_limit,
10550                        &mut act_q[rank_index],
10551                        &mut act_d[rank_index],
10552                        local_out,
10553                        n_sel,
10554                        rank_index,
10555                    )?;
10556                }
10557                let shard = &experts.down[rank_index];
10558                if shard.device_rank != rank_index || shard.local_in != local_out {
10559                    return Err("NVFP4 EP2 down bank placement drifted".into());
10560                }
10561                {
10562                    let Nvfp4DeviceRoutesWorkspace {
10563                        sel,
10564                        act_q,
10565                        act_d,
10566                        route_w,
10567                        accumulator,
10568                        ..
10569                    } = &mut *workspace;
10570                    engine.qmatvec_nvfp4_sel_down8_ep_into(
10571                        &shard.bank,
10572                        &sel[rank_index],
10573                        &act_q[rank_index],
10574                        &act_d[rank_index],
10575                        &route_w[rank_index],
10576                        &experts.macros_down_dev[rank_index],
10577                        &mut accumulator[rank_index],
10578                        n_sel,
10579                        shard.local_in,
10580                        shard.out_features,
10581                        shard.row_bytes,
10582                        shard.expert_bytes,
10583                        local_out,
10584                        local_out / 32,
10585                        rank_index,
10586                    )?;
10587                }
10588                return Ok(());
10589            }
10590            if !device_routed {
10591                engine.htod_i32_into(&mut workspace.sel[rank_index], sel_i32)?;
10592                // Folded combine weights (route_weight x down macro) — one 40-byte upload
10593                // replaces the accumulator reset + n_sel sequential axpy launches below.
10594                let folded = (0..n_sel)
10595                    .map(|pair| route_weights[pair] * experts.macros_down[selected[pair]])
10596                    .collect::<Vec<_>>();
10597                let mut view = workspace.combine_w[rank_index].slice_mut(0..n_sel);
10598                engine.stream().memcpy_htod(&folded, &mut view)?;
10599            }
10600            let gate_bank = &experts.gate[rank_index];
10601            let up_bank = &experts.up[rank_index];
10602            let (aq, ad) = (&workspace.in_q[rank_index], &workspace.in_d[rank_index]);
10603            engine.qmatvec_nvfp4_sel_into(
10604                &gate_bank.bank,
10605                &workspace.sel[rank_index],
10606                aq,
10607                ad,
10608                &mut workspace.gate_out[rank_index],
10609                n_sel,
10610                gate_bank.in_features,
10611                gate_bank.local_out,
10612                gate_bank.row_bytes,
10613                gate_bank.expert_bytes,
10614                0,
10615                0,
10616            )?;
10617            engine.qmatvec_nvfp4_sel_into(
10618                &up_bank.bank,
10619                &workspace.sel[rank_index],
10620                aq,
10621                ad,
10622                &mut workspace.up_out[rank_index],
10623                n_sel,
10624                up_bank.in_features,
10625                up_bank.local_out,
10626                up_bank.row_bytes,
10627                up_bank.expert_bytes,
10628                0,
10629                0,
10630            )?;
10631            // Fused macro-scaled SwiGLU that EMITS q8_1 directly — down consumes it with no
10632            // separate quantize launch. act[rank] IS down canonical shard `rank_index`'s
10633            // input-column window (the geometry gift; see the method doc).
10634            {
10635                let Nvfp4DeviceRoutesWorkspace {
10636                    gate_out,
10637                    up_out,
10638                    sel,
10639                    act_q,
10640                    act_d,
10641                    ..
10642                } = &mut *workspace;
10643                engine.silu_mul_scaled_q8_1_sel_into(
10644                    &gate_out[rank_index],
10645                    &up_out[rank_index],
10646                    &experts.macros_gate_dev[rank_index],
10647                    &experts.macros_up_dev[rank_index],
10648                    &sel[rank_index],
10649                    activation_limit,
10650                    &mut act_q[rank_index],
10651                    &mut act_d[rank_index],
10652                    local_out,
10653                    n_sel,
10654                )?;
10655            }
10656            let shard = &experts.down[rank_index];
10657            if shard.device_rank != rank_index || shard.local_in != local_out {
10658                return Err(
10659                    "NVFP4 device routes: down canonical shard placement drifted from \
10660                     the gate/up column split"
10661                        .into(),
10662                );
10663            }
10664            {
10665                let Nvfp4DeviceRoutesWorkspace {
10666                    sel,
10667                    act_q,
10668                    act_d,
10669                    partial,
10670                    ..
10671                } = &mut *workspace;
10672                engine.qmatvec_nvfp4_sel_into(
10673                    &shard.bank,
10674                    &sel[rank_index],
10675                    &act_q[rank_index],
10676                    &act_d[rank_index],
10677                    &mut partial[rank_index],
10678                    n_sel,
10679                    shard.local_in,
10680                    shard.out_features,
10681                    shard.row_bytes,
10682                    shard.expert_bytes,
10683                    local_out,
10684                    local_out / 32,
10685                )?;
10686            }
10687            // Route-weight accumulation: axpy_rows_seq keeps the exact sequential per-pair
10688            // FP chain of the reset + n_sel axpy launches in ONE launch. Device-routed calls
10689            // fold the down macro in-kernel from the device selection.
10690            {
10691                let Nvfp4DeviceRoutesWorkspace {
10692                    partial,
10693                    combine_w,
10694                    route_w,
10695                    sel,
10696                    accumulator,
10697                    ..
10698                } = &mut *workspace;
10699                if device_routed {
10700                    engine.axpy_rows_seq_md_into(
10701                        &partial[rank_index],
10702                        &route_w[rank_index],
10703                        &experts.macros_down_dev[rank_index],
10704                        &sel[rank_index],
10705                        &mut accumulator[rank_index],
10706                        experts.input_width,
10707                        n_sel,
10708                    )?;
10709                } else {
10710                    engine.axpy_rows_seq_into(
10711                        &partial[rank_index],
10712                        &combine_w[rank_index],
10713                        &mut accumulator[rank_index],
10714                        experts.input_width,
10715                        n_sel,
10716                    )?;
10717                }
10718            }
10719        }
10720        Ok(())
10721    }
10722
10723    /// Device-IO twin of `run_tensor_parallel_routes_nvfp4_device`: the layer input arrives as
10724    /// a device row on the model engine `e` and the combined output returns as a fresh
10725    /// `e`-context row — no host round-trip, no host stream sync. Ordering is evented (the v2
10726    /// attention discipline): `ev_entry` is recorded on `e`'s stream AFTER the caller queued
10727    /// the input's producer; each rank waits it before its peer read; the root reduce waits
10728    /// every rank's done event; `e` waits the root's done event before copying out. The
10729    /// program bytes are identical to the host-IO twin — dtoh/htod and dtod preserve f32 bits.
10730    pub fn run_tensor_parallel_routes_nvfp4_device_io(
10731        &self,
10732        experts: &ResidentNvfp4TensorParallel,
10733        e: &Engine,
10734        input_dev: &crate::CudaSlice<f32>,
10735        selected: &[usize],
10736        route_weights: &[f32],
10737        experts_per_token: usize,
10738        activation_limit: Option<f32>,
10739    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10740        if input_dev.len() != experts.input_width {
10741            return Err(format!(
10742                "NVFP4 device-io routes input {} != width {}",
10743                input_dev.len(),
10744                experts.input_width
10745            )
10746            .into());
10747        }
10748        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
10749            return Err(format!(
10750                "NVFP4 device-io routes selected={} weights={} != experts/token {experts_per_token}",
10751                selected.len(),
10752                route_weights.len(),
10753            )
10754            .into());
10755        }
10756        if !route_weights.iter().all(|weight| weight.is_finite()) {
10757            return Err("NVFP4 device route weights contain a non-finite value".into());
10758        }
10759        let world = self.ranks.len();
10760        if world != NVFP4_CANONICAL_ROW_SHARDS {
10761            return Err(format!(
10762                "NVFP4 device routes require world == canonical shard grid \
10763                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
10764            )
10765            .into());
10766        }
10767        let local_out = experts.expert_width / world;
10768        let n_sel = experts_per_token;
10769
10770        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10771        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10772        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
10773        let started = timing.then(std::time::Instant::now);
10774
10775        let mut workspace_guard = experts
10776            .device_workspace
10777            .lock()
10778            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
10779        if workspace_guard.is_none() {
10780            drop(workspace_guard);
10781            // Build through the host-IO ensure path exactly once: run it with a zero input.
10782            // Cheaper than duplicating the init; the first real call overwrites everything.
10783            let zero = vec![0.0f32; experts.input_width];
10784            let zero_sel = vec![0usize; n_sel];
10785            let zero_w = vec![0.0f32; n_sel];
10786            let _ = self.run_tensor_parallel_routes_nvfp4_device(
10787                experts,
10788                &zero,
10789                &zero_sel,
10790                &zero_w,
10791                n_sel,
10792                activation_limit,
10793            )?;
10794            workspace_guard = experts
10795                .device_workspace
10796                .lock()
10797                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
10798        }
10799        let workspace = workspace_guard
10800            .as_mut()
10801            .expect("NVFP4 device routes workspace initialized above");
10802        if workspace.n_sel != n_sel {
10803            return Err(format!(
10804                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
10805                workspace.n_sel
10806            )
10807            .into());
10808        }
10809        for &expert in selected {
10810            if expert >= experts.expert_count {
10811                return Err(format!(
10812                    "NVFP4 device selected expert {expert} outside 0..{}",
10813                    experts.expert_count
10814                )
10815                .into());
10816            }
10817        }
10818        let sel_i32 = selected
10819            .iter()
10820            .map(|&expert| expert as i32)
10821            .collect::<Vec<_>>();
10822
10823        // Entry fence: e's stream position covers the input's producer AND every consumer of
10824        // the previous layer's output (queued on e's stream before this call), guarding the
10825        // workspace reuse exactly like the v2 attention driver.
10826        if let Some((_, device)) = workspace.ev_entry.as_ref() {
10827            if *device != e.ctx().ordinal() {
10828                return Err("NVFP4 device-io routes engine changed".into());
10829            }
10830        } else {
10831            let _main = e.gpu.enter_main()?;
10832            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
10833        }
10834        {
10835            let _main = e.gpu.enter_main()?;
10836            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
10837            ev_entry.record(&e.stream())?;
10838        }
10839        for (rank_index, engine) in self.ranks.iter().enumerate() {
10840            let _main = engine.gpu.enter_main()?;
10841            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
10842            engine.stream().wait(ev_entry)?;
10843            {
10844                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
10845                engine
10846                    .stream()
10847                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
10848            }
10849            {
10850                let Nvfp4DeviceRoutesWorkspace {
10851                    input, in_q, in_d, ..
10852                } = &mut *workspace;
10853                engine.quantize_q8_1_into(
10854                    &input[rank_index],
10855                    1,
10856                    experts.input_width,
10857                    &mut in_q[rank_index],
10858                    &mut in_d[rank_index],
10859                )?;
10860            }
10861        }
10862        self.nvfp4_routes_batched_sweeps(
10863            experts,
10864            workspace,
10865            selected,
10866            route_weights,
10867            &sel_i32,
10868            local_out,
10869            n_sel,
10870            activation_limit,
10871            false,
10872        )?;
10873
10874        // Evented combine: rank done events replace the host stream syncs, the reduce runs on
10875        // the root stream in canonical shard order, and e copies the combined row out behind
10876        // the root's done event.
10877        // rank0 == root: its own stream order already covers its sweep; only the PEER
10878        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
10879        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
10880            let _main = engine.gpu.enter_main()?;
10881            workspace.ev_rank[rank_index].record(&engine.stream())?;
10882        }
10883        if moe_direct_on() && self.ranks.len() == 2 {
10884            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
10885            // rank0's is root-stream-ordered. One root event + rank1's own event order
10886            // the model engine's single add — same operand order as root's add
10887            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
10888            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
10889            // hazard class does not apply).
10890            {
10891                let root = &self.ranks[0];
10892                let _main = root.gpu.enter_main()?;
10893                workspace
10894                    .ev_done
10895                    .as_ref()
10896                    .expect("device routes done event")
10897                    .record(&root.stream())?;
10898            }
10899            let _main = e.gpu.enter_main()?;
10900            e.stream().wait(
10901                workspace
10902                    .ev_done
10903                    .as_ref()
10904                    .expect("device routes done event"),
10905            )?;
10906            for ev in workspace.ev_rank.iter().skip(1) {
10907                e.stream().wait(ev)?;
10908            }
10909            let mut output = e.uninit(experts.input_width)?;
10910            e.add(
10911                &workspace.accumulator[0],
10912                &workspace.accumulator[1],
10913                &mut output,
10914                experts.input_width,
10915            )?;
10916            let output = output;
10917            if let Some(started) = started {
10918                use std::sync::atomic::Ordering;
10919                let ns = TIMING_NS
10920                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
10921                    + started.elapsed().as_nanos() as u64;
10922                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
10923                if calls % 430 == 0 {
10924                    eprintln!(
10925                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
10926                        ns as f64 / 1.0e6,
10927                        ns as f64 / calls as f64 / 1.0e3,
10928                    );
10929                }
10930            }
10931            return Ok(output);
10932        }
10933        {
10934            let root = &self.ranks[0];
10935            let _main = root.gpu.enter_main()?;
10936            for ev in workspace.ev_rank.iter().skip(1) {
10937                root.stream().wait(ev)?;
10938            }
10939            root.stream()
10940                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
10941            {
10942                let Nvfp4DeviceRoutesWorkspace {
10943                    accumulator,
10944                    remote,
10945                    combined,
10946                    ..
10947                } = &mut *workspace;
10948                root.add(&accumulator[0], remote, combined, experts.input_width)?;
10949            }
10950            workspace
10951                .ev_done
10952                .as_ref()
10953                .expect("device routes done event")
10954                .record(&root.stream())?;
10955        }
10956        let output = {
10957            let _main = e.gpu.enter_main()?;
10958            e.stream().wait(
10959                workspace
10960                    .ev_done
10961                    .as_ref()
10962                    .expect("device routes done event"),
10963            )?;
10964            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
10965            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
10966            let mut output = e.uninit(experts.input_width)?;
10967            e.stream().memcpy_dtod(
10968                &workspace.combined.slice(0..experts.input_width),
10969                &mut output.slice_mut(0..experts.input_width),
10970            )?;
10971            output
10972        };
10973        if let Some(started) = started {
10974            use std::sync::atomic::Ordering;
10975            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
10976                + started.elapsed().as_nanos() as u64;
10977            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
10978            if calls % 430 == 0 {
10979                eprintln!(
10980                    "[nvfp4-dev-routes-io-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
10981                    ns as f64 / 1.0e6,
10982                    ns as f64 / calls as f64 / 1.0e3,
10983                );
10984            }
10985        }
10986        Ok(output)
10987    }
10988
10989    /// Device-routed twin of `run_tensor_parallel_routes_nvfp4_device_io`: the selection and
10990    /// route weights arrive as the device router's e-context outputs — the per-layer host
10991    /// logits readback disappears. The fresh router outputs are staged into persistent
10992    /// e-context buffers on e's stream (never-free discipline) before the entry event; each
10993    /// rank peer-reads them behind it. The down-macro fold happens in-kernel.
10994    #[allow(clippy::too_many_arguments)]
10995    /// Prestage the routed-expert input: pull the shared row to every rank and quantize it
10996    /// there, WITHOUT the selection — callable before the router so the rank chains overlap
10997    /// it. No-op (returns false) when the workspace is not built yet or the door is off;
10998    /// the routed run then does its own staging as before.
10999    pub fn nvfp4_routes_prestage(
11000        &self,
11001        experts: &ResidentNvfp4TensorParallel,
11002        e: &Engine,
11003        input_dev: &crate::CudaSlice<f32>,
11004    ) -> Result<bool, Box<dyn std::error::Error>> {
11005        self.nvfp4_routes_prestage_with(experts, e, input_dev, |_, _, _, _| Ok(false))
11006    }
11007
11008    /// `nvfp4_routes_prestage` with a PEER-ROUTER hook: after rank1's input pull +
11009    /// quantize, the hook may compute rank1's route selection LOCALLY (replicated router —
11010    /// deterministic kernels on identical input bits produce identical sel/w, so the
11011    /// selection is bit-equal to the root's). Returns true when it wrote sel/route_w; the
11012    /// routed run then skips rank1's sel pull.
11013    pub fn nvfp4_routes_prestage_with(
11014        &self,
11015        experts: &ResidentNvfp4TensorParallel,
11016        e: &Engine,
11017        input_dev: &crate::CudaSlice<f32>,
11018        rank1_router: impl FnOnce(
11019            &Engine,
11020            &crate::CudaSlice<f32>,
11021            &mut crate::CudaSlice<i32>,
11022            &mut crate::CudaSlice<f32>,
11023        ) -> Result<bool, Box<dyn std::error::Error>>,
11024    ) -> Result<bool, Box<dyn std::error::Error>> {
11025        if !routes_prestage_on() || step_tp_graph_enabled()? {
11026            return Ok(false);
11027        }
11028        if input_dev.len() != experts.input_width {
11029            return Err("NVFP4 prestage input width mismatch".into());
11030        }
11031        let mut workspace_guard = experts
11032            .device_workspace
11033            .lock()
11034            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
11035        let Some(workspace) = workspace_guard.as_mut() else {
11036            return Ok(false);
11037        };
11038        if workspace.ev_input.is_none() {
11039            let _main = e.gpu.enter_main()?;
11040            workspace.ev_input = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
11041        } else if workspace.ev_input.as_ref().map(|(_, d)| *d) != Some(e.ctx().ordinal()) {
11042            return Err("NVFP4 prestage engine changed".into());
11043        }
11044        {
11045            let _main = e.gpu.enter_main()?;
11046            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
11047            ev.record(&e.stream())?;
11048        }
11049        for (rank_index, engine) in self.ranks.iter().enumerate() {
11050            let _main = engine.gpu.enter_main()?;
11051            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
11052            engine.stream().wait(ev)?;
11053            {
11054                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
11055                engine
11056                    .stream()
11057                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
11058            }
11059            {
11060                let Nvfp4DeviceRoutesWorkspace {
11061                    input, in_q, in_d, ..
11062                } = &mut *workspace;
11063                engine.quantize_q8_1_into(
11064                    &input[rank_index],
11065                    1,
11066                    experts.input_width,
11067                    &mut in_q[rank_index],
11068                    &mut in_d[rank_index],
11069                )?;
11070            }
11071        }
11072        if self.ranks.len() == 2 {
11073            let rank1 = &self.ranks[1];
11074            let _r1 = rank1.gpu.enter_main()?;
11075            let Nvfp4DeviceRoutesWorkspace {
11076                input,
11077                sel,
11078                route_w,
11079                ..
11080            } = &mut *workspace;
11081            let (in1, rest_sel) = (&input[1], &mut sel[1]);
11082            if rank1_router(rank1, in1, rest_sel, &mut route_w[1])? {
11083                workspace.rank1_routed = true;
11084            }
11085        }
11086        workspace.prestaged = true;
11087        Ok(true)
11088    }
11089
11090    /// STEP TP2 GEMM PRIME (`MEMRA_STEP_GEMM_PRIME`, 2026-08-27, TTFT lane): one grouped
11091    /// f16 GEMM per projection over the RESIDENT NVFP4 banks for a prime chunk of `t` tokens.
11092    ///
11093    /// WHY: the t-row walk primes a 4,092-token prompt in 19.8 s at its widest (GEMV-bound) and
11094    /// the generic batch prime's decode-class MoE takes 240 s; the CUTLASS sizing rows put
11095    /// GEMM-class expert math at 170-270 TFLOP/s on this silicon, i.e. a sub-second cold prime.
11096    /// This reuses the grouped f16 lane end to end (`moe_f16g_act` -> `moe_f16_grouped`
11097    /// direct-from-NVFP4 -> silu pairs -> grouped down) once per RANK against that rank's bank
11098    /// half: gate/up are column-halves (silu runs on matching halves), down is the canonical
11099    /// row-shard pair producing partials joined in the pinned shard order, and the final
11100    /// weighted scatter runs a fixed slot-0..n_used-1 sum per token - no atomics anywhere.
11101    /// Per-expert NVFP4 macro scales land where they must: gate/up BEFORE silu (nonlinear),
11102    /// down folded into the scatter weight.
11103    ///
11104    /// NUMERIC CLASS: the f16-mirror grouped-prefill class other families already serve -
11105    /// admission is the prefill-KV acceptance gate plus the ship-shape tape, not byte identity.
11106    #[allow(clippy::too_many_arguments)]
11107    /// MEMRA_MOE_DETERM_STAGE=1: checksum a stage's device buffer so two back-to-back calls of the
11108    /// grouped routine can be compared STAGE BY STAGE. The routine's OUTPUT is nondeterministic above
11109    /// ~400 tokens on the direct lane (1.9e-7 / 99% of elements at t=4096) while its GEMM kernels are
11110    /// bit-exact in isolation, so the divergence enters somewhere between. The first stage whose
11111    /// checksum differs across the two calls is where.
11112    ///
11113    /// Sum-of-bits, not sum-of-floats: float addition would itself reorder and could mask exactly the
11114    /// class of difference being hunted.
11115    fn determ_stage_bytes(v: &[u8]) -> u64 {
11116        v.iter().fold(0u64, |a, b| {
11117            a.wrapping_mul(1_000_003).wrapping_add(*b as u64)
11118        })
11119    }
11120
11121    /// Checksum an i32 index/offset buffer. The CSR, the active-expert ids and the group
11122    /// offsets are inputs the gate kernel dereferences just as much as the activations are;
11123    /// leaving them unchecksummed is what let "identical inputs, different output" stand on a
11124    /// SUBSET of the inputs for six rounds of this investigation.
11125    fn determ_stage_i32(v: &[i32]) -> u64 {
11126        v.iter().fold(0u64, |a, b| {
11127            a.wrapping_mul(1_000_003).wrapping_add(*b as u32 as u64)
11128        })
11129    }
11130
11131    fn determ_stage_sum(v: &[f32]) -> u64 {
11132        v.iter().fold(0u64, |a, x| {
11133            a.wrapping_mul(1_000_003).wrapping_add(x.to_bits() as u64)
11134        })
11135    }
11136
11137    pub fn run_tensor_parallel_routes_nvfp4_prime_grouped(
11138        &self,
11139        experts: &ResidentNvfp4TensorParallel,
11140        e: &Engine,
11141        z_t: &crate::CudaSlice<f32>,
11142        t: usize,
11143        sel: &[i32],
11144        w: &[f32],
11145        n_used: usize,
11146        activation_limit: Option<f32>,
11147    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11148        let world = self.ranks.len();
11149        if world != NVFP4_CANONICAL_ROW_SHARDS {
11150            return Err("NVFP4 grouped prime requires the canonical 2-shard grid".into());
11151        }
11152        // The dequant must read the layout the bank was BUILT in (feeding slot-major bytes
11153        // to the v1 kernel was a garbage-output bug this line exists for). The layout is a
11154        // property of the bank now, never of the environment: EP2 banks are always
11155        // slot-major, TP shard banks always block_nvfp4 v1 (nvfp4_repack_bank_matrix).
11156        let bank_qt = if experts.ep2 {
11157            crate::QT_NVFP4_V2
11158        } else {
11159            crate::QT_NVFP4
11160        };
11161        let width = experts.input_width;
11162        let n_expert = experts.expert_count;
11163        let n_pairs = t * n_used;
11164        if sel.len() < n_pairs || w.len() < n_pairs || z_t.len() < t * width {
11165            return Err("NVFP4 grouped prime geometry".into());
11166        }
11167        // MEMRA_PRIME_PROF=1 sub-split of the grouped prime (2026-08-28). The [moe-prof] mark
11168        // around this whole call reads 90% of the MoE bucket, but the call is not just GEMMs:
11169        // it host-builds the CSR, allocates ~6 large device buffers per rank per layer (z_r is
11170        // 67 MB, act is 84 MB at t=4096), and does 5 H2D copies per rank. Tile form, occupancy,
11171        // padding, B double-buffering and register pressure have ALL come back null, which is
11172        // the signature of time that is not in the kernel. So measure HOST wall with no syncs
11173        // for the build and the issue, and let the join wait absorb the GPU time: host-bound and
11174        // GPU-bound then read differently instead of summing into one opaque number.
11175        let gprof = std::env::var("MEMRA_PRIME_PROF").as_deref() == Ok("1") && t >= 16;
11176        let g_t0 = std::time::Instant::now();
11177        // CSR: expert-major pair lists. Host-built - prime is chunk-granular, and the router
11178        // selections arrive host-side from the sigmoid router oracle.
11179        let mut buckets: Vec<Vec<i32>> = vec![Vec::new(); n_expert];
11180        for (p, &s_id) in sel.iter().take(n_pairs).enumerate() {
11181            let s_id = s_id as usize;
11182            if s_id >= n_expert {
11183                return Err(format!("grouped prime selection {s_id} >= {n_expert}").into());
11184            }
11185            buckets[s_id].push(p as i32);
11186        }
11187        let mut ex_ids: Vec<i32> = Vec::new();
11188        let mut ex_off: Vec<i32> = vec![0];
11189        let mut ex_pairs: Vec<i32> = Vec::new();
11190        for (e_id, b) in buckets.iter().enumerate() {
11191            if !b.is_empty() {
11192                ex_ids.push(e_id as i32);
11193                ex_pairs.extend_from_slice(b);
11194                ex_off.push(ex_pairs.len() as i32);
11195            }
11196        }
11197        let n_active = ex_ids.len();
11198        if n_active == 0 {
11199            return Ok(e.zeros(t * width)?);
11200        }
11201        if n_active > 512 {
11202            return Err("grouped prime n_active > 512 (direct lane cap)".into());
11203        }
11204        let csr_tok: Vec<i32> = ex_pairs.iter().map(|&p| p / n_used as i32).collect();
11205        // pair-id -> CSR row: lets the fused tail read the partials in place, so the prime skips
11206        // a whole [n_pairs, width] permute (532 MB read + write per rank per layer at 4k).
11207        let mut inv = vec![0i32; n_pairs];
11208        for (row, &pair) in ex_pairs.iter().enumerate() {
11209            inv[pair as usize] = row as i32;
11210        }
11211        // Per-CSR-row gate/up macro scales (before silu); down macro folds into the scatter w.
11212        let mg: Vec<f32> = ex_pairs
11213            .iter()
11214            .map(|&p| experts.macros_gate[sel[p as usize] as usize])
11215            .collect();
11216        let mu: Vec<f32> = ex_pairs
11217            .iter()
11218            .map(|&p| experts.macros_up[sel[p as usize] as usize])
11219            .collect();
11220        let wd: Vec<f32> = (0..n_pairs)
11221            .map(|p| w[p] * experts.macros_down[sel[p] as usize])
11222            .collect();
11223        // Pointer tables: built on first use and kept on the bank. Resident banks never move,
11224        // so the old per-rank-per-LAYER rebuild+upload of 3*n_expert u64s was pure prime-path
11225        // host churn (45 layers x 2 ranks x 864 entries per prime).
11226        {
11227            let mut tabs = experts
11228                .prime_tables
11229                .lock()
11230                .map_err(|_| "grouped prime table cache is poisoned")?;
11231            if tabs.len() != world {
11232                tabs.clear();
11233                for rank in 0..world {
11234                    let engine = &self.ranks[rank];
11235                    let _main = engine.gpu.enter_main()?;
11236                    let (gb, ub, db) =
11237                        (&experts.gate[rank], &experts.up[rank], &experts.down[rank]);
11238                    let mut tab = vec![0u64; 3 * n_expert];
11239                    {
11240                        use cudarc::driver::DevicePtr;
11241                        let stream = engine.stream();
11242                        let (pg, _g0) = gb.bank.device_ptr(&stream);
11243                        let (pu, _g1) = ub.bank.device_ptr(&stream);
11244                        let (pd, _g2) = db.bank.device_ptr(&stream);
11245                        for ex in 0..n_expert {
11246                            tab[ex] = pg as u64 + (ex * gb.expert_bytes) as u64;
11247                            tab[n_expert + ex] = pu as u64 + (ex * ub.expert_bytes) as u64;
11248                            tab[2 * n_expert + ex] = pd as u64 + (ex * db.expert_bytes) as u64;
11249                        }
11250                    }
11251                    tabs.push(engine.htod_u64(&tab)?);
11252                }
11253            }
11254        }
11255        let g_csr = g_t0.elapsed().as_secs_f64() * 1e3;
11256        let g_t1 = std::time::Instant::now();
11257        // WHAT ARE THESE RANKS, ACTUALLY (2026-08-28)? The grouped MoE measures join ~ span_sum
11258        // (strictly serialized) at t=4096 while the same kernel hits 40 TFLOP/s standalone, and
11259        // one intervention based on cudarc's peer-copy event was refuted. Before proposing an
11260        // eleventh mechanism, verify the premise the whole question rests on: that the two ranks
11261        // are on DISTINCT devices, contexts and streams. If they share any of those, the
11262        // serialization needs no further explanation. One line per process.
11263        {
11264            static SAID: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
11265            if gprof && !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
11266                for rank in 0..world {
11267                    let e_r = &self.ranks[rank];
11268                    let _m = e_r.gpu.enter_main();
11269                    eprintln!(
11270                        "[rank-id] rank={rank} ordinal={} ctx={:?} stream={:?} root_ordinal={} \
11271                         root_stream={:?}",
11272                        e_r.ctx().ordinal(),
11273                        std::sync::Arc::as_ptr(&e_r.ctx()),
11274                        e_r.stream().cu_stream(),
11275                        e.ctx().ordinal(),
11276                        e.stream().cu_stream(),
11277                    );
11278                }
11279            }
11280        }
11281
11282        let mut partials: Vec<crate::CudaSlice<f32>> = Vec::with_capacity(world);
11283        let mut ev_rank: Vec<CudaEvent> = Vec::with_capacity(world);
11284        let mut ev_head: Vec<CudaEvent> = Vec::with_capacity(world);
11285        let mut ev_tail_prof: Vec<CudaEvent> = Vec::with_capacity(world);
11286        for rank in 0..world {
11287            let engine = &self.ranks[rank];
11288            let _main = engine.gpu.enter_main()?;
11289            if gprof {
11290                // CU_EVENT_DEFAULT, not None: cudarc's new_event(None) creates the event with
11291                // CU_EVENT_DISABLE_TIMING, and cuEventElapsedTime then returns INVALID_HANDLE.
11292                // That is what failed every span query for two build cycles — the ordering
11293                // events below correctly keep the default, since they are never timed.
11294                let h = engine
11295                    .ctx()
11296                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
11297                h.record(&engine.stream())?;
11298                ev_head.push(h);
11299            }
11300            // The grouped-MoE FFI's raw launches follow the RUNTIME API's current device, not
11301            // the pushed driver context — bind it per rank or rank-1 calls die InvalidValue.
11302            engine.bind_runtime_device(engine.ctx().ordinal() as i32)?;
11303            let gb = &experts.gate[rank];
11304            let ub = &experts.up[rank];
11305            let db = &experts.down[rank];
11306            if db.device_rank != rank {
11307                return Err("grouped prime: down shard placement drifted".into());
11308            }
11309            let local_ff = gb.local_out;
11310            if ub.local_out != local_ff || db.local_in != local_ff || db.out_features != width {
11311                return Err("grouped prime: bank width mismatch".into());
11312            }
11313            // All of the rank's host-side staging lands before its first kernel, so the
11314            // launch chain below issues without host copies interleaved.
11315            let csr_tok_d = engine.htod_i32(&csr_tok)?;
11316            let exi_d = engine.htod_i32(&ex_ids)?;
11317            let exoff_d = engine.htod_i32(&ex_off)?;
11318            let mg_d = engine.htod(&mg)?;
11319            let mu_d = engine.htod(&mu)?;
11320            // Per-rank pointer table into the bank shards, slot-major like DevExps::ptr_row.
11321            let tabs_guard = experts
11322                .prime_tables
11323                .lock()
11324                .map_err(|_| "grouped prime table cache is poisoned")?;
11325            let tab_d = &tabs_guard[rank];
11326            let mut z_r = engine.uninit(t * width)?;
11327            {
11328                let mut dst = z_r.slice_mut(0..t * width);
11329                engine
11330                    .stream()
11331                    .memcpy_dtod(&z_t.slice(0..t * width), &mut dst)?;
11332            }
11333            let dstage = std::env::var("MEMRA_MOE_DETERM_STAGE").as_deref() == Ok("1") && t >= 16;
11334            let (z16, zs) = engine.moe_f16g_act(&z_r, Some(&csr_tok_d), width, n_pairs)?;
11335            if dstage {
11336                // z16 is the GEMM's actual DATA input and is a byte buffer; checksumming only
11337                // z_r and zs left "identical inputs" unestablished and produced a localization
11338                // that outran the measurement. Checksum it as bytes.
11339                let zr = engine.dtoh(&z_r)?;
11340                let zsv = engine.dtoh(&zs)?;
11341                let z16v = engine.dtoh_u8(&z16)?;
11342                eprintln!(
11343                    "[determ-stage] rank={rank} t={t} z_r={:016x} zs={:016x} z16={:016x}",
11344                    Self::determ_stage_sum(&zr),
11345                    Self::determ_stage_sum(&zsv),
11346                    Self::determ_stage_bytes(&z16v)
11347                );
11348            }
11349            if dstage {
11350                // INPUT CLOSURE. Everything the gate kernel dereferences, plus the launch
11351                // geometry that decides how it is summed, checksummed in ONE place. A kernel
11352                // proven bit-deterministic on live data, with no atomics, can only diverge if
11353                // (A) some byte it reads differs, (B) the launch differs, or (C) it reads
11354                // outside its declared inputs. This closes A and B; C is what compute-sanitizer
11355                // is for. Partial input sets are how the divergence kept retreating into the
11356                // part that was never measured.
11357                engine.stream().synchronize()?;
11358                let csr_v = engine.dtoh_i32(&csr_tok_d)?;
11359                let exi_v = engine.dtoh_i32(&exi_d)?;
11360                let exo_v = engine.dtoh_i32(&exoff_d)?;
11361                let mg_v = engine.dtoh(&mg_d)?;
11362                let mu_v = engine.dtoh(&mu_d)?;
11363                let tab_v = engine.dtoh_u64(tab_d)?;
11364                eprintln!(
11365                    "[determ-closure] rank={rank} t={t} csr_tok={:016x} exi={:016x} exoff={:016x}                      ex_off_host={:016x} mg={:016x} mu={:016x} tab={:016x} | n_active={n_active}                      n_pairs={n_pairs} width={width} local_ff={local_ff} n_expert={n_expert}                      qt={bank_qt} rb={}",
11366                    Self::determ_stage_i32(&csr_v),
11367                    Self::determ_stage_i32(&exi_v),
11368                    Self::determ_stage_i32(&exo_v),
11369                    Self::determ_stage_i32(&ex_off),
11370                    Self::determ_stage_sum(&mg_v),
11371                    Self::determ_stage_sum(&mu_v),
11372                    tab_v
11373                        .iter()
11374                        .fold(0u64, |a, b| a.wrapping_mul(1_000_003).wrapping_add(*b)),
11375                    gb.row_bytes
11376                );
11377                // The resident weight bank is the GEMM's OTHER operand and was never checked.
11378                // Opt-in because it is a ~424 MB dtoh per rank per layer.
11379                if std::env::var("MEMRA_MOE_DETERM_BANK").as_deref() == Ok("1") {
11380                    let bank_v = engine.dtoh_u8(&gb.bank)?;
11381                    eprintln!(
11382                        "[determ-closure] rank={rank} t={t} gate_bank={:016x} bytes={}",
11383                        Self::determ_stage_bytes(&bank_v),
11384                        bank_v.len()
11385                    );
11386                }
11387            }
11388            let mut g = engine.moe_f16_grouped(
11389                tab_d,
11390                0,
11391                n_expert,
11392                &exi_d,
11393                &ex_off,
11394                &exoff_d,
11395                &z16,
11396                &zs,
11397                width,
11398                local_ff,
11399                n_active,
11400                n_pairs,
11401                bank_qt,
11402                gb.row_bytes,
11403            )?;
11404            engine.scale_rows(&mut g, &mg_d, local_ff, n_pairs)?;
11405            let mut u = engine.moe_f16_grouped(
11406                tab_d,
11407                1,
11408                n_expert,
11409                &exi_d,
11410                &ex_off,
11411                &exoff_d,
11412                &z16,
11413                &zs,
11414                width,
11415                local_ff,
11416                n_active,
11417                n_pairs,
11418                bank_qt,
11419                ub.row_bytes,
11420            )?;
11421            engine.scale_rows(&mut u, &mu_d, local_ff, n_pairs)?;
11422            // step35 routed SwiGLU clamp (per-layer; live only on layers 43/44 for this
11423            // family): min(silu(g), lim) * clamp(u, +-lim). Dropping it was the second
11424            // correctness bug of the first engaged run.
11425            let act = match activation_limit.filter(|l| *l > 1e-6) {
11426                Some(lim) => {
11427                    let mut a = engine.uninit(n_pairs * local_ff)?;
11428                    engine.swiglu_clamped_mul_scaled(
11429                        &g,
11430                        &u,
11431                        1.0,
11432                        1.0,
11433                        lim,
11434                        &mut a,
11435                        n_pairs * local_ff,
11436                    )?;
11437                    a
11438                }
11439                None => engine.moe_pairs_silu_mul(&g, &u, n_pairs * local_ff)?,
11440            };
11441            if dstage {
11442                let gv = engine.dtoh(&g)?;
11443                let uv = engine.dtoh(&u)?;
11444                let av = engine.dtoh(&act)?;
11445                // A SUM tells you THAT gate differs; it does not tell you HOW. ULP-dense diffs
11446                // (nearly every element, ~1e-8) are an ordering/precision class; a handful of
11447                // huge ones are a corruption class. They need different hunts, so measure the
11448                // shape here instead of inferring it later.
11449                let key = (rank, t);
11450                let mut prev_map = DETERM_PREV
11451                    .get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()))
11452                    .lock()
11453                    .map_err(|_| "determ prev map poisoned")?;
11454                let shape = match prev_map.get(&key) {
11455                    Some(prev) if prev.len() == gv.len() => {
11456                        let mut md = 0.0f32;
11457                        let mut n_diff = 0usize;
11458                        let mut n_big = 0usize;
11459                        for (a, b) in prev.iter().zip(gv.iter()) {
11460                            let d = (a - b).abs();
11461                            if d > 0.0 {
11462                                n_diff += 1;
11463                            }
11464                            if d > 1e-3 {
11465                                n_big += 1;
11466                            }
11467                            if d > md {
11468                                md = d;
11469                            }
11470                        }
11471                        format!(
11472                            " | vs_prev maxdiff={md:.3e} differing={n_diff}/{} big(>1e-3)={n_big}",
11473                            gv.len()
11474                        )
11475                    }
11476                    _ => String::new(),
11477                };
11478                prev_map.insert(key, gv.clone());
11479                drop(prev_map);
11480                eprintln!(
11481                    "[determ-stage] rank={rank} t={t} gate={:016x} up={:016x} silu={:016x}{shape}",
11482                    Self::determ_stage_sum(&gv),
11483                    Self::determ_stage_sum(&uv),
11484                    Self::determ_stage_sum(&av)
11485                );
11486            }
11487            let (a16, a_s) = engine.moe_f16g_act(&act, None, local_ff, n_pairs)?;
11488            let d_csr = engine.moe_f16_grouped(
11489                tab_d,
11490                2,
11491                n_expert,
11492                &exi_d,
11493                &ex_off,
11494                &exoff_d,
11495                &a16,
11496                &a_s,
11497                local_ff,
11498                width,
11499                n_active,
11500                n_pairs,
11501                bank_qt,
11502                db.row_bytes,
11503            )?;
11504
11505            // No host sync: both ranks' chains must be in flight before anything waits.
11506            // The rank's tail event orders the root's cross-device pulls below.
11507            if dstage {
11508                engine.stream().synchronize()?;
11509                let a16v = engine.dtoh_u8(&a16)?;
11510                let dv = engine.dtoh(&d_csr)?;
11511                eprintln!(
11512                    "[determ-stage] rank={rank} t={t} a16={:016x} down_partial={:016x}",
11513                    Self::determ_stage_bytes(&a16v),
11514                    Self::determ_stage_sum(&dv)
11515                );
11516            }
11517            let ev = engine.ctx().new_event(None)?;
11518            ev.record(&engine.stream())?;
11519            if gprof {
11520                // Per-rank GPU SPAN (2026-08-28). Keep the tail event; the elapsed time is read
11521                // AFTER the join sync below. Reading it here returns NOT_READY (the work has only
11522                // been queued) and cudarc's elapsed_ms synchronizes, which serialized the very
11523                // ranks this is meant to test: host issue jumped 1.9 ms -> 34-47 ms per call and
11524                // the join wall fell to match. A probe that changes the schedule measures its own
11525                // perturbation.
11526                // CudaEvent is not Clone, so record a second tail event on the same stream —
11527                // adjacent to `ev`, so it carries the same completion timestamp for timing.
11528                let tp = engine
11529                    .ctx()
11530                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
11531                tp.record(&engine.stream())?;
11532                ev_tail_prof.push(tp);
11533            }
11534            ev_rank.push(ev);
11535            partials.push(d_csr);
11536        }
11537        let _main = e.gpu.enter_main()?;
11538        e.bind_runtime_device(e.ctx().ordinal() as i32)?;
11539        // Host-only: every rank's chain is queued, nothing has been waited on yet.
11540        let g_issue = g_t1.elapsed().as_secs_f64() * 1e3;
11541        let g_t2 = std::time::Instant::now();
11542        for ev in &ev_rank {
11543            e.stream().wait(ev)?;
11544        }
11545        // Both partials land on the root (rank 1's crosses the link once), then ONE fused pass
11546        // does join + CSR permute + weight + scatter. Shard order stays pinned as (y0 + y1).
11547        let mut y0 = e.uninit(n_pairs * width)?;
11548        {
11549            let mut dst = y0.slice_mut(0..n_pairs * width);
11550            e.stream()
11551                .memcpy_dtod(&partials[0].slice(0..n_pairs * width), &mut dst)?;
11552        }
11553        let mut y1 = e.uninit(n_pairs * width)?;
11554        {
11555            let mut dst = y1.slice_mut(0..n_pairs * width);
11556            e.stream()
11557                .memcpy_dtod(&partials[1].slice(0..n_pairs * width), &mut dst)?;
11558        }
11559        let inv_d = e.htod_i32(&inv)?;
11560        let wd_d = e.htod(&wd)?;
11561        let mut out = e.uninit(t * width)?;
11562        e.moe_prime_join_scatter(&y0, &y1, &inv_d, &wd_d, &mut out, width, n_used, t)?;
11563        if gprof {
11564            let _ = e.stream().synchronize();
11565            let g_join = g_t2.elapsed().as_secs_f64() * 1e3;
11566            // Everything has completed, so both events of every pair are ready and elapsed_ms
11567            // cannot block. A negative entry means the query itself failed and the row must be
11568            // read as missing data, never as a zero-length span.
11569            // cuEventElapsedTime needs the events' OWN context current — computing it under the
11570            // root's pushed context returned an error for every pair, and the first version
11571            // swallowed that into -1.0 with no reason attached. Enter each rank's context, and
11572            // print the failure once so a dead probe can never again look like a zero-length span.
11573            let mut span_ms: Vec<f32> = Vec::with_capacity(world);
11574            for (rank, (h, tp)) in ev_head.iter().zip(ev_tail_prof.iter()).enumerate() {
11575                let guard = self.ranks[rank].gpu.enter_main();
11576                match guard.and_then(|_g| h.elapsed_ms(tp).map_err(|e| e.into())) {
11577                    Ok(v) => span_ms.push(v),
11578                    Err(err) => {
11579                        static SAID: std::sync::atomic::AtomicBool =
11580                            std::sync::atomic::AtomicBool::new(false);
11581                        if !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
11582                            eprintln!("[grp-prof] span query failed on rank {rank}: {err}");
11583                        }
11584                        span_ms.push(-1.0);
11585                    }
11586                }
11587            }
11588            eprintln!(
11589                "[grp-prof] t={t} n_active={n_active} csr={g_csr:.1}ms issue={g_issue:.1}ms \
11590                 join={g_join:.1}ms spans={span_ms:?} span_sum={:.1}ms span_max={:.1}ms",
11591                span_ms.iter().sum::<f32>(),
11592                span_ms.iter().cloned().fold(0.0f32, f32::max)
11593            );
11594        }
11595        Ok(out)
11596    }
11597
11598    pub fn run_tensor_parallel_routes_nvfp4_device_routed(
11599        &self,
11600        experts: &ResidentNvfp4TensorParallel,
11601        e: &Engine,
11602        input_dev: &crate::CudaSlice<f32>,
11603        sel_d: &crate::CudaSlice<i32>,
11604        w_d: &crate::CudaSlice<f32>,
11605        experts_per_token: usize,
11606        activation_limit: Option<f32>,
11607    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11608        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
11609            experts,
11610            e,
11611            input_dev,
11612            sel_d,
11613            w_d,
11614            experts_per_token,
11615            activation_limit,
11616            || Ok(()),
11617        )
11618    }
11619
11620    /// `run_tensor_parallel_routes_nvfp4_device_routed` with a PREJOIN hook: `pre_join`
11621    /// runs on the host right before the join wait is enqueued on e's stream — work it
11622    /// issues there (e.g. the shexp overlap) executes WHILE the peer rank finishes its
11623    /// sweep, instead of after the join. Value-neutral by construction (the hook only
11624    /// reorders independent host issue).
11625    #[allow(clippy::too_many_arguments)]
11626    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
11627        &self,
11628        experts: &ResidentNvfp4TensorParallel,
11629        e: &Engine,
11630        input_dev: &crate::CudaSlice<f32>,
11631        sel_d: &crate::CudaSlice<i32>,
11632        w_d: &crate::CudaSlice<f32>,
11633        experts_per_token: usize,
11634        activation_limit: Option<f32>,
11635        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
11636    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11637        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
11638            experts,
11639            e,
11640            input_dev,
11641            sel_d,
11642            w_d,
11643            experts_per_token,
11644            activation_limit,
11645            pre_join,
11646            None,
11647        )
11648    }
11649
11650    /// The prejoin variant with MOE TAIL FUSION M1: when `post_add = Some((sh_raw,
11651    /// scale_raw))`, the direct-join arm folds the shexp apply into the join add
11652    /// (`dst = (acc0+acc1) + sh*scale[0]`, exact split-pair sequence) — the caller skips
11653    /// its apply launch. Raw UVA pointers so no lock is held across the call.
11654    #[allow(clippy::too_many_arguments)]
11655    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
11656        &self,
11657        experts: &ResidentNvfp4TensorParallel,
11658        e: &Engine,
11659        input_dev: &crate::CudaSlice<f32>,
11660        sel_d: &crate::CudaSlice<i32>,
11661        w_d: &crate::CudaSlice<f32>,
11662        experts_per_token: usize,
11663        activation_limit: Option<f32>,
11664        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
11665        post_add: Option<(u64, u64)>,
11666    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11667        if input_dev.len() != experts.input_width {
11668            return Err(format!(
11669                "NVFP4 device-routed input {} != width {}",
11670                input_dev.len(),
11671                experts.input_width
11672            )
11673            .into());
11674        }
11675        let n_sel = experts_per_token;
11676        if sel_d.len() < n_sel || w_d.len() < n_sel {
11677            return Err(format!(
11678                "NVFP4 device-routed routes sel={} w={} < experts/token {n_sel}",
11679                sel_d.len(),
11680                w_d.len()
11681            )
11682            .into());
11683        }
11684        let world = self.ranks.len();
11685        if world != NVFP4_CANONICAL_ROW_SHARDS {
11686            return Err(format!(
11687                "NVFP4 device routes require world == canonical shard grid \
11688                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
11689            )
11690            .into());
11691        }
11692        let local_out = if experts.ep2 {
11693            experts.expert_width
11694        } else {
11695            experts.expert_width / world
11696        };
11697
11698        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11699        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11700        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11701        let started = timing.then(std::time::Instant::now);
11702
11703        let mut workspace_guard = experts
11704            .device_workspace
11705            .lock()
11706            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
11707        if workspace_guard.is_none() {
11708            drop(workspace_guard);
11709            let zero = vec![0.0f32; experts.input_width];
11710            let zero_sel = vec![0usize; n_sel];
11711            let zero_w = vec![0.0f32; n_sel];
11712            let _ = self.run_tensor_parallel_routes_nvfp4_device(
11713                experts,
11714                &zero,
11715                &zero_sel,
11716                &zero_w,
11717                n_sel,
11718                activation_limit,
11719            )?;
11720            workspace_guard = experts
11721                .device_workspace
11722                .lock()
11723                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
11724        }
11725        let workspace = workspace_guard
11726            .as_mut()
11727            .expect("NVFP4 device routes workspace initialized above");
11728        if workspace.n_sel != n_sel {
11729            return Err(format!(
11730                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
11731                workspace.n_sel
11732            )
11733            .into());
11734        }
11735
11736        // GRAPH DOOR (MEMRA_STEP_TP_GRAPH=1): the whole rank+root segment replays as one
11737        // stitched multi-device parent launched on e's stream — no events, no per-token node
11738        // updates (every address is persistent staging). VALUE-IDENTICAL to the eager path:
11739        // the children replay exactly the same kernel/copy sequence.
11740        if step_tp_graph_enabled()? {
11741            if experts.ep2 {
11742                return Err(
11743                    "MEMRA_STEP_TP_GRAPH=1 with MEMRA_STEP_NVFP4_EP2=1 has never been \
11744                     co-gated; unset one"
11745                        .into(),
11746                );
11747            }
11748            if workspace.dev_route_e.is_none() {
11749                let _main = e.gpu.enter_main()?;
11750                workspace.dev_route_e = Some((
11751                    e.htod_i32(&vec![0i32; n_sel])?,
11752                    e.htod(&vec![0.0f32; n_sel])?,
11753                ));
11754            }
11755            if workspace.in_stage_e.is_none() {
11756                let _main = e.gpu.enter_main()?;
11757                workspace.in_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
11758                workspace.out_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
11759            }
11760            if workspace.routes_graph.is_none() {
11761                let graph = self.nvfp4_routes_build_graph(
11762                    experts,
11763                    workspace,
11764                    local_out,
11765                    n_sel,
11766                    activation_limit,
11767                )?;
11768                workspace.routes_graph = Some(graph);
11769                eprintln!(
11770                    "[step-tp-graph] routes segment captured: ranks={world} n_sel={n_sel} \
11771                     children=3 updates=none performance_claim=false"
11772                );
11773            }
11774            let output = {
11775                let _main = e.gpu.enter_main()?;
11776                {
11777                    let (sel_e, w_e) = workspace
11778                        .dev_route_e
11779                        .as_mut()
11780                        .expect("device route staging set above");
11781                    {
11782                        let mut dst = sel_e.slice_mut(0..n_sel);
11783                        e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
11784                    }
11785                    {
11786                        let mut dst = w_e.slice_mut(0..n_sel);
11787                        e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
11788                    }
11789                }
11790                {
11791                    let in_stage = workspace
11792                        .in_stage_e
11793                        .as_mut()
11794                        .expect("graph staging set above");
11795                    let mut dst = in_stage.slice_mut(0..experts.input_width);
11796                    e.stream()
11797                        .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut dst)?;
11798                }
11799                unsafe {
11800                    let r = cudarc::driver::sys::cuGraphLaunch(
11801                        workspace
11802                            .routes_graph
11803                            .as_ref()
11804                            .expect("routes graph built above")
11805                            .exec,
11806                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
11807                    );
11808                    if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
11809                        return Err(format!("routes graph launch: {r:?}").into());
11810                    }
11811                }
11812                let mut output = e.uninit(experts.input_width)?;
11813                {
11814                    let out_stage = workspace
11815                        .out_stage_e
11816                        .as_ref()
11817                        .expect("graph staging set above");
11818                    e.stream().memcpy_dtod(
11819                        &out_stage.slice(0..experts.input_width),
11820                        &mut output.slice_mut(0..experts.input_width),
11821                    )?;
11822                }
11823                output
11824            };
11825            if let Some(started) = started {
11826                use std::sync::atomic::Ordering;
11827                let ns = TIMING_NS
11828                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
11829                    + started.elapsed().as_nanos() as u64;
11830                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11831                if calls % 430 == 0 {
11832                    eprintln!(
11833                        "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11834                        ns as f64 / 1.0e6,
11835                        ns as f64 / calls as f64 / 1.0e3,
11836                    );
11837                }
11838            }
11839            return Ok(output);
11840        }
11841
11842        // Entry fence + router-output staging, all on e's stream: the fresh sel/w slices are
11843        // copied into the persistent e-context pair, then the event is recorded — the caller's
11844        // sel_d/w_d can free on e's stream with no cross-stream reader.
11845        if let Some((_, device)) = workspace.ev_entry.as_ref() {
11846            if *device != e.ctx().ordinal() {
11847                return Err("NVFP4 device-routed routes engine changed".into());
11848            }
11849        } else {
11850            let _main = e.gpu.enter_main()?;
11851            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
11852        }
11853        if workspace.dev_route_e.is_none() {
11854            let _main = e.gpu.enter_main()?;
11855            workspace.dev_route_e = Some((
11856                e.htod_i32(&vec![0i32; n_sel])?,
11857                e.htod(&vec![0.0f32; n_sel])?,
11858            ));
11859        }
11860        // MEMRA_SEL_MIRROR: the staging pair exists so the rank streams read a persistent
11861        // e-context address. The caller's sel_d/w_d ARE persistent (the process-static
11862        // selection rows), so when every consuming rank shares e's device the ranks can read
11863        // them directly and this hop disappears. The graph door keeps the staging (its
11864        // captured copies read the fixed addresses).
11865        let mirror = sel_mirror_on() && !step_tp_graph_enabled()?;
11866        let e_device = e.ctx().ordinal();
11867        // rank1_routed is consumed (taken) below; peek it here for the staging decision.
11868        let rank1_routed_peek = workspace.rank1_routed;
11869        let stage_needed = !mirror
11870            || self.ranks.iter().enumerate().any(|(rank_index, engine)| {
11871                !(rank1_routed_peek && rank_index == 1) && engine.ctx().ordinal() != e_device
11872            });
11873        {
11874            let _main = e.gpu.enter_main()?;
11875            if stage_needed {
11876                let (sel_e, w_e) = workspace
11877                    .dev_route_e
11878                    .as_mut()
11879                    .expect("device route staging set above");
11880                {
11881                    let mut dst = sel_e.slice_mut(0..n_sel);
11882                    e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
11883                }
11884                {
11885                    let mut dst = w_e.slice_mut(0..n_sel);
11886                    e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
11887                }
11888            }
11889            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
11890            ev_entry.record(&e.stream())?;
11891        }
11892        // Prestage door: input pull + quantize were already issued on the rank streams
11893        // (before the router) — the rank stream order suffices, skip them here.
11894        let prestaged = std::mem::take(&mut workspace.prestaged);
11895        let rank1_routed = std::mem::take(&mut workspace.rank1_routed);
11896        for (rank_index, engine) in self.ranks.iter().enumerate() {
11897            let _main = engine.gpu.enter_main()?;
11898            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
11899            engine.stream().wait(ev_entry)?;
11900            if !prestaged {
11901                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
11902                engine
11903                    .stream()
11904                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
11905            }
11906            if !(rank1_routed && rank_index == 1) {
11907                // ONE mirror launch instead of two 32-byte copy-engine dispatches; source is
11908                // the caller's persistent rows when this rank shares e's device (UVA, ordered
11909                // by ev_entry), else the staged e-context pair.
11910                let same_dev = engine.ctx().ordinal() == e_device;
11911                if mirror {
11912                    // Split the workspace borrow so the source (the staged pair, when this
11913                    // rank is off-device) and the destination rows coexist.
11914                    let Nvfp4DeviceRoutesWorkspace {
11915                        sel,
11916                        route_w,
11917                        dev_route_e,
11918                        ..
11919                    } = &mut *workspace;
11920                    let (src_sel, src_w): (&crate::CudaSlice<i32>, &crate::CudaSlice<f32>) =
11921                        if same_dev {
11922                            (sel_d, w_d)
11923                        } else {
11924                            let (sel_e, w_e) = dev_route_e
11925                                .as_ref()
11926                                .expect("device route staging set above");
11927                            (sel_e, w_e)
11928                        };
11929                    engine.moe_sel_w_mirror(
11930                        src_sel,
11931                        src_w,
11932                        &mut sel[rank_index],
11933                        &mut route_w[rank_index],
11934                        n_sel,
11935                    )?;
11936                } else {
11937                    let (sel_e, w_e) = workspace
11938                        .dev_route_e
11939                        .as_ref()
11940                        .expect("device route staging set above");
11941                    {
11942                        let mut dst = workspace.sel[rank_index].slice_mut(0..n_sel);
11943                        engine
11944                            .stream()
11945                            .memcpy_dtod(&sel_e.slice(0..n_sel), &mut dst)?;
11946                    }
11947                    {
11948                        let mut dst = workspace.route_w[rank_index].slice_mut(0..n_sel);
11949                        engine
11950                            .stream()
11951                            .memcpy_dtod(&w_e.slice(0..n_sel), &mut dst)?;
11952                    }
11953                }
11954            }
11955            if !prestaged {
11956                let Nvfp4DeviceRoutesWorkspace {
11957                    input, in_q, in_d, ..
11958                } = &mut *workspace;
11959                engine.quantize_q8_1_into(
11960                    &input[rank_index],
11961                    1,
11962                    experts.input_width,
11963                    &mut in_q[rank_index],
11964                    &mut in_d[rank_index],
11965                )?;
11966            }
11967        }
11968        self.nvfp4_routes_batched_sweeps(
11969            experts,
11970            workspace,
11971            &[],
11972            &[],
11973            &[],
11974            local_out,
11975            n_sel,
11976            activation_limit,
11977            true,
11978        )?;
11979
11980        // rank0 == root: its own stream order already covers its sweep; only the PEER
11981        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
11982        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
11983            let _main = engine.gpu.enter_main()?;
11984            workspace.ev_rank[rank_index].record(&engine.stream())?;
11985        }
11986        // Doorbell fences (MEMRA_FENCE_MEMOPS=1): rank1 + root ring their flags; e waits
11987        // the tickets instead of the two events. Arm lazily; 0-len = unsupported.
11988        let memops = fence_memops_on() && moe_direct_on() && self.ranks.len() == 2;
11989        let mut ticket = 0u32;
11990        if memops {
11991            use cudarc::driver::sys;
11992            if workspace.fence_flags_raw == 0 {
11993                let root = &self.ranks[0];
11994                let _main = root.gpu.enter_main()?;
11995                let mut ptr: sys::CUdeviceptr = 0;
11996                let r = unsafe { sys::cuMemAlloc_v2(&mut ptr, 8) };
11997                if r != sys::CUresult::CUDA_SUCCESS {
11998                    return Err(format!("fence flag alloc: {r:?}").into());
11999                }
12000                let r = unsafe { sys::cuMemsetD8_v2(ptr, 0, 8) };
12001                if r != sys::CUresult::CUDA_SUCCESS {
12002                    return Err(format!("fence flag memset: {r:?}").into());
12003                }
12004                workspace.fence_flags_raw = ptr as u64;
12005            }
12006            workspace.fence_ticket = workspace.fence_ticket.wrapping_add(1).max(1);
12007            ticket = workspace.fence_ticket;
12008            let base = workspace.fence_flags_raw;
12009            // rank1's fence: a peer stream MEMOP is rejected over PCIe P2P
12010            // (CUDA_ERROR_INVALID_VALUE, receipted 2026-08-23), but a peer KERNEL STORE into
12011            // root memory is legal — the direct join already relies on it. Under
12012            // MEMRA_FENCE_RANK1 rank1 rings flag[0] that way and e waits it same-device,
12013            // replacing the cross-device event wait below.
12014            if fence_rank1_on() {
12015                let peer = &self.ranks[1];
12016                let _pmain = peer.gpu.enter_main()?;
12017                peer.ring_flag_raw(base, ticket)?;
12018            }
12019            {
12020                let root = &self.ranks[0];
12021                let _main = root.gpu.enter_main()?;
12022                let r = unsafe {
12023                    sys::cuStreamWriteValue32_v2(
12024                        root.stream().cu_stream() as sys::CUstream,
12025                        (base + 4) as sys::CUdeviceptr,
12026                        ticket,
12027                        0,
12028                    )
12029                };
12030                if r != sys::CUresult::CUDA_SUCCESS {
12031                    return Err(format!("fence write root: {r:?}").into());
12032                }
12033            }
12034        }
12035        // PREJOIN hook: rank work is fully issued (dev1 running); independent e-stream
12036        // kernels queued here execute while the peer rank drains its sweep.
12037        pre_join()?;
12038
12039        if moe_direct_on() && self.ranks.len() == 2 {
12040            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
12041            // rank0's is root-stream-ordered. One root event + rank1's own event order
12042            // the model engine's single add — same operand order as root's add
12043            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
12044            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
12045            // hazard class does not apply).
12046            let _main = e.gpu.enter_main()?;
12047            if memops {
12048                use cudarc::driver::sys;
12049                let base = workspace.fence_flags_raw;
12050                let r = unsafe {
12051                    sys::cuStreamWaitValue32_v2(
12052                        e.stream().cu_stream() as sys::CUstream,
12053                        (base + 4) as sys::CUdeviceptr,
12054                        ticket,
12055                        sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
12056                    )
12057                };
12058                if r != sys::CUresult::CUDA_SUCCESS {
12059                    return Err(format!("fence wait: {r:?}").into());
12060                }
12061                if fence_rank1_on() {
12062                    // Same-device wait on the flag rank1 rang over P2P.
12063                    let r = unsafe {
12064                        sys::cuStreamWaitValue32_v2(
12065                            e.stream().cu_stream() as sys::CUstream,
12066                            base as sys::CUdeviceptr,
12067                            ticket,
12068                            sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
12069                        )
12070                    };
12071                    if r != sys::CUresult::CUDA_SUCCESS {
12072                        return Err(format!("fence wait rank1: {r:?}").into());
12073                    }
12074                } else {
12075                    for ev in workspace.ev_rank.iter().skip(1) {
12076                        e.stream().wait(ev)?;
12077                    }
12078                }
12079            } else {
12080                {
12081                    let root = &self.ranks[0];
12082                    let _rmain = root.gpu.enter_main()?;
12083                    workspace
12084                        .ev_done
12085                        .as_ref()
12086                        .expect("device routes done event")
12087                        .record(&root.stream())?;
12088                }
12089                e.stream().wait(
12090                    workspace
12091                        .ev_done
12092                        .as_ref()
12093                        .expect("device routes done event"),
12094                )?;
12095                for ev in workspace.ev_rank.iter().skip(1) {
12096                    e.stream().wait(ev)?;
12097                }
12098            }
12099            let mut output = e.uninit(experts.input_width)?;
12100            if let Some((sh_raw, scale_raw)) = post_add {
12101                // MOE TAIL FUSION M1: fold the shexp apply into the join add —
12102                // dst = (acc0 + acc1) + sh*scale[0], the exact split-pair sequence.
12103                e.add3_raw(
12104                    &workspace.accumulator[0],
12105                    &workspace.accumulator[1],
12106                    sh_raw,
12107                    scale_raw,
12108                    &mut output,
12109                    experts.input_width,
12110                )?;
12111            } else {
12112                e.add(
12113                    &workspace.accumulator[0],
12114                    &workspace.accumulator[1],
12115                    &mut output,
12116                    experts.input_width,
12117                )?;
12118            }
12119            let output = output;
12120            if let Some(started) = started {
12121                use std::sync::atomic::Ordering;
12122                let ns = TIMING_NS
12123                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
12124                    + started.elapsed().as_nanos() as u64;
12125                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12126                if calls % 430 == 0 {
12127                    eprintln!(
12128                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12129                        ns as f64 / 1.0e6,
12130                        ns as f64 / calls as f64 / 1.0e3,
12131                    );
12132                }
12133            }
12134            return Ok(output);
12135        }
12136        {
12137            let root = &self.ranks[0];
12138            let _main = root.gpu.enter_main()?;
12139            for ev in workspace.ev_rank.iter().skip(1) {
12140                root.stream().wait(ev)?;
12141            }
12142            root.stream()
12143                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
12144            {
12145                let Nvfp4DeviceRoutesWorkspace {
12146                    accumulator,
12147                    remote,
12148                    combined,
12149                    ..
12150                } = &mut *workspace;
12151                root.add(&accumulator[0], remote, combined, experts.input_width)?;
12152            }
12153            workspace
12154                .ev_done
12155                .as_ref()
12156                .expect("device routes done event")
12157                .record(&root.stream())?;
12158        }
12159        let output = {
12160            let _main = e.gpu.enter_main()?;
12161            e.stream().wait(
12162                workspace
12163                    .ev_done
12164                    .as_ref()
12165                    .expect("device routes done event"),
12166            )?;
12167            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
12168            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
12169            let mut output = e.uninit(experts.input_width)?;
12170            e.stream().memcpy_dtod(
12171                &workspace.combined.slice(0..experts.input_width),
12172                &mut output.slice_mut(0..experts.input_width),
12173            )?;
12174            output
12175        };
12176        if let Some(started) = started {
12177            use std::sync::atomic::Ordering;
12178            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
12179                + started.elapsed().as_nanos() as u64;
12180            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12181            if calls % 430 == 0 {
12182                eprintln!(
12183                    "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12184                    ns as f64 / 1.0e6,
12185                    ns as f64 / calls as f64 / 1.0e3,
12186                );
12187            }
12188        }
12189        Ok(output)
12190    }
12191
12192    /// The fused finish's ROOT section (combine + shadow gathers), event-free: the eager
12193    /// caller wraps it with rank-event waits + the done record; the token graph captures it
12194    /// verbatim (parent edges provide the ordering).
12195    pub(crate) fn decode_v2_finish_root_fused(
12196        &self,
12197        ws: &mut StepTpDecodeV2Ws,
12198    ) -> Result<(), Box<dyn std::error::Error>> {
12199        let root = &self.ranks[0];
12200        let _main = root.gpu.enter_main()?;
12201        if ws.raw_peer_partial != 0 {
12202            // Capture-safe raw seams (arming happened in the stage flow).
12203            raw_copy_bytes(ws.raw_peer_partial, ws.raw_o_partial1, ws.o_out * 4, root)?;
12204        } else {
12205            root.stream()
12206                .memcpy_dtod(&ws.o_partials[1][0], &mut ws.peer_partial)?;
12207        }
12208        {
12209            let StepTpDecodeV2Ws {
12210                o_partials,
12211                peer_partial,
12212                reduce_a,
12213                o_out,
12214                ..
12215            } = &mut *ws;
12216            root.add(&o_partials[0][0], peer_partial, reduce_a, *o_out)?;
12217        }
12218        let shadows = !no_local_shadow_on() || ws.raw_mixed_stage_e != 0;
12219        if shadows {
12220            // rank0's shadows are same-context (root) copies; rank1's cross-context reads go
12221            // raw when armed.
12222            let mut k_dst = ws.k_shadow.slice_mut(0..ws.local_kv_dim);
12223            root.stream().memcpy_dtod(&ws.k[0], &mut k_dst)?;
12224            let mut v_dst = ws.v_shadow.slice_mut(0..ws.local_kv_dim);
12225            root.stream().memcpy_dtod(&ws.v_raw[0], &mut v_dst)?;
12226        }
12227        if shadows && ws.raw_peer_partial != 0 {
12228            raw_copy_bytes(
12229                ws.raw_k_shadow + (ws.local_kv_dim * 4) as u64,
12230                ws.raw_k1,
12231                ws.local_kv_dim * 4,
12232                root,
12233            )?;
12234            raw_copy_bytes(
12235                ws.raw_v_shadow + (ws.local_kv_dim * 4) as u64,
12236                ws.raw_v1,
12237                ws.local_kv_dim * 4,
12238                root,
12239            )?;
12240        } else if shadows {
12241            let start = ws.local_kv_dim;
12242            let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
12243            root.stream().memcpy_dtod(&ws.k[1], &mut k_dst)?;
12244            let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
12245            root.stream().memcpy_dtod(&ws.v_raw[1], &mut v_dst)?;
12246        }
12247        if ws.raw_mixed_stage_e != 0 {
12248            // Token-graph mirrors: the e-glue children read same-context copies of the
12249            // root-produced rows.
12250            raw_copy_bytes(ws.raw_mixed_stage_e, ws.raw_reduce_a, ws.o_out * 4, root)?;
12251            let (k_stage, v_stage) = ws.raw_shadow_stage_e;
12252            raw_copy_bytes(k_stage, ws.raw_k_shadow, 2 * ws.local_kv_dim * 4, root)?;
12253            raw_copy_bytes(v_stage, ws.raw_v_shadow, 2 * ws.local_kv_dim * 4, root)?;
12254        }
12255        Ok(())
12256    }
12257
12258    /// Arm the token-graph e-context mirrors (orchestrator-supplied fixed addresses) plus
12259    /// reduce_a's own pointer.
12260    pub(crate) fn decode_v2_arm_token_mirrors(
12261        &self,
12262        ws: &mut StepTpDecodeV2Ws,
12263        mixed_stage_e: u64,
12264        shadow_stage_e: (u64, u64),
12265    ) -> Result<(), Box<dyn std::error::Error>> {
12266        use cudarc::driver::DevicePtr;
12267        let root = &self.ranks[0];
12268        let _main = root.gpu.enter_main()?;
12269        let stream = root.stream();
12270        let (a, _g) = ws.reduce_a.device_ptr(&stream);
12271        ws.raw_reduce_a = a as u64;
12272        ws.raw_mixed_stage_e = mixed_stage_e;
12273        ws.raw_shadow_stage_e = shadow_stage_e;
12274        Ok(())
12275    }
12276
12277    /// Build one layer's stitched routes graph: per-rank children captured on their own
12278    /// streams (raw cuMemcpyAsync at every cross-context seam — cudarc's slice tracking is
12279    /// capture-illegal there), a root combine child, and a multi-device parent with
12280    /// {rank0, rank1} -> root dependency edges. Zero per-token updates: every address the
12281    /// nodes touch is persistent workspace/staging.
12282    fn nvfp4_routes_build_graph(
12283        &self,
12284        experts: &ResidentNvfp4TensorParallel,
12285        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12286        local_out: usize,
12287        n_sel: usize,
12288        activation_limit: Option<f32>,
12289    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
12290        use cudarc::driver::DevicePtr;
12291        use cudarc::driver::sys;
12292        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
12293            if r == sys::CUresult::CUDA_SUCCESS {
12294                Ok(())
12295            } else {
12296                Err(format!("{what}: {r:?}").into())
12297            }
12298        }
12299        let world = self.ranks.len();
12300        if world != 2 {
12301            return Err("routes graph door is built for the TP2 pair".into());
12302        }
12303        let width = experts.input_width;
12304
12305        // Raw pointers cached before capture (each read with its owner's stream).
12306        let ptr_f32 = |buf: &crate::CudaSlice<f32>, engine: &Engine| -> u64 {
12307            let stream = engine.stream();
12308            let (ptr, _g) = buf.device_ptr(&stream);
12309            ptr as u64
12310        };
12311        let ptr_i32 = |buf: &crate::CudaSlice<i32>, engine: &Engine| -> u64 {
12312            let stream = engine.stream();
12313            let (ptr, _g) = buf.device_ptr(&stream);
12314            ptr as u64
12315        };
12316        let (sel_e, w_e) = workspace
12317            .dev_route_e
12318            .as_ref()
12319            .expect("device route staging set before graph build");
12320        let root_engine = &self.ranks[0];
12321        let p_in_stage = ptr_f32(
12322            workspace.in_stage_e.as_ref().expect("graph staging"),
12323            root_engine,
12324        );
12325        let p_out_stage = ptr_f32(
12326            workspace.out_stage_e.as_ref().expect("graph staging"),
12327            root_engine,
12328        );
12329        let p_sel_e = ptr_i32(sel_e, root_engine);
12330        let p_w_e = ptr_f32(w_e, root_engine);
12331        let p_input: Vec<u64> = (0..world)
12332            .map(|r| ptr_f32(&workspace.input[r], &self.ranks[r]))
12333            .collect();
12334        let p_sel: Vec<u64> = (0..world)
12335            .map(|r| ptr_i32(&workspace.sel[r], &self.ranks[r]))
12336            .collect();
12337        let p_route_w: Vec<u64> = (0..world)
12338            .map(|r| ptr_f32(&workspace.route_w[r], &self.ranks[r]))
12339            .collect();
12340        let p_acc1 = ptr_f32(&workspace.accumulator[1], &self.ranks[1]);
12341        let p_remote = ptr_f32(&workspace.remote, root_engine);
12342        let p_combined = ptr_f32(&workspace.combined, root_engine);
12343
12344        let raw_copy = |dst: u64,
12345                        src: u64,
12346                        bytes: usize,
12347                        engine: &Engine|
12348         -> Result<(), Box<dyn std::error::Error>> {
12349            unsafe {
12350                cu_try(
12351                    sys::cuMemcpyAsync(
12352                        dst as sys::CUdeviceptr,
12353                        src as sys::CUdeviceptr,
12354                        bytes,
12355                        engine.stream().cu_stream() as sys::CUstream,
12356                    ),
12357                    "routes graph cuMemcpyAsync",
12358                )
12359            }
12360        };
12361
12362        let mut children = Vec::with_capacity(3);
12363        for rank in 0..world {
12364            let engine = &self.ranks[rank];
12365            let _main = engine.gpu.enter_main()?;
12366            let (child, _retained) = engine.capture_graph_retained(|_| {
12367                raw_copy(p_input[rank], p_in_stage, width * 4, engine)?;
12368                raw_copy(p_sel[rank], p_sel_e, n_sel * 4, engine)?;
12369                raw_copy(p_route_w[rank], p_w_e, n_sel * 4, engine)?;
12370                {
12371                    let Nvfp4DeviceRoutesWorkspace {
12372                        input, in_q, in_d, ..
12373                    } = &mut *workspace;
12374                    engine.quantize_q8_1_into(
12375                        &input[rank],
12376                        1,
12377                        width,
12378                        &mut in_q[rank],
12379                        &mut in_d[rank],
12380                    )?;
12381                }
12382                self.nvfp4_routes_batched_sweeps_rank(
12383                    experts,
12384                    workspace,
12385                    &[],
12386                    &[],
12387                    &[],
12388                    local_out,
12389                    n_sel,
12390                    activation_limit,
12391                    true,
12392                    rank,
12393                )?;
12394                Ok(())
12395            })?;
12396            children.push(child);
12397        }
12398        {
12399            let root = &self.ranks[0];
12400            let _main = root.gpu.enter_main()?;
12401            let (child, _retained) = root.capture_graph_retained(|_| {
12402                raw_copy(p_remote, p_acc1, width * 4, root)?;
12403                {
12404                    let Nvfp4DeviceRoutesWorkspace {
12405                        accumulator,
12406                        remote,
12407                        combined,
12408                        ..
12409                    } = &mut *workspace;
12410                    root.add(&accumulator[0], remote, combined, width)?;
12411                }
12412                raw_copy(p_out_stage, p_combined, width * 4, root)?;
12413                Ok(())
12414            })?;
12415            children.push(child);
12416        }
12417
12418        let mut parent: sys::CUgraph = std::ptr::null_mut();
12419        unsafe {
12420            cu_try(sys::cuGraphCreate(&mut parent, 0), "routes cuGraphCreate")?;
12421        }
12422        let mut n0: sys::CUgraphNode = std::ptr::null_mut();
12423        let mut n1: sys::CUgraphNode = std::ptr::null_mut();
12424        let mut n2: sys::CUgraphNode = std::ptr::null_mut();
12425        unsafe {
12426            cu_try(
12427                sys::cuGraphAddChildGraphNode(
12428                    &mut n0,
12429                    parent,
12430                    std::ptr::null(),
12431                    0,
12432                    children[0].cu_graph(),
12433                ),
12434                "routes child r0",
12435            )?;
12436            cu_try(
12437                sys::cuGraphAddChildGraphNode(
12438                    &mut n1,
12439                    parent,
12440                    std::ptr::null(),
12441                    0,
12442                    children[1].cu_graph(),
12443                ),
12444                "routes child r1",
12445            )?;
12446            let deps = [n0, n1];
12447            cu_try(
12448                sys::cuGraphAddChildGraphNode(
12449                    &mut n2,
12450                    parent,
12451                    deps.as_ptr(),
12452                    2,
12453                    children[2].cu_graph(),
12454                ),
12455                "routes child root",
12456            )?;
12457        }
12458        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
12459        unsafe {
12460            cu_try(
12461                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
12462                "routes instantiate",
12463            )?;
12464        }
12465        Ok(RoutesGraph {
12466            exec,
12467            parent,
12468            _children: children,
12469        })
12470    }
12471
12472    /// One rank's routes section for the token graph (event-free): staged input copy (raw
12473    /// when the caller supplies the source pointer), quantize, and the batched sweeps.
12474    /// Eager device_routed wraps it with the entry-event wait.
12475    #[allow(clippy::too_many_arguments)]
12476    pub(crate) fn routes_rank_section(
12477        &self,
12478        experts: &ResidentNvfp4TensorParallel,
12479        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12480        raw_input_src: u64,
12481        local_out: usize,
12482        n_sel: usize,
12483        activation_limit: Option<f32>,
12484        rank_index: usize,
12485    ) -> Result<(), Box<dyn std::error::Error>> {
12486        let engine = &self.ranks[rank_index];
12487        {
12488            let _main = engine.gpu.enter_main()?;
12489            // sel/route_w land via raw copies from the e staging (fixed addresses).
12490            let (sel_e_ptr, w_e_ptr) = workspace
12491                .raw_dev_route_e
12492                .ok_or("routes rank section requires armed staging pointers")?;
12493            raw_copy_bytes(
12494                workspace.raw_input[rank_index],
12495                raw_input_src,
12496                experts.input_width * 4,
12497                engine,
12498            )?;
12499            raw_copy_bytes(workspace.raw_sel[rank_index], sel_e_ptr, n_sel * 4, engine)?;
12500            raw_copy_bytes(
12501                workspace.raw_route_w[rank_index],
12502                w_e_ptr,
12503                n_sel * 4,
12504                engine,
12505            )?;
12506            {
12507                let Nvfp4DeviceRoutesWorkspace {
12508                    input, in_q, in_d, ..
12509                } = &mut *workspace;
12510                engine.quantize_q8_1_into(
12511                    &input[rank_index],
12512                    1,
12513                    experts.input_width,
12514                    &mut in_q[rank_index],
12515                    &mut in_d[rank_index],
12516                )?;
12517            }
12518        }
12519        self.nvfp4_routes_batched_sweeps_rank(
12520            experts,
12521            workspace,
12522            &[],
12523            &[],
12524            &[],
12525            local_out,
12526            n_sel,
12527            activation_limit,
12528            true,
12529            rank_index,
12530        )
12531    }
12532
12533    /// The routes ROOT combine section (event-free): peer accumulator read (raw), canonical
12534    /// add, combined row raw-copied into the fixed e-context out stage.
12535    pub(crate) fn routes_root_section(
12536        &self,
12537        experts: &ResidentNvfp4TensorParallel,
12538        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12539    ) -> Result<(), Box<dyn std::error::Error>> {
12540        let root = &self.ranks[0];
12541        let _main = root.gpu.enter_main()?;
12542        let (acc1_ptr, remote_ptr, combined_ptr, out_stage_ptr) = workspace
12543            .raw_combine
12544            .ok_or("routes root section requires armed combine pointers")?;
12545        raw_copy_bytes(remote_ptr, acc1_ptr, experts.input_width * 4, root)?;
12546        {
12547            let Nvfp4DeviceRoutesWorkspace {
12548                accumulator,
12549                remote,
12550                combined,
12551                ..
12552            } = &mut *workspace;
12553            root.add(&accumulator[0], remote, combined, experts.input_width)?;
12554        }
12555        raw_copy_bytes(out_stage_ptr, combined_ptr, experts.input_width * 4, root)?;
12556        Ok(())
12557    }
12558
12559    /// Arm the routes raw pointers (once): staging pair, per-rank input/sel/route_w, and the
12560    /// combine set. Requires dev_route_e + in/out stages already allocated.
12561    pub(crate) fn routes_arm_raw(
12562        &self,
12563        experts: &ResidentNvfp4TensorParallel,
12564        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12565    ) -> Result<(), Box<dyn std::error::Error>> {
12566        use cudarc::driver::DevicePtr;
12567        if workspace.raw_dev_route_e.is_some() {
12568            return Ok(());
12569        }
12570        let _ = experts;
12571        let (sel_e, w_e) = workspace
12572            .dev_route_e
12573            .as_ref()
12574            .ok_or("routes staging not armed")?;
12575        let root = &self.ranks[0];
12576        {
12577            let _main = root.gpu.enter_main()?;
12578            let stream = root.stream();
12579            let (a, _g) = sel_e.device_ptr(&stream);
12580            let (b, _g) = w_e.device_ptr(&stream);
12581            workspace.raw_dev_route_e = Some((a as u64, b as u64));
12582            let (c, _g) = workspace.accumulator[1].device_ptr(&stream);
12583            let (d, _g) = workspace.remote.device_ptr(&stream);
12584            let (f, _g) = workspace.combined.device_ptr(&stream);
12585            let out_stage = workspace
12586                .out_stage_e
12587                .as_ref()
12588                .ok_or("routes out stage not armed")?;
12589            let (g_, _g) = out_stage.device_ptr(&stream);
12590            workspace.raw_combine = Some((c as u64, d as u64, f as u64, g_ as u64));
12591        }
12592        for rank in 0..self.ranks.len() {
12593            let engine = &self.ranks[rank];
12594            let _main = engine.gpu.enter_main()?;
12595            let stream = engine.stream();
12596            let (a, _g) = workspace.input[rank].device_ptr(&stream);
12597            let (b, _g) = workspace.sel[rank].device_ptr(&stream);
12598            let (c, _g) = workspace.route_w[rank].device_ptr(&stream);
12599            workspace.raw_input.push(a as u64);
12600            workspace.raw_sel.push(b as u64);
12601            workspace.raw_route_w.push(c as u64);
12602        }
12603        Ok(())
12604    }
12605
12606    /// Routed NVFP4 expert program, host-canonical transport. Native/bulk P2P transport for the
12607    /// NVFP4 bank is a separate increment; this entry point is exactness-first and reports no
12608    /// throughput claim.
12609    pub fn run_tensor_parallel_routes_nvfp4(
12610        &self,
12611        experts: &ResidentNvfp4TensorParallel,
12612        input: &[f32],
12613        tokens: usize,
12614        selected: &[usize],
12615        route_weights: &[f32],
12616        experts_per_token: usize,
12617        activation_limit: Option<f32>,
12618    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
12619        validate_activations(input, tokens, experts.input_width)?;
12620        let pairs = tokens
12621            .checked_mul(experts_per_token)
12622            .ok_or("NVFP4 TP route count overflow")?;
12623        if selected.len() != pairs || route_weights.len() != pairs {
12624            return Err(format!(
12625                "NVFP4 TP routes selected={} weights={} != tokens {tokens} x experts/token \
12626                 {experts_per_token} ({pairs})",
12627                selected.len(),
12628                route_weights.len(),
12629            )
12630            .into());
12631        }
12632        if !route_weights.iter().all(|weight| weight.is_finite()) {
12633            return Err("NVFP4 TP route weights contain a non-finite value".into());
12634        }
12635
12636        let mut output = vec![0.0f32; tokens * experts.input_width];
12637        for token in 0..tokens {
12638            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
12639            for slot in 0..experts_per_token {
12640                let pair = token * experts_per_token + slot;
12641                let expert = selected[pair];
12642                if expert >= experts.expert_count {
12643                    return Err(format!(
12644                        "NVFP4 TP selected expert {expert} outside 0..{}",
12645                        experts.expert_count
12646                    )
12647                    .into());
12648                }
12649                // EP2 banks hold the WHOLE expert on rank (expert & 1) at slot (expert >> 1);
12650                // per-row dots are the same full-width program either way (a column shard
12651                // splits ROWS, not the dot), so gate/up are bit-equal across layouts. Only
12652                // down's parenthesization moves (full-width dot vs canonical 2-shard sum) —
12653                // the numeric-class this door declares.
12654                let gate = if experts.ep2 {
12655                    self.run_full_bank_expert_nvfp4(
12656                        &experts.gate,
12657                        &experts.macros_gate,
12658                        expert,
12659                        input_row,
12660                    )?
12661                } else {
12662                    self.run_column_bank_expert_nvfp4(
12663                        &experts.gate,
12664                        &experts.macros_gate,
12665                        expert,
12666                        input_row,
12667                    )?
12668                };
12669                let up = if experts.ep2 {
12670                    self.run_full_bank_expert_nvfp4(
12671                        &experts.up,
12672                        &experts.macros_up,
12673                        expert,
12674                        input_row,
12675                    )?
12676                } else {
12677                    self.run_column_bank_expert_nvfp4(
12678                        &experts.up,
12679                        &experts.macros_up,
12680                        expert,
12681                        input_row,
12682                    )?
12683                };
12684                let activated: Vec<f32> = gate
12685                    .iter()
12686                    .zip(&up)
12687                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
12688                    .collect();
12689                debug_assert_eq!(activated.len(), experts.expert_width);
12690                let down = if experts.ep2 {
12691                    self.run_full_down_expert_nvfp4(
12692                        &experts.down,
12693                        &experts.macros_down,
12694                        expert,
12695                        &activated,
12696                    )?
12697                } else {
12698                    self.run_row_bank_expert_nvfp4(
12699                        &experts.down,
12700                        &experts.macros_down,
12701                        expert,
12702                        &activated,
12703                    )?
12704                };
12705                let weight = route_weights[pair];
12706                for (sum, value) in output
12707                    [token * experts.input_width..(token + 1) * experts.input_width]
12708                    .iter_mut()
12709                    .zip(down)
12710                {
12711                    *sum += weight * value;
12712                }
12713            }
12714        }
12715        Ok(output)
12716    }
12717}
12718
12719#[cfg(test)]
12720mod bank_v2_layout_tests {
12721    use super::{nvfp4_matrix_v2_permute, nvfp4_row_bytes};
12722
12723    /// The slot-major permutation had NO test at all until 2026-08-29, while its (since
12724    /// removed) `MEMRA_NVFP4_BANK_V2` FLAGS row carried a bit-identity claim and the live
12725    /// serving env pinned it on. This pins the DOCUMENTED mapping so a reader can be checked
12726    /// against something: per row, slot g's 16 qs bytes land contiguously at `g*16`, and its
12727    /// two UE4M3 scale bytes at `nslots*16 + g*2`. Source layout is memra `block_nvfp4`:
12728    /// 36-byte superblocks of [4 scale bytes | 32 packed e2m1], two 32-value slots per
12729    /// superblock. Since the 2026-08-29 door removal the permutation's ONLY consumer is the
12730    /// EP2 whole-expert bank build (`nvfp4_repack_bank_matrix(_, true)`), whose `*_ep`
12731    /// kernels and `qmatvec_nvfp4_fast_v2` oracle read this exact mapping.
12732    #[test]
12733    fn the_v2_bank_row_is_the_documented_slot_major_permutation() {
12734        // two rows, in_features 128 => 2 superblocks/row, 4 slots/row, 72 bytes/row.
12735        let (out_f, in_f) = (2usize, 128usize);
12736        let row_bytes = nvfp4_row_bytes(in_f);
12737        assert_eq!(row_bytes, 72);
12738        let v1: Vec<u8> = (0..out_f * row_bytes).map(|i| (i % 251) as u8).collect();
12739        let v2 = nvfp4_matrix_v2_permute(&v1, out_f, in_f);
12740        assert_eq!(v2.len(), v1.len(), "a permutation cannot change the size");
12741        let n_slots = in_f / 32;
12742        for row in 0..out_f {
12743            let src = &v1[row * row_bytes..(row + 1) * row_bytes];
12744            let dst = &v2[row * row_bytes..(row + 1) * row_bytes];
12745            for g in 0..n_slots {
12746                let (sblk, h) = (g / 2, g % 2);
12747                let sb = &src[sblk * 36..sblk * 36 + 36];
12748                assert_eq!(
12749                    &dst[g * 16..g * 16 + 16],
12750                    &sb[4 + 16 * h..4 + 16 * h + 16],
12751                    "row {row} slot {g} codes"
12752                );
12753                assert_eq!(
12754                    &dst[n_slots * 16 + g * 2..n_slots * 16 + g * 2 + 2],
12755                    &sb[2 * h..2 * h + 2],
12756                    "row {row} slot {g} scales"
12757                );
12758            }
12759            // and it moves bytes only: same multiset per row, rows never cross.
12760            let (mut a, mut b) = (src.to_vec(), dst.to_vec());
12761            a.sort_unstable();
12762            b.sort_unstable();
12763            assert_eq!(a, b, "row {row} is not a byte permutation");
12764        }
12765    }
12766}
12767
12768#[cfg(test)]
12769mod tests {
12770
12771    /// THE DEFECT, ASSERTED SO IT CANNOT COME BACK. The retired memo key hashed only the K
12772    /// pointer, the base pointer, the layer and t, while the table it returned ALSO carried
12773    /// the V and LEN pointers. Two different allocation generations that happen to share a K
12774    /// address therefore collide, and the entry the map hands back sends a live launch at
12775    /// another allocation's V and len. This test does not assert the key is fine; it asserts
12776    /// the key is BLIND, which is why `rows_tab_restage_on` exists and defaults ON.
12777    #[test]
12778    fn the_retired_rows_tab_key_cannot_see_the_v_and_len_pointers_it_hands_back() {
12779        let (kp, bp) = (0xdead_0000u64, 0u64);
12780        let live = [[kp, 0x00b1_0000u64, 0x00c1_0000u64, bp]];
12781        let recycled = [[kp, 0x00b2_0000u64, 0x00c2_0000u64, bp]];
12782        assert_eq!(
12783            super::retired_rows_tab_key(kp, bp, 20, 2),
12784            super::retired_rows_tab_key(kp, bp, 20, 2),
12785            "same layer and t must hash the same, or the test proves nothing"
12786        );
12787        let a = super::rows_tab_host(&live, 0x9000, true, 1);
12788        let b = super::rows_tab_host(&recycled, 0x9000, true, 1);
12789        assert_ne!(a, b, "the two generations write DIFFERENT tables");
12790        // ... yet one key covers both, which is exactly the use-after-free.
12791        assert_eq!(
12792            super::retired_rows_tab_key(live[0][0], live[0][3], 20, 1),
12793            super::retired_rows_tab_key(recycled[0][0], recycled[0][3], 20, 1),
12794            "the retired key collides across allocation generations"
12795        );
12796    }
12797
12798    /// The restage must be VALUE-NEUTRAL: on a fresh lookup the memo and the restage produce
12799    /// identical bytes, which is what makes spec-on output byte-identical to spec-off.
12800    #[test]
12801    fn rows_tab_layout_is_the_same_bytes_the_memo_would_have_cached() {
12802        let parts = [
12803            [0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64],
12804            [0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64],
12805        ];
12806        let same = super::rows_tab_host(&parts, 0x7000, true, 2);
12807        assert_eq!(
12808            same,
12809            vec![
12810                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000,
12811                1, // row 0: back = t-1-r = 1
12812                0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64, 0x7000, 0, // row 1: back = 0
12813            ],
12814            "same-session rows share one counter cell and step back t-1-r"
12815        );
12816        let cross = super::rows_tab_host(&parts, 0x7000, false, 2);
12817        assert_eq!(
12818            cross,
12819            vec![
12820                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000, 0, 0x00a1u64, 0x00b1u64,
12821                0x00c1u64, 0x00d1u64, 0x7004, 0,
12822            ],
12823            "cross-session rows get their own counter cell and no step back"
12824        );
12825    }
12826    use super::*;
12827
12828    #[test]
12829    fn step_expert_activation_clamps_each_arm_by_the_official_contract() {
12830        let limit = Some(7.0);
12831        assert_eq!(step_expert_activation_host(20.0, 9.0, limit), 49.0);
12832        assert_eq!(step_expert_activation_host(20.0, -9.0, limit), -49.0);
12833        assert!(
12834            step_expert_activation_host(-20.0, 9.0, limit).abs()
12835                < step_expert_activation_host(-20.0, 9.0, None).abs()
12836        );
12837        assert!(validate_step_expert_activation_limit(Some(f32::NAN)).is_err());
12838        assert!(validate_step_expert_activation_limit(Some(0.0)).is_err());
12839        assert!(validate_step_expert_activation_limit(limit).is_ok());
12840    }
12841
12842    #[test]
12843    fn moe_residual_host_preserves_official_add_order() {
12844        let output = moe_residual_host(&[1.0e20], &[-1.0e20], &[1.0]).unwrap();
12845        assert_eq!(output, [0.0]);
12846        assert_eq!(
12847            moe_residual_host(&[0.0], &[0.0, 1.0], &[0.0]).unwrap_err(),
12848            "MoE residual lengths residual=1 routed=2 shared=1"
12849        );
12850    }
12851
12852    #[test]
12853    fn expert_owner_routes_preserve_global_pair_order_with_local_expert_ids() {
12854        let selected = [0, 36, 72, 108, 144, 180, 216, 252];
12855        let owners = partition_expert_owner_routes(288, 4, 1, 8, &selected).unwrap();
12856        assert_eq!(owners.len(), 4);
12857        for (rank, owner) in owners.iter().enumerate() {
12858            assert_eq!(owner.rank, rank);
12859            assert_eq!(owner.selected, vec![0, 36]);
12860            assert_eq!(owner.token_rows, vec![0, 0]);
12861            assert_eq!(owner.global_pairs, vec![rank * 2, rank * 2 + 1]);
12862        }
12863    }
12864
12865    #[test]
12866    fn expert_owner_routes_validate_geometry_and_selected_experts() {
12867        assert!(partition_expert_owner_routes(288, 5, 1, 8, &[0; 8]).is_err());
12868        assert!(partition_expert_owner_routes(288, 4, 2, 8, &[0; 8]).is_err());
12869        let error = partition_expert_owner_routes(288, 4, 1, 8, &[288; 8]).unwrap_err();
12870        assert!(error.contains("outside 0..288"));
12871    }
12872
12873    #[test]
12874    fn step_grouped_owner_routes_validate_dynamic_top8_shapes() {
12875        let selected = [
12876            1, 73, 80, 145, 152, 159, 217, 224, 12, 84, 91, 156, 163, 170, 228, 235,
12877        ];
12878        assert_eq!(
12879            validate_step_grouped_owner_routes(288, 2, &selected).unwrap(),
12880            16
12881        );
12882        let owners = partition_expert_owner_routes(288, 4, 2, 8, &selected).unwrap();
12883        assert_eq!(
12884            owners
12885                .iter()
12886                .map(|owner| owner.selected.len())
12887                .collect::<Vec<_>>(),
12888            vec![2, 4, 6, 4]
12889        );
12890        assert!(validate_step_grouped_owner_routes(288, 2, &selected[..8]).is_err());
12891        assert!(validate_step_grouped_owner_routes(288, 1, &[0; 8]).is_err());
12892        assert!(validate_step_grouped_owner_routes(287, 2, &selected).is_err());
12893    }
12894
12895    #[test]
12896    fn weighted_route_combine_requires_a_canonical_pair_permutation() {
12897        let owner0 = [0usize, 3];
12898        let owner1 = [1usize, 2];
12899        let owners = [owner0.as_slice(), owner1.as_slice()];
12900        assert_eq!(
12901            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, 0.2, 0.3, 0.4],)
12902                .unwrap(),
12903            WeightedRouteCombineShape {
12904                pairs: 4,
12905                max_pairs: 12,
12906            }
12907        );
12908        let duplicate = [owner0.as_slice(), &[1usize, 1][..]];
12909        assert!(
12910            validate_weighted_route_combine(4096, 4, 3, 1, &duplicate, &[0.1, 0.2, 0.3, 0.4],)
12911                .is_err()
12912        );
12913        assert!(
12914            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, f32::NAN, 0.3, 0.4],)
12915                .is_err()
12916        );
12917        assert!(
12918            validate_weighted_route_combine(4096, 4, 1, 2, &owners, &[0.1, 0.2, 0.3, 0.4],)
12919                .is_err()
12920        );
12921    }
12922
12923    #[test]
12924    fn native_p2p_door_is_strict_and_default_off() {
12925        assert!(!parse_step_tp_native_p2p(None).unwrap());
12926        assert!(!parse_step_tp_native_p2p(Some("")).unwrap());
12927        assert!(!parse_step_tp_native_p2p(Some("0")).unwrap());
12928        assert!(parse_step_tp_native_p2p(Some("1")).unwrap());
12929        assert!(parse_step_tp_native_p2p(Some("true")).is_err());
12930        assert!(parse_step_tp_native_p2p(Some("2")).is_err());
12931    }
12932
12933    #[test]
12934    fn bulk_p2p_door_is_strict_and_default_off() {
12935        assert!(!parse_step_tp_bulk_p2p(None).unwrap());
12936        assert!(!parse_step_tp_bulk_p2p(Some("")).unwrap());
12937        assert!(!parse_step_tp_bulk_p2p(Some("0")).unwrap());
12938        assert!(parse_step_tp_bulk_p2p(Some("1")).unwrap());
12939        assert!(parse_step_tp_bulk_p2p(Some("true")).is_err());
12940        assert!(parse_step_tp_bulk_p2p(Some("2")).is_err());
12941    }
12942
12943    #[test]
12944    fn ep_device_arithmetic_door_is_strict_and_default_off() {
12945        assert!(!parse_step_ep_device_arithmetic(None).unwrap());
12946        assert!(!parse_step_ep_device_arithmetic(Some("")).unwrap());
12947        assert!(!parse_step_ep_device_arithmetic(Some("0")).unwrap());
12948        assert!(parse_step_ep_device_arithmetic(Some("1")).unwrap());
12949        assert!(parse_step_ep_device_arithmetic(Some("true")).is_err());
12950        assert!(parse_step_ep_device_arithmetic(Some("2")).is_err());
12951    }
12952
12953    #[test]
12954    fn f32_mirror_door_is_strict_and_default_off() {
12955        assert!(!parse_step_tp_f32_mirror(None).unwrap());
12956        assert!(!parse_step_tp_f32_mirror(Some("")).unwrap());
12957        assert!(!parse_step_tp_f32_mirror(Some("0")).unwrap());
12958        assert!(parse_step_tp_f32_mirror(Some("1")).unwrap());
12959        assert!(parse_step_tp_f32_mirror(Some("true")).is_err());
12960        assert!(parse_step_tp_f32_mirror(Some("2")).is_err());
12961    }
12962
12963    fn matrix(out_features: usize, in_features: usize) -> (Vec<u8>, Vec<f32>) {
12964        let codes = (0..out_features * in_features)
12965            .map(|index| (index % 251) as u8)
12966            .collect();
12967        let scales = (0..out_features.div_ceil(FP8_BLOCK) * in_features.div_ceil(FP8_BLOCK))
12968            .map(|index| index as f32 + 1.0)
12969            .collect();
12970        (codes, scales)
12971    }
12972
12973    fn bf16_matrix_bytes(out_features: usize, in_features: usize) -> Vec<u8> {
12974        (0..out_features * in_features)
12975            .flat_map(|value| (value as u16).to_le_bytes())
12976            .collect()
12977    }
12978
12979    fn decode_u16(bytes: &[u8]) -> Vec<u16> {
12980        bytes
12981            .chunks_exact(2)
12982            .map(|bytes| u16::from_le_bytes([bytes[0], bytes[1]]))
12983            .collect()
12984    }
12985
12986    #[test]
12987    fn bf16_matrix_rejects_wrong_byte_count() {
12988        let bytes = vec![0u8; 4 * 4 * 2 - 1];
12989        let matrix = Bf16Matrix {
12990            bytes: &bytes,
12991            out_features: 4,
12992            in_features: 4,
12993        };
12994        assert!(matrix.validate().unwrap_err().contains("4x4x2"));
12995    }
12996
12997    #[test]
12998    fn replicated_device_rows_require_exact_rank_local_shapes() {
12999        assert_eq!(
13000            replicated_device_row_values(3, 4096, 4, &[12_288; 4]).unwrap(),
13001            12_288
13002        );
13003        assert!(replicated_device_row_values(0, 4096, 4, &[0; 4]).is_err());
13004        assert!(replicated_device_row_values(3, 0, 4, &[0; 4]).is_err());
13005        assert!(replicated_device_row_values(3, 4096, 4, &[12_288; 3]).is_err());
13006        assert!(
13007            replicated_device_row_values(3, 4096, 4, &[12_288, 12_288, 12_287, 12_288]).is_err()
13008        );
13009        assert!(replicated_device_row_values(usize::MAX, 2, 1, &[0]).is_err());
13010    }
13011
13012    #[test]
13013    fn replicated_device_row_refresh_requires_exact_root_source() {
13014        assert_eq!(
13015            replicated_device_row_source_values(1, 12_288, 12_288, 3, 3).unwrap(),
13016            12_288
13017        );
13018        assert!(replicated_device_row_source_values(0, 12_288, 0, 3, 3).is_err());
13019        assert!(replicated_device_row_source_values(1, 0, 0, 3, 3).is_err());
13020        assert!(replicated_device_row_source_values(1, 12_288, 12_287, 3, 3).is_err());
13021        assert!(replicated_device_row_source_values(1, 12_288, 12_288, 2, 3).is_err());
13022        assert!(replicated_device_row_source_values(usize::MAX, 2, 0, 3, 3).is_err());
13023    }
13024
13025    #[test]
13026    fn step_bf16_canonical_rows_are_topology_invariant_through_tp8() {
13027        for tp in [1, 2, 4, 8] {
13028            assert_eq!(step_bf16_canonical_chunk_rows(8_192, tp).unwrap(), 1_024);
13029            assert_eq!(step_bf16_canonical_chunk_rows(12_288, tp).unwrap(), 1_536);
13030            assert_eq!(step_bf16_canonical_chunk_rows(1_024, tp).unwrap(), 128);
13031            assert_eq!(step_bf16_canonical_chunk_cols(8_192, tp).unwrap(), 1_024);
13032            assert_eq!(step_bf16_canonical_chunk_cols(12_288, tp).unwrap(), 1_536);
13033        }
13034        assert!(step_bf16_canonical_chunk_rows(12_288, 3).is_err());
13035        assert!(step_bf16_canonical_chunk_rows(1_001, 2).is_err());
13036        assert!(step_bf16_canonical_chunk_cols(12_288, 3).is_err());
13037        assert!(step_bf16_canonical_chunk_cols(1_001, 2).is_err());
13038    }
13039
13040    #[test]
13041    fn cache_rows_split_by_token_then_rank() {
13042        let rows = (0u8..24).collect::<Vec<_>>();
13043        assert_eq!(
13044            cache_rank_rows(&rows, 3, 4, 2, 0).unwrap(),
13045            vec![0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19]
13046        );
13047        assert_eq!(
13048            cache_rank_rows(&rows, 3, 4, 2, 1).unwrap(),
13049            vec![4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23]
13050        );
13051        assert!(cache_rank_rows(&rows[..23], 3, 4, 2, 0).is_err());
13052        assert!(cache_rank_rows(&rows, 3, 4, 2, 2).is_err());
13053    }
13054
13055    #[test]
13056    fn bf16_column_shard_preserves_contiguous_output_rows() {
13057        let bytes = bf16_matrix_bytes(4, 4);
13058        let matrix = Bf16Matrix {
13059            bytes: &bytes,
13060            out_features: 4,
13061            in_features: 4,
13062        };
13063        let shard = bf16_column_shard(matrix, 2, 1).unwrap();
13064        assert_eq!(shard.out_features, 2);
13065        assert_eq!(shard.in_features, 4);
13066        assert_eq!(decode_u16(shard.bytes), (8..16).collect::<Vec<_>>());
13067    }
13068
13069    #[test]
13070    fn bf16_row_shard_preserves_each_input_column_window() {
13071        let bytes = bf16_matrix_bytes(3, 4);
13072        let matrix = Bf16Matrix {
13073            bytes: &bytes,
13074            out_features: 3,
13075            in_features: 4,
13076        };
13077        let shard = bf16_row_shard(matrix, 2, 1).unwrap();
13078        assert_eq!(decode_u16(&shard), vec![2, 3, 6, 7, 10, 11]);
13079    }
13080
13081    #[test]
13082    fn bf16_row_block_preserves_global_column_order() {
13083        let bytes = bf16_matrix_bytes(3, 8);
13084        let matrix = Bf16Matrix {
13085            bytes: &bytes,
13086            out_features: 3,
13087            in_features: 8,
13088        };
13089        let block = bf16_row_block(matrix, 2, 3).unwrap();
13090        assert_eq!(decode_u16(&block), vec![2, 3, 4, 10, 11, 12, 18, 19, 20]);
13091    }
13092
13093    #[test]
13094    fn column_shard_preserves_contiguous_weight_and_scale_rows() {
13095        let (codes, scales) = matrix(1280, 4096);
13096        let matrix = E4m3BlockMatrix {
13097            codes: &codes,
13098            scales: &scales,
13099            out_features: 1280,
13100            in_features: 4096,
13101        };
13102        let shard = column_shard(matrix, 2, 1).unwrap();
13103        assert_eq!(shard.out_features, 640);
13104        assert_eq!(shard.codes, &codes[640 * 4096..]);
13105        assert_eq!(shard.scales, &scales[5 * 32..]);
13106    }
13107
13108    #[test]
13109    fn row_shard_preserves_each_weight_and_scale_column_window() {
13110        let (codes, scales) = matrix(4096, 1280);
13111        let matrix = E4m3BlockMatrix {
13112            codes: &codes,
13113            scales: &scales,
13114            out_features: 4096,
13115            in_features: 1280,
13116        };
13117        let (shard_codes, shard_scales) = row_shard(matrix, 2, 1).unwrap();
13118        assert_eq!(shard_codes.len(), 4096 * 640);
13119        assert_eq!(&shard_codes[..640], &codes[640..1280]);
13120        assert_eq!(&shard_codes[640..1280], &codes[1280 + 640..2560]);
13121        assert_eq!(shard_scales.len(), 32 * 5);
13122        assert_eq!(&shard_scales[..5], &scales[5..10]);
13123        assert_eq!(&shard_scales[5..10], &scales[15..20]);
13124    }
13125
13126    #[test]
13127    fn activation_shards_keep_token_rows_separate() {
13128        let activations: Vec<f32> = (0..2 * 8).map(|value| value as f32).collect();
13129        assert_eq!(
13130            activation_shard(&activations, 2, 8, 2, 1),
13131            vec![4.0, 5.0, 6.0, 7.0, 12.0, 13.0, 14.0, 15.0],
13132        );
13133    }
13134
13135    #[test]
13136    fn expert_bank_selects_expert_major_code_and_scale_planes() {
13137        let expert_count = 2;
13138        let out_features = 128;
13139        let in_features = 128;
13140        let code_stride = out_features * in_features;
13141        let codes: Vec<u8> = (0..expert_count * code_stride)
13142            .map(|index| (index % 251) as u8)
13143            .collect();
13144        let scales = vec![1.0f32, 2.0];
13145        let bank = E4m3ExpertBank {
13146            codes: &codes,
13147            scales: &scales,
13148            expert_count,
13149            out_features,
13150            in_features,
13151        };
13152        bank.validate().unwrap();
13153        let expert = bank.expert(1).unwrap();
13154        assert_eq!(expert.codes, &codes[code_stride..]);
13155        assert_eq!(expert.scales, &[2.0]);
13156    }
13157
13158    #[test]
13159    fn expert_bank_rejects_non_positive_scale() {
13160        let codes = vec![0u8; 128 * 128];
13161        let scales = vec![0.0f32];
13162        let bank = E4m3ExpertBank {
13163            codes: &codes,
13164            scales: &scales,
13165            expert_count: 1,
13166            out_features: 128,
13167            in_features: 128,
13168        };
13169        assert!(bank.validate().unwrap_err().contains("non-positive"));
13170    }
13171
13172    #[test]
13173    fn tensor_parallel_column_bank_keeps_each_expert_scale_plane_separate() {
13174        let expert_count = 2;
13175        let out_features = 256;
13176        let in_features = 128;
13177        let code_stride = out_features * in_features;
13178        let scale_stride = 2;
13179        let codes = (0..expert_count * code_stride)
13180            .map(|index| (index % 251) as u8)
13181            .collect::<Vec<_>>();
13182        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
13183        let bank = E4m3ExpertBank {
13184            codes: &codes,
13185            scales: &scales,
13186            expert_count,
13187            out_features,
13188            in_features,
13189        };
13190
13191        let rank = pack_column_bank_rank(bank, 2, 1).unwrap();
13192        assert_eq!(rank.out_features, 128);
13193        assert_eq!(rank.in_features, 128);
13194        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
13195        assert_eq!(rank.scales, vec![11.0, 21.0]);
13196        assert_eq!(&rank.codes[..128 * 128], &codes[128 * 128..256 * 128]);
13197        assert_eq!(
13198            &rank.codes[128 * 128..],
13199            &codes[code_stride + 128 * 128..2 * code_stride]
13200        );
13201        assert_eq!(scale_stride, scales.len() / expert_count);
13202    }
13203
13204    #[test]
13205    fn tensor_parallel_row_bank_keeps_each_expert_scale_plane_separate() {
13206        let expert_count = 2;
13207        let out_features = 128;
13208        let in_features = 256;
13209        let code_stride = out_features * in_features;
13210        let codes = (0..expert_count * code_stride)
13211            .map(|index| (index % 251) as u8)
13212            .collect::<Vec<_>>();
13213        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
13214        let bank = E4m3ExpertBank {
13215            codes: &codes,
13216            scales: &scales,
13217            expert_count,
13218            out_features,
13219            in_features,
13220        };
13221
13222        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
13223        assert_eq!(rank.out_features, 128);
13224        assert_eq!(rank.in_features, 128);
13225        assert_eq!(rank.k_blocks, Some(1));
13226        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
13227        assert_eq!(rank.scales, vec![11.0, 21.0]);
13228        assert_eq!(&rank.codes[..128], &codes[128..256]);
13229        assert_eq!(
13230            &rank.codes[128 * 128..128 * 128 + 128],
13231            &codes[code_stride + 128..code_stride + 256]
13232        );
13233    }
13234
13235    #[test]
13236    fn tensor_parallel_row_bank_preserves_global_k_block_order() {
13237        let expert_count = 2;
13238        let out_features = 256;
13239        let in_features = 512;
13240        let code_stride = out_features * in_features;
13241        let mut codes = vec![0u8; expert_count * code_stride];
13242        for expert in 0..expert_count {
13243            for row in 0..out_features {
13244                for block in 0..4 {
13245                    let value = (expert * 80 + block * 16 + row % 16) as u8;
13246                    let start = expert * code_stride + row * in_features + block * FP8_BLOCK;
13247                    codes[start..start + FP8_BLOCK].fill(value);
13248                }
13249            }
13250        }
13251        let scales = vec![
13252            1.0f32, 2.0, 3.0, 4.0, 11.0, 12.0, 13.0, 14.0, 101.0, 102.0, 103.0, 104.0, 111.0,
13253            112.0, 113.0, 114.0,
13254        ];
13255        let bank = E4m3ExpertBank {
13256            codes: &codes,
13257            scales: &scales,
13258            expert_count,
13259            out_features,
13260            in_features,
13261        };
13262
13263        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
13264        assert_eq!(rank.out_features, out_features);
13265        assert_eq!(rank.in_features, 256);
13266        assert_eq!(rank.k_blocks, Some(2));
13267        assert_eq!(rank.code_stride, out_features * 256);
13268        assert_eq!(rank.scale_stride, 4);
13269        assert_eq!(&rank.scales[..4], &[3.0, 13.0, 4.0, 14.0]);
13270        assert_eq!(&rank.scales[4..], &[103.0, 113.0, 104.0, 114.0]);
13271
13272        let block_stride = out_features * FP8_BLOCK;
13273        assert!(rank.codes[..FP8_BLOCK].iter().all(|&code| code == 32));
13274        assert!(
13275            rank.codes[block_stride..block_stride + FP8_BLOCK]
13276                .iter()
13277                .all(|&code| code == 48)
13278        );
13279        assert!(
13280            rank.codes[rank.code_stride..rank.code_stride + FP8_BLOCK]
13281                .iter()
13282                .all(|&code| code == 112)
13283        );
13284        assert!(
13285            rank.codes
13286                [rank.code_stride + block_stride..rank.code_stride + block_stride + FP8_BLOCK]
13287                .iter()
13288                .all(|&code| code == 128)
13289        );
13290    }
13291
13292    #[test]
13293    fn step_ep_layer_specs_are_literal_and_fail_closed() {
13294        assert!(parse_step_ep_layer_specs(None).unwrap().is_empty());
13295        assert!(parse_step_ep_layer_specs(Some("0")).unwrap().is_empty());
13296        assert_eq!(
13297            parse_step_ep_layer_specs(Some("24@1,2")).unwrap(),
13298            vec![StepEpLayerSpec {
13299                layer: 24,
13300                devices: vec![1, 2],
13301            }]
13302        );
13303        assert_eq!(
13304            parse_step_ep_layer_specs(Some("24-25@1,2;31@0,2")).unwrap(),
13305            vec![
13306                StepEpLayerSpec {
13307                    layer: 24,
13308                    devices: vec![1, 2],
13309                },
13310                StepEpLayerSpec {
13311                    layer: 25,
13312                    devices: vec![1, 2],
13313                },
13314                StepEpLayerSpec {
13315                    layer: 31,
13316                    devices: vec![0, 2],
13317                },
13318            ]
13319        );
13320        assert!(parse_step_ep_layer_specs(Some("24@1")).is_err());
13321        assert!(parse_step_ep_layer_specs(Some("24@1,1")).is_err());
13322        assert!(parse_step_ep_layer_specs(Some("layer@1,2")).is_err());
13323        assert!(parse_step_ep_layer_specs(Some("25-24@1,2")).is_err());
13324        assert!(parse_step_ep_layer_specs(Some("0-128@1,2")).is_err());
13325        assert!(parse_step_ep_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
13326        assert!(parse_step_ep_layer_specs(Some("all@0,1")).is_err());
13327    }
13328
13329    #[test]
13330    fn step_tp_layer_specs_share_the_fail_closed_layer_contract() {
13331        assert!(parse_step_tp_layer_specs(None).unwrap().is_empty());
13332        assert!(parse_step_tp_layer_specs(Some("0")).unwrap().is_empty());
13333        assert_eq!(
13334            parse_step_tp_layer_specs(Some("24-25@1,2")).unwrap(),
13335            vec![
13336                StepTpLayerSpec {
13337                    layer: 24,
13338                    devices: vec![1, 2],
13339                },
13340                StepTpLayerSpec {
13341                    layer: 25,
13342                    devices: vec![1, 2],
13343                },
13344            ]
13345        );
13346        let error = parse_step_tp_layer_specs(Some("24@1")).unwrap_err();
13347        assert!(error.contains("MEMRA_STEP_TP"));
13348        assert!(parse_step_tp_layer_specs(Some("24@1,1")).is_err());
13349        assert!(parse_step_tp_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
13350
13351        let all = parse_step_tp_layer_specs(Some("all@0,1,2,3,4,5,6,7")).unwrap();
13352        assert_eq!(all.len(), STEP37_TRUNK_LAYERS);
13353        assert_eq!(all.first().unwrap().layer, 0);
13354        assert_eq!(all.last().unwrap().layer, STEP37_TRUNK_LAYERS - 1);
13355        let devices = (0..8).collect::<Vec<_>>();
13356        assert!(all.iter().all(|spec| spec.devices == devices));
13357        assert!(parse_step_tp_layer_specs(Some("all@0,1;44@0,1")).is_err());
13358    }
13359}
13360
13361// ===== Whole-token graph builder (increment B) ==================================================
13362//
13363// The decode fns are already sectioned at every e/rank/root seam (the stage flow, sweeps_rank,
13364// finish splits, the dcw arm). `graph_section` is the one annotation those seams call: eager
13365// mode runs the closure verbatim; build mode wraps it in a stream capture on the section's
13366// device and records a child + its dependency edges. A token then assembles as ONE multi-device
13367// parent (children per section per layer), launched once per token — the launch-collapse the
13368// per-layer minis could not reach (routes-mini negative, 2026-08-21).
13369
13370/// One captured section: the child graph plus which parent node it became, and the CUDA
13371/// context it was captured under (exec memset updates need it).
13372struct TokenGraphChild {
13373    graph: cudarc::driver::CudaGraph,
13374    node: cudarc::driver::sys::CUgraphNode,
13375    ctx: cudarc::driver::sys::CUcontext,
13376}
13377
13378/// Exec-updatable fa geometry discovered in one attention rank child: the three partial-pool
13379/// memsets, the dcw fa kernel, and its combine — everything a bucket change touches. Node
13380/// handles address the parent's CLONED child graphs (the M1-probed update path).
13381struct TokenGraphFaSite {
13382    ctx: cudarc::driver::sys::CUcontext,
13383    memset_o: cudarc::driver::sys::CUgraphNode,
13384    memset_m: [cudarc::driver::sys::CUgraphNode; 2],
13385    fa: cudarc::driver::sys::CUgraphNode,
13386    combine: cudarc::driver::sys::CUgraphNode,
13387    window: usize,
13388    n_head: usize,
13389    n_head_kv: usize,
13390    head_dim: usize,
13391}
13392
13393pub struct TokenGraphBuilder {
13394    parent: cudarc::driver::sys::CUgraph,
13395    children: Vec<TokenGraphChild>,
13396    /// Nodes every NEXT section must depend on (the frontier): one node for serial flow,
13397    /// several while a parallel group is open.
13398    frontier: Vec<cudarc::driver::sys::CUgraphNode>,
13399    /// Detached sections: forked from the frontier at issue time, joined ONLY by the next
13400    /// non-group section (they never gate a parallel group merge — the SH1 shape).
13401    pending_detached: Vec<cudarc::driver::sys::CUgraphNode>,
13402    /// Open parallel group: sections issued under the same group id fork from the SAME
13403    /// predecessor set and merge into the frontier together when the group closes.
13404    group: Option<(
13405        u32,
13406        Vec<cudarc::driver::sys::CUgraphNode>,
13407        Vec<cudarc::driver::sys::CUgraphNode>,
13408    )>,
13409}
13410
13411// SAFETY: single decode thread; graph handles are process handles.
13412unsafe impl Send for TokenGraphBuilder {}
13413
13414impl TokenGraphBuilder {
13415    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
13416        use cudarc::driver::sys;
13417        let mut parent: sys::CUgraph = std::ptr::null_mut();
13418        let r = unsafe { sys::cuGraphCreate(&mut parent, 0) };
13419        if r != sys::CUresult::CUDA_SUCCESS {
13420            return Err(format!("token graph create: {r:?}").into());
13421        }
13422        Ok(Self {
13423            parent,
13424            children: Vec::new(),
13425            frontier: Vec::new(),
13426            pending_detached: Vec::new(),
13427            group: None,
13428        })
13429    }
13430
13431    fn push_child(
13432        &mut self,
13433        graph: cudarc::driver::CudaGraph,
13434        parallel_group: Option<u32>,
13435        detached: bool,
13436        absorb: bool,
13437        ctx: cudarc::driver::sys::CUcontext,
13438    ) -> Result<(), Box<dyn std::error::Error>> {
13439        use cudarc::driver::sys;
13440        // Resolve the dependency set: serial sections depend on the current frontier; a
13441        // parallel-group section depends on the frontier AS OF the group opening; a
13442        // DETACHED section forks like a group member but joins only the next serial section.
13443        let deps: Vec<sys::CUgraphNode> = match (&mut self.group, parallel_group) {
13444            (Some((open, base, _)), Some(group)) if *open == group => base.clone(),
13445            (state, Some(group)) => {
13446                // opening a new group (closing any previous one first)
13447                if let Some((_, _, members)) = state.take() {
13448                    self.frontier = members;
13449                }
13450                let base = self.frontier.clone();
13451                *state = Some((group, base.clone(), Vec::new()));
13452                base
13453            }
13454            (state, None) if detached => match state.as_ref() {
13455                Some((_, base, _)) => base.clone(),
13456                None => self.frontier.clone(),
13457            },
13458            (state, None) => {
13459                if let Some((_, _, members)) = state.take() {
13460                    self.frontier = members;
13461                }
13462                let mut deps = self.frontier.clone();
13463                if absorb {
13464                    deps.append(&mut self.pending_detached);
13465                }
13466                deps
13467            }
13468        };
13469        let mut node: sys::CUgraphNode = std::ptr::null_mut();
13470        let r = unsafe {
13471            sys::cuGraphAddChildGraphNode(
13472                &mut node,
13473                self.parent,
13474                if deps.is_empty() {
13475                    std::ptr::null()
13476                } else {
13477                    deps.as_ptr()
13478                },
13479                deps.len(),
13480                graph.cu_graph(),
13481            )
13482        };
13483        if r != sys::CUresult::CUDA_SUCCESS {
13484            return Err(format!("token graph child: {r:?}").into());
13485        }
13486        match (&mut self.group, parallel_group, detached) {
13487            (_, None, true) => self.pending_detached.push(node),
13488            (Some((_, _, members)), Some(_), _) => members.push(node),
13489            _ => self.frontier = vec![node],
13490        }
13491        self.children.push(TokenGraphChild { graph, node, ctx });
13492        Ok(())
13493    }
13494
13495    pub fn finish(mut self) -> Result<TokenGraph, Box<dyn std::error::Error>> {
13496        use cudarc::driver::sys;
13497        if let Some((_, _, members)) = self.group.take() {
13498            self.frontier = members;
13499        }
13500        // Discover the fa sites BEFORE instantiate: the parent's cloned child graphs hold
13501        // the node handles the exec update path (M1) addresses.
13502        let mut fa_sites = Vec::new();
13503        for child in &self.children {
13504            if let Some(site) = discover_fa_site(child.node, child.ctx)? {
13505                fa_sites.push(site);
13506            }
13507        }
13508        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
13509        let r = unsafe { sys::cuGraphInstantiateWithFlags(&mut exec, self.parent, 0) };
13510        if r != sys::CUresult::CUDA_SUCCESS {
13511            return Err(format!("token graph instantiate: {r:?}").into());
13512        }
13513        Ok(TokenGraph {
13514            exec,
13515            parent: self.parent,
13516            _children: self.children,
13517            fa_sites,
13518        })
13519    }
13520}
13521
13522/// Walk one child graph; if it carries the attention-section signature (exactly three MEMSET
13523/// nodes chained memset->memset->memset->fa_kernel->combine_kernel), return its update site.
13524fn discover_fa_site(
13525    child_node: cudarc::driver::sys::CUgraphNode,
13526    ctx: cudarc::driver::sys::CUcontext,
13527) -> Result<Option<TokenGraphFaSite>, Box<dyn std::error::Error>> {
13528    use cudarc::driver::sys;
13529    fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
13530        if r == sys::CUresult::CUDA_SUCCESS {
13531            Ok(())
13532        } else {
13533            Err(format!("{what}: {r:?}").into())
13534        }
13535    }
13536    let mut graph: sys::CUgraph = std::ptr::null_mut();
13537    unsafe {
13538        cu_try(
13539            sys::cuGraphChildGraphNodeGetGraph(child_node, &mut graph),
13540            "fa-site child GetGraph",
13541        )?;
13542    }
13543    let mut count: usize = 0;
13544    unsafe {
13545        cu_try(
13546            sys::cuGraphGetNodes(graph, std::ptr::null_mut(), &mut count),
13547            "fa-site GetNodes(count)",
13548        )?;
13549    }
13550    let mut nodes: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); count];
13551    unsafe {
13552        cu_try(
13553            sys::cuGraphGetNodes(graph, nodes.as_mut_ptr(), &mut count),
13554            "fa-site GetNodes",
13555        )?;
13556    }
13557    nodes.truncate(count);
13558    let node_type =
13559        |node: sys::CUgraphNode| -> Result<sys::CUgraphNodeType, Box<dyn std::error::Error>> {
13560            let mut ty = sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_EMPTY;
13561            unsafe {
13562                cu_try(
13563                    sys::cuGraphNodeGetType(node, &mut ty),
13564                    "fa-site NodeGetType",
13565                )?;
13566            }
13567            Ok(ty)
13568        };
13569    let memsets: Vec<sys::CUgraphNode> = {
13570        let mut v = Vec::new();
13571        for &node in &nodes {
13572            if node_type(node)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_MEMSET {
13573                v.push(node);
13574            }
13575        }
13576        v
13577    };
13578    if memsets.len() != 3 {
13579        return Ok(None);
13580    }
13581    // Single-stream capture makes the chain linear: follow dependent edges from each memset.
13582    let dependents =
13583        |node: sys::CUgraphNode| -> Result<Vec<sys::CUgraphNode>, Box<dyn std::error::Error>> {
13584            let mut n: usize = 0;
13585            unsafe {
13586                cu_try(
13587                    sys::cuGraphNodeGetDependentNodes_v2(
13588                        node,
13589                        std::ptr::null_mut(),
13590                        std::ptr::null_mut(),
13591                        &mut n,
13592                    ),
13593                    "fa-site GetDependentNodes(count)",
13594                )?;
13595            }
13596            let mut v: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); n];
13597            unsafe {
13598                cu_try(
13599                    sys::cuGraphNodeGetDependentNodes_v2(
13600                        node,
13601                        v.as_mut_ptr(),
13602                        std::ptr::null_mut(),
13603                        &mut n,
13604                    ),
13605                    "fa-site GetDependentNodes",
13606                )?;
13607            }
13608            v.truncate(n);
13609            Ok(v)
13610        };
13611    // The LAST memset is the one whose direct dependent is a kernel (fa); the other two are
13612    // ordered among themselves but interchangeable for width updates.
13613    let mut fa: Option<sys::CUgraphNode> = None;
13614    let mut last_memset: Option<sys::CUgraphNode> = None;
13615    for &ms in &memsets {
13616        for dep in dependents(ms)? {
13617            if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
13618                fa = Some(dep);
13619                last_memset = Some(ms);
13620            }
13621        }
13622    }
13623    let (Some(fa), Some(_last)) = (fa, last_memset) else {
13624        return Ok(None);
13625    };
13626    let mut combine: Option<sys::CUgraphNode> = None;
13627    for dep in dependents(fa)? {
13628        if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
13629            combine = Some(dep);
13630        }
13631    }
13632    let Some(combine) = combine else {
13633        return Ok(None);
13634    };
13635    // Read the fa launch geometry from its baked args (arg order pinned by fa_decode_dcw):
13636    // 6=hd 7=nh 8=nhkv 11=win 13=nsp 14=ski.
13637    let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
13638    unsafe {
13639        cu_try(
13640            sys::cuGraphKernelNodeGetParams_v2(fa, &mut params),
13641            "fa-site KernelNodeGetParams",
13642        )?;
13643    }
13644    let arg_i32 =
13645        |slot: usize| -> i32 { unsafe { *(*params.kernelParams.add(slot) as *const i32) } };
13646    let (hd, nh, nhkv, win) = (arg_i32(6), arg_i32(7), arg_i32(8), arg_i32(11));
13647    // Identify the o-partial memset (hd x wider than the m/l pair).
13648    let width_of = |node: sys::CUgraphNode| -> Result<usize, Box<dyn std::error::Error>> {
13649        let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
13650        unsafe {
13651            cu_try(
13652                sys::cuGraphMemsetNodeGetParams(node, &mut mp),
13653                "fa-site MemsetNodeGetParams",
13654            )?;
13655        }
13656        Ok(mp.width)
13657    };
13658    let mut widest = memsets[0];
13659    for &ms in &memsets[1..] {
13660        if width_of(ms)? > width_of(widest)? {
13661            widest = ms;
13662        }
13663    }
13664    let memset_m: Vec<sys::CUgraphNode> =
13665        memsets.iter().copied().filter(|&m| m != widest).collect();
13666    Ok(Some(TokenGraphFaSite {
13667        ctx,
13668        memset_o: widest,
13669        memset_m: [memset_m[0], memset_m[1]],
13670        fa,
13671        combine,
13672        window: win as usize,
13673        n_head: nh as usize,
13674        n_head_kv: nhkv as usize,
13675        head_dim: hd as usize,
13676    }))
13677}
13678
13679pub struct TokenGraph {
13680    exec: cudarc::driver::sys::CUgraphExec,
13681    parent: cudarc::driver::sys::CUgraph,
13682    _children: Vec<TokenGraphChild>,
13683    fa_sites: Vec<TokenGraphFaSite>,
13684}
13685
13686unsafe impl Send for TokenGraph {}
13687
13688impl TokenGraph {
13689    /// Retarget every fa site to a new bucket via exec param updates (M1 path) — replaces the
13690    /// per-bucket whole-graph rebuild (~55ms) with ~450 node updates (~1ms). Per site the
13691    /// bucket caps at the layer window; nsp/ski/gridDimY and the partial-pool memset widths
13692    /// move together so the exec always matches what a fresh build at `bucket` would bake.
13693    pub fn retarget_bucket(&mut self, bucket: usize) -> Result<(), Box<dyn std::error::Error>> {
13694        use cudarc::driver::sys;
13695        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
13696            if r == sys::CUresult::CUDA_SUCCESS {
13697                Ok(())
13698            } else {
13699                Err(format!("{what}: {r:?}").into())
13700            }
13701        }
13702        for site in &self.fa_sites {
13703            let layer_bucket = if site.window > 0 {
13704                bucket.min(site.window)
13705            } else {
13706                bucket
13707            };
13708            let sp = crate::fa_split_keys(layer_bucket, site.n_head_kv);
13709            let nsp = layer_bucket.div_ceil(sp).max(1);
13710            // fa kernel: nsp (slot 13), ski (slot 14), gridDimY = nsp.
13711            let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
13712            unsafe {
13713                cu_try(
13714                    sys::cuGraphKernelNodeGetParams_v2(site.fa, &mut params),
13715                    "retarget fa GetParams",
13716                )?;
13717                *(*params.kernelParams.add(13) as *mut i32) = nsp as i32;
13718                *(*params.kernelParams.add(14) as *mut i32) = sp as i32;
13719                params.gridDimY = nsp as u32;
13720                cu_try(
13721                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.fa, &params),
13722                    "retarget fa SetParams",
13723                )?;
13724            }
13725            // combine: nsp (slot 6).
13726            let mut cparams: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
13727            unsafe {
13728                cu_try(
13729                    sys::cuGraphKernelNodeGetParams_v2(site.combine, &mut cparams),
13730                    "retarget combine GetParams",
13731                )?;
13732                *(*cparams.kernelParams.add(6) as *mut i32) = nsp as i32;
13733                cu_try(
13734                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.combine, &cparams),
13735                    "retarget combine SetParams",
13736                )?;
13737            }
13738            // partial-pool memsets: o = nh*nsp*hd elements, m/l = nh*nsp.
13739            let set_width =
13740                |node: sys::CUgraphNode, width: usize| -> Result<(), Box<dyn std::error::Error>> {
13741                    let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
13742                    unsafe {
13743                        cu_try(
13744                            sys::cuGraphMemsetNodeGetParams(node, &mut mp),
13745                            "retarget memset GetParams",
13746                        )?;
13747                    }
13748                    mp.width = width;
13749                    unsafe {
13750                        cu_try(
13751                            sys::cuGraphExecMemsetNodeSetParams(self.exec, node, &mp, site.ctx),
13752                            "retarget memset SetParams",
13753                        )?;
13754                    }
13755                    Ok(())
13756                };
13757            set_width(site.memset_o, site.n_head * nsp * site.head_dim)?;
13758            set_width(site.memset_m[0], site.n_head * nsp)?;
13759            set_width(site.memset_m[1], site.n_head * nsp)?;
13760        }
13761        Ok(())
13762    }
13763
13764    pub fn launch(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
13765        use cudarc::driver::sys;
13766        let _main = e.gpu.enter_main()?;
13767        let r = unsafe { sys::cuGraphLaunch(self.exec, e.stream().cu_stream() as sys::CUstream) };
13768        if r != sys::CUresult::CUDA_SUCCESS {
13769            return Err(format!("token graph launch: {r:?}").into());
13770        }
13771        Ok(())
13772    }
13773}
13774
13775impl Drop for TokenGraph {
13776    fn drop(&mut self) {
13777        unsafe {
13778            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
13779            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
13780        }
13781    }
13782}
13783
13784std::thread_local! {
13785    static TOKEN_GRAPH_BUILDER: std::cell::RefCell<Option<TokenGraphBuilder>> =
13786        const { std::cell::RefCell::new(None) };
13787}
13788
13789/// Arm the thread-local builder (build mode) — the next `graph_section` calls capture.
13790pub fn token_graph_build_begin() -> Result<(), Box<dyn std::error::Error>> {
13791    let builder = TokenGraphBuilder::new()?;
13792    TOKEN_GRAPH_BUILDER.with(|cell| *cell.borrow_mut() = Some(builder));
13793    Ok(())
13794}
13795
13796/// Take the finished parent (ends build mode).
13797pub fn token_graph_build_finish() -> Result<TokenGraph, Box<dyn std::error::Error>> {
13798    let builder = TOKEN_GRAPH_BUILDER
13799        .with(|cell| cell.borrow_mut().take())
13800        .ok_or("token graph build was not begun")?;
13801    builder.finish()
13802}
13803
13804/// True while the thread-local builder is armed.
13805pub fn token_graph_building() -> bool {
13806    TOKEN_GRAPH_BUILDER.with(|cell| cell.borrow().is_some())
13807}
13808
13809/// The section annotation: eager mode runs the closure verbatim; build mode wraps it in a
13810/// stream capture on `engine`'s stream and records the child. Sections sharing a
13811/// `parallel_group` id fork from the same predecessor set and merge together. The closure
13812/// must be capture-safe (raw copies at cross-context seams, no host syncs, no events).
13813pub fn graph_section<F>(
13814    engine: &Engine,
13815    parallel_group: Option<u32>,
13816    f: F,
13817) -> Result<(), Box<dyn std::error::Error>>
13818where
13819    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
13820{
13821    graph_section_opts(engine, parallel_group, false, false, f)
13822}
13823
13824/// Serial section that ALSO joins every pending detached section (the SH1 consumer shape).
13825pub fn graph_section_absorbing<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
13826where
13827    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
13828{
13829    graph_section_opts(engine, None, false, true, f)
13830}
13831
13832/// `graph_section` with the DETACHED shape: forks from the current frontier (or the open
13833/// group base) and is joined only by the next serial section — never gates a group merge.
13834pub fn graph_section_detached<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
13835where
13836    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
13837{
13838    graph_section_opts(engine, None, true, false, f)
13839}
13840
13841pub fn graph_section_opts<F>(
13842    engine: &Engine,
13843    parallel_group: Option<u32>,
13844    detached: bool,
13845    absorb: bool,
13846    f: F,
13847) -> Result<(), Box<dyn std::error::Error>>
13848where
13849    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
13850{
13851    let building = token_graph_building();
13852    if !building {
13853        let mut f = f;
13854        return f();
13855    }
13856    let (child, ctx) = {
13857        let _main = engine.gpu.enter_main()?;
13858        let mut ctx: cudarc::driver::sys::CUcontext = std::ptr::null_mut();
13859        let r = unsafe { cudarc::driver::sys::cuCtxGetCurrent(&mut ctx) };
13860        if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
13861            return Err(format!("graph section ctx query: {r:?}").into());
13862        }
13863        let mut f = f;
13864        // NO WARMUP RUNS: section bodies carry device side effects (dcw appends, counter
13865        // incs) that a warmup would really execute — the len_d-drift crash of 2026-08-21.
13866        let (child, _retained) = engine.capture_graph_retained_nowarm(|_| f())?;
13867        (child, ctx)
13868    };
13869    TOKEN_GRAPH_BUILDER.with(|cell| {
13870        cell.borrow_mut()
13871            .as_mut()
13872            .expect("builder checked above")
13873            .push_child(child, parallel_group, detached, absorb, ctx)
13874    })
13875}