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
14const FP8_BLOCK: usize = 128;
15const NATIVE_P2P_PROBE_WORDS: usize = 4096;
16const STEP_GROUPED_FP8_EXPERTS: usize = 288;
17const STEP_GROUPED_FP8_TOP_K: usize = 8;
18const STEP_GROUPED_FP8_WIDTH: usize = 1280;
19
20fn validate_step_expert_activation_limit(limit: Option<f32>) -> Result<(), String> {
21    if let Some(limit) = limit {
22        if !limit.is_finite() || limit <= 0.0 {
23            return Err(format!(
24                "Step routed-expert activation limit must be positive and finite, got {limit}"
25            ));
26        }
27    }
28    Ok(())
29}
30
31/// Host-canonical Step routed-expert SwiGLU operation.
32///
33/// Step's final routed layers clamp the linear arm symmetrically and the SiLU arm only above.
34/// Keeping this scalar order explicit also defines the device-host-exact CUDA gate.
35/// Raw stream-ordered device copy for capture-safe cross-context seams (cudarc's slice-use
36/// tracking creates capture-illegal dependencies there). Pointers must be pre-cached with
37/// their owners' streams; bytes flow identically to the tracked copy.
38/// MEMRA_OPROJ_DIRECT=1 (o-proj direct join, default OFF until gated): peer ranks write
39/// their fused O partial OVER P2P into a root-resident buffer (UVA kernel stores), and the
40/// model engine adds the two partials itself — the root stream leaves the join entirely
41/// (no peer pull copy, no root add, no second event hop, no final 16KB ownership copy).
42/// Reduction order and kernel programs are unchanged, so the row is BIT-IDENTICAL.
43/// MEMRA_MOE_DIRECT=1 (moe direct join, default OFF until gated): the o-proj direct-join
44/// recipe on the expert combine — peer ranks' accumulators live root-side (the axpy twin
45/// register-accumulates and stores ONCE, so the P2P cost is a single 16KB store pass), and
46/// the model engine adds the two shard rows itself. Operand order matches root's add:
47/// BIT-IDENTICAL.
48/// MEMRA_ROUTES_PRESTAGE=1 (default OFF until gated): stage the shared layer input to
49/// every rank and quantize it BEFORE the router runs — neither depends on the selection,
50/// so the rank streams' pull+quantize overlaps dev0's router gemv+topk instead of chaining
51/// behind it (the router->quantize and axpy->add gap edges). Same copies, same quantize
52/// kernel, same operands: BIT-IDENTICAL.
53pub(crate) fn routes_prestage_on() -> bool {
54    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
55    *ON.get_or_init(|| std::env::var("MEMRA_ROUTES_PRESTAGE").as_deref() == Ok("1"))
56}
57
58/// MEMRA_FENCE_MEMOPS=1 (default OFF until gated): the moe direct join's two event
59/// fences become cuStreamWriteValue32/cuStreamWaitValue32 doorbells — hardware stream
60/// memops with lower signal->wake latency than cross-device cuStreamWaitEvent. Ordering:
61/// PCIe posted writes from one device arrive in order, so rank1's accumulator stores are
62/// visible before its flag write lands; e's GEQ wait then covers them. Falls back to
63/// events when the device rejects stream memops. Scheduling-only: BIT-IDENTICAL values.
64/// MEMRA_LEN_MIRROR_LAZY=1 (default OFF until gated): skip redundant per-layer 4B len
65/// htods — the local device mirror is unread in TP decode, and under FUSE_ROPE_APPEND the
66/// fused append's atomicInc owns the rank counters. Every one of those tiny copies is a
67/// compute->copy engine turnaround in the middle of the layer stream.
68/// MEMRA_RANK0_MERGE=1 (default OFF until gated): same-device rank0 rides e's stream via
69/// the runtime redirect — see decode_step_h.
70/// MEMRA_OPROJ_TAIL=1 (default OFF until gated): the o-proj direct-join add is DEFERRED —
71/// the finish arm keeps its waits, stores the two partial pointers here, and the residual
72/// add_rms_norm consumer composes mixed = a0+a1 in-register (join_add_rms_norm, verbatim
73/// program: BIT-IDENTICAL). The returned `mixed` buffer is UNWRITTEN in this mode; its
74/// only live consumer is the residual_norm_ffn seam, which takes the handoff.
75pub(crate) fn oproj_tail_on() -> bool {
76    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
77    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_TAIL").as_deref() == Ok("1"))
78}
79thread_local! {
80    static OPROJ_TAIL_PENDING: std::cell::Cell<Option<(u64, u64)>> =
81        const { std::cell::Cell::new(None) };
82}
83thread_local! {
84    /// The deferral is legal ONLY under callers whose walk flows into
85    /// residual_norm_ffn (decode_step_h / decode_step_chain arm this) — the verify
86    /// prefill reaches the same finish and would consume unwritten `mixed` otherwise
87    /// (M2-MISMATCH receipt: prefill argmax corrupted while decode stayed exact).
88    static OPROJ_TAIL_ELIGIBLE: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
89}
90/// RAII eligibility scope for the o-proj tail deferral.
91pub(crate) struct OprojTailScope(());
92pub(crate) fn oproj_tail_scope() -> OprojTailScope {
93    OPROJ_TAIL_ELIGIBLE.with(|c| c.set(true));
94    OprojTailScope(())
95}
96impl Drop for OprojTailScope {
97    fn drop(&mut self) {
98        OPROJ_TAIL_ELIGIBLE.with(|c| c.set(false));
99        // A leftover un-consumed handoff must never leak across calls.
100        OPROJ_TAIL_PENDING.with(|c| c.set(None));
101    }
102}
103thread_local! {
104    /// T-COLUMN verify select: the verify driver sets the column before each per-column
105    /// attention call; decode_v2_input_qkv takes it (once) and selects from the slabs.
106    static VERIFY_TCOL: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
107}
108pub(crate) fn set_verify_tcol(c: Option<usize>) {
109    VERIFY_TCOL.with(|x| x.set(c));
110}
111pub(crate) fn take_verify_tcol() -> Option<usize> {
112    VERIFY_TCOL.with(|x| x.take())
113}
114
115/// MEMRA_TCOL_OPROJ=1 (spec verify): defer each column's o_proj out of the per-column
116/// walk — the finish seam stashes the column's `gated` rows instead of running the
117/// per-column finish choreography (rank events, P2P join, engine handoff), and one
118/// weight-amortized b4_tcol per rank + one elementwise join produce every column's
119/// `mixed` afterwards. Bit-exact per column: the tcol kernel is the t=1 b4 program per
120/// column, and the slab join adds the same operand values elementwise.
121pub(crate) fn tcol_oproj_on() -> bool {
122    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
123    *ON.get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ").as_deref() == Ok("1"))
124}
125thread_local! {
126    /// The verify driver arms the column before each per-column attention call; the
127    /// finish seam takes it (once). Stashed=true reports the defer actually happened
128    /// (the seam falls back to the normal finish when the config is ineligible).
129    static TCOL_OPROJ_DEFER: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
130    static TCOL_OPROJ_STASHED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
131}
132pub(crate) fn set_tcol_oproj_defer(c: Option<usize>) {
133    TCOL_OPROJ_DEFER.with(|x| x.set(c));
134}
135pub(crate) fn take_tcol_oproj_defer() -> Option<usize> {
136    TCOL_OPROJ_DEFER.with(|x| x.take())
137}
138pub(crate) fn set_tcol_oproj_stashed() {
139    TCOL_OPROJ_STASHED.with(|x| x.set(true));
140}
141pub(crate) fn take_tcol_oproj_stashed() -> bool {
142    TCOL_OPROJ_STASHED.with(|x| x.replace(false))
143}
144
145pub(crate) fn oproj_tail_eligible() -> bool {
146    OPROJ_TAIL_ELIGIBLE.with(|c| c.get())
147}
148pub(crate) fn take_oproj_tail() -> Option<(u64, u64)> {
149    OPROJ_TAIL_PENDING.with(|c| c.take())
150}
151pub(crate) fn set_oproj_tail(v: (u64, u64)) {
152    OPROJ_TAIL_PENDING.with(|c| c.set(Some(v)));
153}
154
155pub(crate) fn rank0_merge_on() -> bool {
156    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
157    *ON.get_or_init(|| std::env::var("MEMRA_RANK0_MERGE").as_deref() == Ok("1"))
158}
159
160pub(crate) fn len_mirror_lazy_on() -> bool {
161    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
162    *ON.get_or_init(|| std::env::var("MEMRA_LEN_MIRROR_LAZY").as_deref() == Ok("1"))
163}
164
165pub(crate) fn fence_memops_on() -> bool {
166    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
167    *ON.get_or_init(|| std::env::var("MEMRA_FENCE_MEMOPS").as_deref() == Ok("1"))
168}
169
170pub(crate) fn moe_direct_on() -> bool {
171    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
172    *ON.get_or_init(|| std::env::var("MEMRA_MOE_DIRECT").as_deref() == Ok("1"))
173}
174
175/// MEMRA_SEL_DOWN8=1: fuse the NVFP4 down sweep with the route-weight combine and run one
176/// warp per routed slot (the q8 `down8 w8` occupancy arm). Bit-identical; default OFF until
177/// receipted on this bank family.
178/// MEMRA_SEL_MIRROR=1: the per-rank routed-selection pull runs as ONE `moe_sel_w_mirror`
179/// launch instead of two 32-byte D2D copies, and when every consuming rank shares e's device
180/// the intermediate e-context staging pair is skipped entirely (the caller's sel/route_w rows
181/// are process-persistent, so the ranks read them directly). Bit-identical: same bytes, one
182/// fewer hop. Refused under the graph door, whose captured copies need the fixed staging
183/// addresses. Default OFF until receipted.
184/// MEMRA_FENCE_RANK1=1: the peer rank rings a doorbell in ROOT memory with a kernel store
185/// (`memra_ring_flag`) and the model engine waits it with a SAME-DEVICE stream memop, instead
186/// of waiting a cross-device event. Completes the half the memops receipt left open (peer
187/// memops are rejected; peer kernel stores are the direct-join mechanism). Ordering only —
188/// values are untouched. Requires MEMRA_FENCE_MEMOPS=1 (it owns the flag allocation).
189pub(crate) fn fence_rank1_on() -> bool {
190    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
191    *ON.get_or_init(|| std::env::var("MEMRA_FENCE_RANK1").as_deref() == Ok("1"))
192}
193
194/// MEMRA_SPEC_FA2=1 (the DSpark verify lesson): the T=2 verify walk defers each column's
195/// ATTENTION CORE — the dcw arm appends the column's K/V and stashes its post-rope q and
196/// gate rows, then ONE fa_decode_dcw2 per rank walks the KV stream once for both columns
197/// (per-row causal bounds; bit-identical per row under the equal-partition guard), the
198/// per-row combine writes both gated rows, and the o_proj join runs on the TCOL slabs.
199pub(crate) fn spec_fa2_on() -> bool {
200    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
201    *ON.get_or_init(|| std::env::var("MEMRA_SPEC_FA2").as_deref() == Ok("1"))
202}
203thread_local! {
204    /// The verify driver arms the column before each per-column attention call; the dcw
205    /// arm takes it (once) and stashes q/gate instead of running fa+finish.
206    static SPEC_FA2_DEFER: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
207    static SPEC_FA2_STASHED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
208}
209pub(crate) fn set_spec_fa2_defer(c: Option<usize>) {
210    SPEC_FA2_DEFER.with(|x| x.set(c));
211}
212pub(crate) fn take_spec_fa2_defer() -> Option<usize> {
213    SPEC_FA2_DEFER.with(|x| x.take())
214}
215pub(crate) fn set_spec_fa2_stashed() {
216    SPEC_FA2_STASHED.with(|x| x.set(true));
217}
218pub(crate) fn take_spec_fa2_stashed() -> bool {
219    SPEC_FA2_STASHED.with(|x| x.replace(false))
220}
221
222pub(crate) fn sel_mirror_on() -> bool {
223    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
224    *ON.get_or_init(|| std::env::var("MEMRA_SEL_MIRROR").as_deref() == Ok("1"))
225}
226
227pub(crate) fn sel_down8_on() -> bool {
228    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
229    *ON.get_or_init(|| std::env::var("MEMRA_SEL_DOWN8").as_deref() == Ok("1"))
230}
231
232pub(crate) fn oproj_direct_on() -> bool {
233    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
234    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_DIRECT").as_deref() == Ok("1"))
235}
236
237pub(crate) fn raw_copy_bytes(
238    dst: u64,
239    src: u64,
240    bytes: usize,
241    engine: &Engine,
242) -> Result<(), Box<dyn std::error::Error>> {
243    use cudarc::driver::sys;
244    let r = unsafe {
245        sys::cuMemcpyAsync(
246            dst as sys::CUdeviceptr,
247            src as sys::CUdeviceptr,
248            bytes,
249            engine.stream().cu_stream() as sys::CUstream,
250        )
251    };
252    if r == sys::CUresult::CUDA_SUCCESS {
253        Ok(())
254    } else {
255        Err(format!("raw_copy_bytes: {r:?}").into())
256    }
257}
258
259pub fn step_expert_activation_host(gate: f32, up: f32, limit: Option<f32>) -> f32 {
260    let silu = gate / (1.0 + (-gate).exp());
261    match limit {
262        Some(limit) => silu.min(limit) * up.clamp(-limit, limit),
263        None => silu * up,
264    }
265}
266
267#[derive(Debug, Clone, PartialEq, Eq)]
268struct ExpertOwnerRoutes {
269    rank: usize,
270    selected: Vec<usize>,
271    token_rows: Vec<usize>,
272    global_pairs: Vec<usize>,
273}
274
275fn partition_expert_owner_routes(
276    expert_count: usize,
277    ranks: usize,
278    tokens: usize,
279    experts_per_token: usize,
280    selected: &[usize],
281) -> Result<Vec<ExpertOwnerRoutes>, String> {
282    if expert_count == 0
283        || ranks == 0
284        || tokens == 0
285        || experts_per_token == 0
286        || expert_count % ranks != 0
287    {
288        return Err(format!(
289            "invalid expert-owner route geometry experts={expert_count} ranks={ranks} \
290             tokens={tokens} experts_per_token={experts_per_token}"
291        ));
292    }
293    let pairs = tokens
294        .checked_mul(experts_per_token)
295        .ok_or("expert-owner route count overflow")?;
296    if selected.len() != pairs {
297        return Err(format!(
298            "expert-owner routes {} != {tokens}x{experts_per_token} ({pairs})",
299            selected.len()
300        ));
301    }
302    let per_rank = expert_count / ranks;
303    let mut owners = (0..ranks)
304        .map(|rank| ExpertOwnerRoutes {
305            rank,
306            selected: Vec::new(),
307            token_rows: Vec::new(),
308            global_pairs: Vec::new(),
309        })
310        .collect::<Vec<_>>();
311    for (pair, &expert) in selected.iter().enumerate() {
312        if expert >= expert_count {
313            return Err(format!(
314                "expert-owner route {pair} selects expert {expert} outside 0..{expert_count}"
315            ));
316        }
317        let rank = expert / per_rank;
318        owners[rank].selected.push(expert - rank * per_rank);
319        owners[rank].token_rows.push(pair / experts_per_token);
320        owners[rank].global_pairs.push(pair);
321    }
322    Ok(owners)
323}
324
325fn validate_step_grouped_owner_routes(
326    expert_count: usize,
327    tokens: usize,
328    selected: &[usize],
329) -> Result<usize, String> {
330    if expert_count != STEP_GROUPED_FP8_EXPERTS || tokens == 0 {
331        return Err(format!(
332            "official Step owner-grouped FP8 requires {} experts and nonzero tokens, got \
333             experts={expert_count} tokens={tokens}",
334            STEP_GROUPED_FP8_EXPERTS
335        ));
336    }
337    let pairs = tokens
338        .checked_mul(STEP_GROUPED_FP8_TOP_K)
339        .ok_or("official Step owner-grouped FP8 route count overflow")?;
340    if selected.len() != pairs {
341        return Err(format!(
342            "official Step owner-grouped FP8 routes {} != {tokens}x{} ({pairs})",
343            selected.len(),
344            STEP_GROUPED_FP8_TOP_K,
345        ));
346    }
347    for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
348        let mut unique = routes.to_vec();
349        unique.sort_unstable();
350        unique.dedup();
351        if unique.len() != STEP_GROUPED_FP8_TOP_K {
352            return Err(format!(
353                "official Step owner-grouped FP8 token {token} routes are not top-8 unique: \
354                 {routes:?}"
355            ));
356        }
357    }
358    Ok(pairs)
359}
360
361#[derive(Debug, Clone, Copy, PartialEq, Eq)]
362struct WeightedRouteCombineShape {
363    pairs: usize,
364    max_pairs: usize,
365}
366
367fn validate_weighted_route_combine(
368    width: usize,
369    experts_per_token: usize,
370    max_tokens: usize,
371    tokens: usize,
372    owner_global_pairs: &[&[usize]],
373    route_weights: &[f32],
374) -> Result<WeightedRouteCombineShape, String> {
375    if width == 0
376        || experts_per_token == 0
377        || max_tokens == 0
378        || tokens == 0
379        || tokens > max_tokens
380        || width > i32::MAX as usize
381        || experts_per_token > i32::MAX as usize
382        || tokens > i32::MAX as usize
383    {
384        return Err(format!(
385            "invalid weighted route combine geometry width={width} experts_per_token=\
386             {experts_per_token} tokens={tokens}/{max_tokens}"
387        ));
388    }
389    let pairs = tokens
390        .checked_mul(experts_per_token)
391        .ok_or("weighted route combine pair count overflow")?;
392    let max_pairs = max_tokens
393        .checked_mul(experts_per_token)
394        .ok_or("weighted route combine capacity overflow")?;
395    if route_weights.len() != pairs || !route_weights.iter().all(|weight| weight.is_finite()) {
396        return Err(format!(
397            "weighted route combine weights {} != pairs {pairs} or contain a non-finite value",
398            route_weights.len()
399        ));
400    }
401    let mut seen = vec![false; pairs];
402    let mut observed = 0usize;
403    for pairs_for_owner in owner_global_pairs {
404        observed = observed
405            .checked_add(pairs_for_owner.len())
406            .ok_or("weighted route combine observed pair count overflow")?;
407        for &pair in *pairs_for_owner {
408            if pair >= pairs || std::mem::replace(&mut seen[pair], true) {
409                return Err(format!(
410                    "weighted route combine pair {pair} is outside 0..{pairs} or duplicated"
411                ));
412            }
413        }
414    }
415    if observed != pairs || seen.iter().any(|present| !present) {
416        return Err(format!(
417            "weighted route combine owner schedules cover {observed} of {pairs} canonical pairs"
418        ));
419    }
420    Ok(WeightedRouteCombineShape { pairs, max_pairs })
421}
422
423fn cache_rank_rows(
424    rows: &[u8],
425    tokens: usize,
426    local_token_bytes: usize,
427    ranks: usize,
428    rank: usize,
429) -> Result<Vec<u8>, String> {
430    if ranks == 0 || rank >= ranks {
431        return Err(format!(
432            "TP cache rank {rank} is outside a {ranks}-rank layout"
433        ));
434    }
435    let global_token_bytes = local_token_bytes
436        .checked_mul(ranks)
437        .ok_or("TP cache global token-byte overflow")?;
438    let expected = tokens
439        .checked_mul(global_token_bytes)
440        .ok_or("TP cache row-byte overflow")?;
441    if rows.len() != expected {
442        return Err(format!(
443            "TP cache rows contain {} bytes, expected {tokens}x{global_token_bytes}={expected}",
444            rows.len()
445        ));
446    }
447    let mut shard = Vec::with_capacity(tokens * local_token_bytes);
448    for token in 0..tokens {
449        let start = token * global_token_bytes + rank * local_token_bytes;
450        shard.extend_from_slice(&rows[start..start + local_token_bytes]);
451    }
452    Ok(shard)
453}
454
455fn parse_step_tp_native_p2p(value: Option<&str>) -> Result<bool, String> {
456    match value {
457        None | Some("") | Some("0") => Ok(false),
458        Some("1") => Ok(true),
459        Some(value) => Err(format!(
460            "MEMRA_STEP_TP_NATIVE_P2P={value:?} is invalid; expected 0 or 1"
461        )),
462    }
463}
464
465pub fn step_tp_native_p2p_enabled() -> Result<bool, String> {
466    parse_step_tp_native_p2p(std::env::var("MEMRA_STEP_TP_NATIVE_P2P").ok().as_deref())
467}
468
469fn parse_step_tp_bulk_p2p(value: Option<&str>) -> Result<bool, String> {
470    match value {
471        None | Some("") | Some("0") => Ok(false),
472        Some("1") => Ok(true),
473        Some(value) => Err(format!(
474            "MEMRA_STEP_TP_BULK_P2P={value:?} is invalid; expected 0 or 1"
475        )),
476    }
477}
478
479pub fn step_tp_bulk_p2p_enabled() -> Result<bool, String> {
480    parse_step_tp_bulk_p2p(std::env::var("MEMRA_STEP_TP_BULK_P2P").ok().as_deref())
481}
482
483fn parse_step_ep_device_arithmetic(value: Option<&str>) -> Result<bool, String> {
484    match value {
485        None | Some("") | Some("0") => Ok(false),
486        Some("1") => Ok(true),
487        Some(value) => Err(format!(
488            "MEMRA_STEP_EP_DEVICE_ARITHMETIC={value:?} is invalid; expected 0 or 1"
489        )),
490    }
491}
492
493fn parse_step_nvfp4_dev_routes(value: Option<&str>) -> Result<bool, String> {
494    match value {
495        None | Some("") | Some("0") => Ok(false),
496        Some("1") => Ok(true),
497        Some(value) => Err(format!(
498            "MEMRA_STEP_NVFP4_DEV_ROUTES={value:?} is invalid; expected 0 or 1"
499        )),
500    }
501}
502
503/// Opt-in door for the device-resident NVFP4 TP routed-expert decode program. Default OFF; the
504/// host-canonical program remains the oracle until the device path carries its own gates.
505pub fn step_nvfp4_dev_routes_enabled() -> Result<bool, String> {
506    parse_step_nvfp4_dev_routes(std::env::var("MEMRA_STEP_NVFP4_DEV_ROUTES").ok().as_deref())
507}
508
509pub fn step_ep_device_arithmetic_enabled() -> Result<bool, String> {
510    parse_step_ep_device_arithmetic(
511        std::env::var("MEMRA_STEP_EP_DEVICE_ARITHMETIC")
512            .ok()
513            .as_deref(),
514    )
515}
516
517fn parse_step_tp_f32_mirror(value: Option<&str>) -> Result<bool, String> {
518    match value {
519        None | Some("") | Some("0") => Ok(false),
520        Some("1") => Ok(true),
521        Some(value) => Err(format!(
522            "MEMRA_STEP_TP_F32_MIRROR={value:?} is invalid; expected 0 or 1"
523        )),
524    }
525}
526
527pub fn step_tp_f32_mirror_enabled() -> Result<bool, String> {
528    parse_step_tp_f32_mirror(std::env::var("MEMRA_STEP_TP_F32_MIRROR").ok().as_deref())
529}
530
531fn parse_step_tp_decode_v2(value: Option<&str>) -> Result<bool, String> {
532    match value {
533        None | Some("") | Some("0") => Ok(false),
534        Some("1") => Ok(true),
535        Some(value) => Err(format!(
536            "MEMRA_STEP_TP_DECODE_V2={value:?} is invalid; expected 0 or 1"
537        )),
538    }
539}
540
541/// The v2 rank-local Step decode-attention driver: persistent workspaces, evented cross-stream
542/// ordering, and a root-device O reduction — same kernels, values, and canonical reduction order
543/// as the v1 driver (it requires the F32 mirror so no per-call weight expansion exists on either
544/// side of the comparison).
545pub fn step_tp_decode_v2_enabled() -> Result<bool, String> {
546    parse_step_tp_decode_v2(std::env::var("MEMRA_STEP_TP_DECODE_V2").ok().as_deref())
547}
548
549fn parse_step_tp_qkv_fused(value: Option<&str>) -> Result<bool, String> {
550    match value {
551        None | Some("") | Some("0") => Ok(false),
552        Some("1") => Ok(true),
553        Some(value) => Err(format!(
554            "MEMRA_STEP_TP_QKV_FUSED={value:?} is invalid; expected 0 or 1"
555        )),
556    }
557}
558
559fn parse_step_tp_dev_router(value: Option<&str>) -> Result<bool, String> {
560    match value {
561        None | Some("") | Some("0") => Ok(false),
562        Some("1") => Ok(true),
563        Some(value) => Err(format!(
564            "MEMRA_STEP_TP_DEV_ROUTER={value:?} is invalid; expected 0 or 1"
565        )),
566    }
567}
568
569/// Device-side sigmoid top-k routing for the TP device-IO expert program: the per-layer host
570/// logits readback (the last per-layer host sync) disappears. Selection tie-breaking may
571/// differ from the host router — NUMERIC-CLASS door, run-gen argmax gate + boot battery.
572pub fn step_tp_dev_router_enabled() -> Result<bool, String> {
573    parse_step_tp_dev_router(std::env::var("MEMRA_STEP_TP_DEV_ROUTER").ok().as_deref())
574}
575
576fn parse_step_tp_graph(value: Option<&str>) -> Result<bool, String> {
577    match value {
578        None | Some("") | Some("0") => Ok(false),
579        Some("1") => Ok(true),
580        Some(value) => Err(format!(
581            "MEMRA_STEP_TP_GRAPH={value:?} is invalid; expected 0 or 1"
582        )),
583    }
584}
585
586fn parse_step_tp_dcw(value: Option<&str>) -> Result<bool, String> {
587    match value {
588        None | Some("") | Some("0") => Ok(false),
589        Some("1") => Ok(true),
590        Some(value) => Err(format!(
591            "MEMRA_STEP_TP_DCW={value:?} is invalid; expected 0 or 1"
592        )),
593    }
594}
595
596/// Device-counter attention path (graph increment A run EAGERLY): append at len_d - base_d,
597/// inc_i32, fa over the counter-derived window — with bucket = the effective t_kv this is
598/// bit-identical to the host-row + kvmod path (the one-partition law), and it is the exact
599/// child content the capture wraps. Rebase tokens and sub-vec-floor contexts fall back.
600pub fn step_tp_dcw_enabled() -> Result<bool, String> {
601    parse_step_tp_dcw(std::env::var("MEMRA_STEP_TP_DCW").ok().as_deref())
602}
603
604/// CUDA-graph door for the shape-stable TP segments (first increment: the device-routed
605/// expert program — per-layer multi-device parents built from per-rank children, launched on
606/// the model engine's stream; zero per-token node updates). Mechanism proven by
607/// tp_graph_probe. VALUE-IDENTICAL: the graphs replay exactly the eager kernel/copy sequence.
608pub fn step_tp_graph_enabled() -> Result<bool, String> {
609    parse_step_tp_graph(std::env::var("MEMRA_STEP_TP_GRAPH").ok().as_deref())
610}
611
612/// Fused single-launch QKV projection inside the v2 decode driver — a NUMERIC-CLASS door
613/// (per-row deterministic tree reduce instead of the chunked cuBLASLt program), default OFF,
614/// gated by the run-gen argmax gate + boot battery like MEMRA_STEP_NVFP4_DEV_ROUTES.
615pub fn step_tp_qkv_fused_enabled() -> Result<bool, String> {
616    parse_step_tp_qkv_fused(std::env::var("MEMRA_STEP_TP_QKV_FUSED").ok().as_deref())
617}
618
619#[derive(Debug, Clone, PartialEq, Eq)]
620pub struct StepEpLayerSpec {
621    pub layer: usize,
622    pub devices: Vec<usize>,
623}
624
625pub type StepTpLayerSpec = StepEpLayerSpec;
626
627fn parse_step_layer_specs(
628    flag: &str,
629    value: Option<&str>,
630    allow_full_model: bool,
631) -> Result<Vec<StepEpLayerSpec>, String> {
632    let Some(value) = value else {
633        return Ok(Vec::new());
634    };
635    if value.is_empty() || value == "0" {
636        return Ok(Vec::new());
637    }
638
639    let mut specs = Vec::new();
640    for item in value.split(';') {
641        let (layers, devices) = item.split_once('@').ok_or_else(|| {
642            let layers = if allow_full_model {
643                "LAYER[-LAYER] or all"
644            } else {
645                "LAYER[-LAYER]"
646            };
647            format!("{flag} must be {layers}@DEVICE,DEVICE[;...]")
648        })?;
649        let (first, last) = if layers == "all" {
650            if !allow_full_model {
651                return Err(format!(
652                    "{flag} does not support the full-model shorthand; assign routed layers \
653                     explicitly"
654                ));
655            }
656            (0, STEP37_TRUNK_LAYERS - 1)
657        } else {
658            match layers.split_once('-') {
659                Some((first, last)) => {
660                    let first = first
661                        .parse::<usize>()
662                        .map_err(|_| format!("{flag} layer {first:?} is not an integer"))?;
663                    let last = last
664                        .parse::<usize>()
665                        .map_err(|_| format!("{flag} layer {last:?} is not an integer"))?;
666                    if first > last {
667                        return Err(format!("{flag} layer range {first}-{last} is reversed"));
668                    }
669                    if last - first + 1 > 128 {
670                        return Err(format!(
671                            "{flag} layer range {first}-{last} exceeds the 128-layer parser cap"
672                        ));
673                    }
674                    (first, last)
675                }
676                None => {
677                    let layer = layers
678                        .parse::<usize>()
679                        .map_err(|_| format!("{flag} layer {layers:?} is not an integer"))?;
680                    (layer, layer)
681                }
682            }
683        };
684        let devices = devices
685            .split(',')
686            .map(|device| {
687                device
688                    .parse::<usize>()
689                    .map_err(|_| format!("{flag} device {device:?} is not an integer"))
690            })
691            .collect::<Result<Vec<_>, _>>()?;
692        if !(2..=8).contains(&devices.len()) {
693            return Err(format!(
694                "{flag} requires 2..=8 devices, got {}",
695                devices.len()
696            ));
697        }
698        let mut unique = devices.clone();
699        unique.sort_unstable();
700        unique.dedup();
701        if unique.len() != devices.len() {
702            return Err(format!("{flag} devices must be distinct, got {devices:?}"));
703        }
704        for layer in first..=last {
705            if specs
706                .iter()
707                .any(|existing: &StepEpLayerSpec| existing.layer == layer)
708            {
709                return Err(format!("{flag} assigns layer {layer} more than once"));
710            }
711            specs.push(StepEpLayerSpec {
712                layer,
713                devices: devices.clone(),
714            });
715        }
716    }
717    Ok(specs)
718}
719
720pub fn parse_step_ep_layer_specs(value: Option<&str>) -> Result<Vec<StepEpLayerSpec>, String> {
721    parse_step_layer_specs("MEMRA_STEP_EP", value, false)
722}
723
724pub fn step_ep_layer_specs() -> Result<Vec<StepEpLayerSpec>, String> {
725    parse_step_ep_layer_specs(std::env::var("MEMRA_STEP_EP").ok().as_deref())
726}
727
728pub fn parse_step_tp_layer_specs(value: Option<&str>) -> Result<Vec<StepTpLayerSpec>, String> {
729    parse_step_layer_specs("MEMRA_STEP_TP", value, true)
730}
731
732pub fn step_tp_layer_specs() -> Result<Vec<StepTpLayerSpec>, String> {
733    parse_step_tp_layer_specs(std::env::var("MEMRA_STEP_TP").ok().as_deref())
734}
735
736#[derive(Clone, Copy)]
737pub struct E4m3BlockMatrix<'a> {
738    pub codes: &'a [u8],
739    pub scales: &'a [f32],
740    pub out_features: usize,
741    pub in_features: usize,
742}
743
744impl E4m3BlockMatrix<'_> {
745    fn validate(&self) -> Result<(), String> {
746        let code_count = self
747            .out_features
748            .checked_mul(self.in_features)
749            .ok_or_else(|| "E4M3 matrix size overflow".to_string())?;
750        if self.codes.len() != code_count {
751            return Err(format!(
752                "E4M3 code count {} != {}x{} ({code_count})",
753                self.codes.len(),
754                self.out_features,
755                self.in_features,
756            ));
757        }
758        let scale_count =
759            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
760        if self.scales.len() != scale_count {
761            return Err(format!(
762                "E4M3 scale count {} != {scale_count} for {}x{}",
763                self.scales.len(),
764                self.out_features,
765                self.in_features,
766            ));
767        }
768        if !self
769            .scales
770            .iter()
771            .all(|scale| scale.is_finite() && *scale > 0.0)
772        {
773            return Err("E4M3 scale grid contains a non-finite or non-positive value".to_string());
774        }
775        Ok(())
776    }
777}
778
779#[derive(Clone, Copy)]
780pub struct E4m3ExpertBank<'a> {
781    pub codes: &'a [u8],
782    pub scales: &'a [f32],
783    pub expert_count: usize,
784    pub out_features: usize,
785    pub in_features: usize,
786}
787
788impl E4m3ExpertBank<'_> {
789    fn validate(&self) -> Result<(), String> {
790        if self.expert_count == 0 {
791            return Err("E4M3 expert bank is empty".to_string());
792        }
793        let code_stride = self
794            .out_features
795            .checked_mul(self.in_features)
796            .ok_or_else(|| "E4M3 expert code stride overflow".to_string())?;
797        let code_count = self
798            .expert_count
799            .checked_mul(code_stride)
800            .ok_or_else(|| "E4M3 expert code count overflow".to_string())?;
801        if self.codes.len() != code_count {
802            return Err(format!(
803                "E4M3 expert code count {} != {}x{} ({code_count})",
804                self.codes.len(),
805                self.expert_count,
806                code_stride,
807            ));
808        }
809        let scale_stride =
810            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
811        let scale_count = self
812            .expert_count
813            .checked_mul(scale_stride)
814            .ok_or_else(|| "E4M3 expert scale count overflow".to_string())?;
815        if self.scales.len() != scale_count {
816            return Err(format!(
817                "E4M3 expert scale count {} != {}x{} ({scale_count})",
818                self.scales.len(),
819                self.expert_count,
820                scale_stride,
821            ));
822        }
823        if !self
824            .scales
825            .iter()
826            .all(|scale| scale.is_finite() && *scale > 0.0)
827        {
828            return Err(
829                "E4M3 expert scale grid contains a non-finite or non-positive value".to_string(),
830            );
831        }
832        Ok(())
833    }
834
835    pub fn expert(&self, expert: usize) -> Result<E4m3BlockMatrix<'_>, String> {
836        if expert >= self.expert_count {
837            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
838        }
839        let code_stride = self.out_features * self.in_features;
840        let scale_stride =
841            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
842        Ok(E4m3BlockMatrix {
843            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
844            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
845            out_features: self.out_features,
846            in_features: self.in_features,
847        })
848    }
849}
850
851pub struct ColumnParallelResult {
852    pub gathered: Vec<f32>,
853    pub rank_outputs: Vec<Vec<f32>>,
854}
855
856pub struct RowParallelResult {
857    pub reduced: Vec<f32>,
858    pub rank_partials: Vec<Vec<f32>>,
859}
860
861#[derive(Clone, Copy)]
862pub struct Bf16Matrix<'a> {
863    pub bytes: &'a [u8],
864    pub out_features: usize,
865    pub in_features: usize,
866}
867
868impl Bf16Matrix<'_> {
869    pub fn validate(&self) -> Result<(), String> {
870        if self.out_features == 0 || self.in_features == 0 {
871            return Err("BF16 matrix dimensions must be nonzero".into());
872        }
873        let expected = self
874            .out_features
875            .checked_mul(self.in_features)
876            .and_then(|values| values.checked_mul(2))
877            .ok_or("BF16 matrix byte count overflow")?;
878        if self.bytes.len() != expected {
879            return Err(format!(
880                "BF16 matrix bytes {} != {}x{}x2 ({expected})",
881                self.bytes.len(),
882                self.out_features,
883                self.in_features,
884            ));
885        }
886        Ok(())
887    }
888}
889
890struct ResidentE4m3Rank {
891    codes: CudaSlice<u8>,
892    scales: CudaSlice<f32>,
893    out_features: usize,
894    in_features: usize,
895}
896
897enum ResidentBf16Weight {
898    Bf16(CudaSlice<u8>),
899    F32(CudaSlice<f32>),
900}
901
902impl ResidentBf16Weight {
903    fn ordinal(&self) -> usize {
904        match self {
905            Self::Bf16(bytes) => bytes.ordinal(),
906            Self::F32(values) => values.ordinal(),
907        }
908    }
909}
910
911struct ResidentBf16Rank {
912    weight: ResidentBf16Weight,
913    out_features: usize,
914    in_features: usize,
915}
916
917pub struct ResidentColumnParallel {
918    ranks: Vec<ResidentE4m3Rank>,
919    out_features: usize,
920    in_features: usize,
921}
922
923pub struct ResidentRowParallel {
924    ranks: Vec<ResidentE4m3Rank>,
925    out_features: usize,
926    in_features: usize,
927}
928
929pub struct ResidentBf16ColumnParallel {
930    ranks: Vec<ResidentBf16Rank>,
931    out_features: usize,
932    in_features: usize,
933    canonical_chunk_rows: Option<usize>,
934}
935
936pub struct ResidentBf16RowParallel {
937    ranks: Vec<ResidentBf16Rank>,
938    out_features: usize,
939    in_features: usize,
940}
941
942pub struct ResidentStepBf16RowParallel {
943    ranks: Vec<Vec<ResidentBf16Rank>>,
944    out_features: usize,
945    in_features: usize,
946    canonical_chunk_cols: usize,
947}
948
949/// Root-owned BF16 sigmoid router with persistent F32 weight, bias, and active mask.
950pub struct ResidentSigmoidTopKRouter {
951    weight: CudaSlice<f32>,
952    correction_bias: CudaSlice<f32>,
953    active: CudaSlice<u8>,
954    root_device: usize,
955    input_width: usize,
956    expert_count: usize,
957    experts_per_token: usize,
958    active_count: usize,
959    scaling_factor: f32,
960    route_norm: bool,
961}
962
963pub struct SigmoidTopKHostOutput {
964    pub logits: Vec<f32>,
965    pub selected: Vec<u32>,
966    pub weights: Vec<f32>,
967}
968
969/// Full BF16 SwiGLU weights replicated independently on every runtime rank.
970pub struct ResidentReplicatedBf16SwiGlu {
971    gate: Vec<ResidentBf16Rank>,
972    up: Vec<ResidentBf16Rank>,
973    down: Vec<ResidentBf16Rank>,
974    input_width: usize,
975    intermediate_width: usize,
976}
977
978/// One token-major F32 batch replicated across a native-P2P rank group.
979///
980/// Every allocation is owned by its matching rank CUDA context. This is the generic handoff
981/// substrate between independently sharded operators; it carries no model or topology claim.
982pub struct ResidentReplicatedDeviceRows {
983    ranks: Vec<CudaSlice<f32>>,
984    tokens: usize,
985    width: usize,
986}
987
988impl ResidentReplicatedDeviceRows {
989    pub fn tokens(&self) -> usize {
990        self.tokens
991    }
992
993    pub fn width(&self) -> usize {
994        self.width
995    }
996
997    pub fn ranks(&self) -> usize {
998        self.ranks.len()
999    }
1000}
1001
1002/// Canonical MoE output order: routed plus shared, then add the layer residual.
1003pub fn moe_residual_host(
1004    residual: &[f32],
1005    routed: &[f32],
1006    shared: &[f32],
1007) -> Result<Vec<f32>, String> {
1008    if residual.len() != routed.len() || residual.len() != shared.len() {
1009        return Err(format!(
1010            "MoE residual lengths residual={} routed={} shared={}",
1011            residual.len(),
1012            routed.len(),
1013            shared.len()
1014        ));
1015    }
1016    let ffn = routed
1017        .iter()
1018        .zip(shared)
1019        .map(|(&routed, &shared)| routed + shared)
1020        .collect::<Vec<_>>();
1021    Ok(residual
1022        .iter()
1023        .zip(ffn)
1024        .map(|(&residual, ffn)| residual + ffn)
1025        .collect())
1026}
1027
1028pub use memra_kv::{
1029    KvRingAppend, ResidentTpKvCache, ResidentTpKvCacheRank, TpKvAppendPlan, TpKvTransaction,
1030};
1031
1032/// Persistent TP2/TP4/TP8 routed-expert reference.
1033///
1034/// Rank-local checkpoint shards are uploaded once and remain tied to their owning CUDA context.
1035/// Activations and deterministic host-staged collectives remain per invocation. This is the
1036/// correctness substrate for serving TP/EP, not product-throughput evidence.
1037pub struct ResidentTpExpert {
1038    gate: ResidentColumnParallel,
1039    up: ResidentColumnParallel,
1040    down: ResidentRowParallel,
1041    input_width: usize,
1042    expert_width: usize,
1043}
1044
1045struct ResidentE4m3ExpertBankRank {
1046    codes: CudaSlice<u8>,
1047    scales: CudaSlice<f32>,
1048    expert_range: Range<usize>,
1049    out_features: usize,
1050    in_features: usize,
1051    code_stride: usize,
1052    scale_stride: usize,
1053    /// TP row banks are packed by native 128-wide K block so reduction can replay the
1054    /// checkpoint's global block order exactly. Other banks remain row-major.
1055    k_blocks: Option<usize>,
1056}
1057
1058struct PackedE4m3ExpertBankRank {
1059    codes: Vec<u8>,
1060    scales: Vec<f32>,
1061    expert_range: Range<usize>,
1062    out_features: usize,
1063    in_features: usize,
1064    code_stride: usize,
1065    scale_stride: usize,
1066    k_blocks: Option<usize>,
1067}
1068
1069struct ResidentEpRank {
1070    gate: ResidentE4m3ExpertBankRank,
1071    up: ResidentE4m3ExpertBankRank,
1072    down: ResidentE4m3ExpertBankRank,
1073}
1074
1075/// Persistent expert-parallel reference.
1076///
1077/// Every routed expert has exactly one owner rank. Shared experts are deliberately absent from
1078/// this object because Step replicates them per rank. Routes execute on the owner CUDA context.
1079/// The default oracle stages through host memory; the native path peer-dispatches inputs and
1080/// peer-returns owner outputs while preserving host-canonical activation and accumulation.
1081pub struct ResidentExpertParallel {
1082    ranks: Vec<ResidentEpRank>,
1083    expert_count: usize,
1084    input_width: usize,
1085    expert_width: usize,
1086}
1087
1088/// Projection-level output from the opt-in official Step grouped-FP8 gate.
1089///
1090/// Rows remain pair-major. Routing, weighted combine, and production integration are deliberately
1091/// outside this gate-only adapter.
1092pub struct StepGroupedFp8ProjectionOutput {
1093    pub gate: Vec<f32>,
1094    pub up: Vec<f32>,
1095    pub down: Vec<f32>,
1096}
1097
1098/// Prepared official Step grouped-FP8 projection gate.
1099///
1100/// The complete tensor banks, both CSR schedules, input, activation buffer, and three projection
1101/// workspaces are uploaded or allocated once. Repeated execution performs no device allocation.
1102pub struct PreparedStepGroupedFp8Gate {
1103    device: usize,
1104    gate: ResidentE4m3ExpertBankRank,
1105    up: ResidentE4m3ExpertBankRank,
1106    down: ResidentE4m3ExpertBankRank,
1107    input: CudaSlice<f32>,
1108    route_csr: DeviceExpertCsr,
1109    down_csr: DeviceExpertCsr,
1110    gate_workspace: Fp8GroupedWorkspace,
1111    up_workspace: Fp8GroupedWorkspace,
1112    down_workspace: Fp8GroupedWorkspace,
1113    activation: CudaSlice<f32>,
1114    activation_limit: Option<f32>,
1115    tokens: usize,
1116    pairs: usize,
1117}
1118
1119impl PreparedStepGroupedFp8Gate {
1120    pub fn tokens(&self) -> usize {
1121        self.tokens
1122    }
1123
1124    pub fn pairs(&self) -> usize {
1125        self.pairs
1126    }
1127}
1128
1129struct PreparedStepGroupedExpertOwner {
1130    rank: usize,
1131    global_pairs: Vec<usize>,
1132    route_csr: DeviceExpertCsr,
1133    down_csr: DeviceExpertCsr,
1134    gate_workspace: Fp8GroupedWorkspace,
1135    up_workspace: Fp8GroupedWorkspace,
1136    down_workspace: Fp8GroupedWorkspace,
1137    activation: CudaSlice<f32>,
1138}
1139
1140struct StepGroupedExpertOwnerSchedule {
1141    global_pairs: Vec<usize>,
1142    route_csr: ExpertCsr,
1143    down_csr: ExpertCsr,
1144}
1145
1146/// Prepared official Step expert-owner grouped-FP8 projection gate.
1147///
1148/// Route partitioning, owner-local CSR uploads, input dispatch, activation buffers, and grouped
1149/// workspaces are persistent. Projection rows are scattered back to canonical pair order only
1150/// after every owner has completed its rank-local program.
1151pub struct PreparedStepGroupedExpertParallelGate {
1152    rank_inputs: Vec<CudaSlice<f32>>,
1153    owners: Vec<PreparedStepGroupedExpertOwner>,
1154    activation_limit: Option<f32>,
1155    tokens: usize,
1156    pairs: usize,
1157    max_tokens: usize,
1158    max_pairs: usize,
1159    input_width: usize,
1160    expert_width: usize,
1161    generation: u64,
1162    executed_generation: Option<u64>,
1163    ready: bool,
1164}
1165
1166impl PreparedStepGroupedExpertParallelGate {
1167    pub fn tokens(&self) -> usize {
1168        self.tokens
1169    }
1170
1171    pub fn pairs(&self) -> usize {
1172        self.pairs
1173    }
1174
1175    pub fn max_tokens(&self) -> usize {
1176        self.max_tokens
1177    }
1178
1179    pub fn input_width(&self) -> usize {
1180        self.input_width
1181    }
1182
1183    pub fn expert_width(&self) -> usize {
1184        self.expert_width
1185    }
1186
1187    pub fn set_activation_limit(&mut self, limit: Option<f32>) -> Result<(), String> {
1188        validate_step_expert_activation_limit(limit)?;
1189        self.activation_limit = limit;
1190        self.executed_generation = None;
1191        Ok(())
1192    }
1193
1194    pub fn active_owners(&self) -> usize {
1195        self.owners
1196            .iter()
1197            .filter(|owner| !owner.global_pairs.is_empty())
1198            .count()
1199    }
1200
1201    pub fn owner_pair_counts(&self) -> Vec<usize> {
1202        self.owners
1203            .iter()
1204            .map(|owner| owner.global_pairs.len())
1205            .collect()
1206    }
1207
1208    pub fn generation(&self) -> u64 {
1209        self.generation
1210    }
1211}
1212
1213struct PreparedPeerWeightedRouteOwner {
1214    token_rows: CudaSlice<i32>,
1215    slots: CudaSlice<i32>,
1216    weights: CudaSlice<f32>,
1217    active_pairs: usize,
1218}
1219
1220/// Persistent root-side weighted combine for peer-owned canonical route rows.
1221///
1222/// Owner metadata, one reusable peer staging buffer, the canonical slot bank, weight bank, and
1223/// output are allocated once. Refreshes update metadata prefixes; execution peer-copies active
1224/// rows, scatters them by canonical token/slot, and reduces in the requested numeric order.
1225pub struct PreparedPeerWeightedRouteCombine {
1226    root_device: usize,
1227    owners: Vec<PreparedPeerWeightedRouteOwner>,
1228    peer_staging: CudaSlice<f32>,
1229    slots: CudaSlice<f32>,
1230    weights: CudaSlice<f32>,
1231    output: CudaSlice<f32>,
1232    peer_devices: Vec<usize>,
1233    peer_outputs: Vec<CudaSlice<f32>>,
1234    width: usize,
1235    experts_per_token: usize,
1236    max_tokens: usize,
1237    max_pairs: usize,
1238    tokens: usize,
1239    pairs: usize,
1240    projection_generation: u64,
1241    output_generation: Option<u64>,
1242    broadcast_generation: Option<u64>,
1243    ready: bool,
1244}
1245
1246impl PreparedPeerWeightedRouteCombine {
1247    pub fn tokens(&self) -> usize {
1248        self.tokens
1249    }
1250
1251    pub fn pairs(&self) -> usize {
1252        self.pairs
1253    }
1254
1255    pub fn owner_pair_counts(&self) -> Vec<usize> {
1256        self.owners.iter().map(|owner| owner.active_pairs).collect()
1257    }
1258
1259    pub fn distributed_ranks(&self) -> usize {
1260        1 + self.peer_outputs.len()
1261    }
1262}
1263
1264struct ResidentTpExpertBank {
1265    gate: Vec<ResidentE4m3ExpertBankRank>,
1266    up: Vec<ResidentE4m3ExpertBankRank>,
1267    down: Vec<ResidentE4m3ExpertBankRank>,
1268    expert_count: usize,
1269    input_width: usize,
1270    expert_width: usize,
1271}
1272
1273/// Persistent tensor-parallel expert bank.
1274///
1275/// Every rank owns a checkpoint-aligned output-row shard of every gate/up projection and an
1276/// input-column shard of every down projection. Activations cross deterministic host-staged
1277/// collectives on hosts where native peer copies are unavailable or corrupt.
1278pub struct ResidentTensorParallel {
1279    bank: ResidentTpExpertBank,
1280}
1281
1282/// Multi-context TP correctness runtime. Each rank owns an independent `Engine` and CUDA context.
1283///
1284/// Host bounce is the default oracle. Native P2P is opt-in and preserves the oracle's global
1285/// checkpoint-block reduction order; it remains a correctness path until serving gates and
1286/// repeated performance evidence qualify it.
1287pub struct TpE4m3HostBounce {
1288    devices: Vec<usize>,
1289    ranks: Vec<Engine>,
1290    native_p2p: bool,
1291    ep_device_arithmetic: bool,
1292    bulk_p2p: bool,
1293    /// v2 decode-attention workspace (MEMRA_STEP_TP_DECODE_V2). One per runtime, shared by
1294    /// every TP attention layer — the buffer shapes are geometry-constant across the trunk.
1295    decode_v2: std::sync::Mutex<Vec<StepTpDecodeV2Ws>>,
1296}
1297
1298/// Persistent workspace of the v2 rank-local decode-attention driver.
1299///
1300/// Buffers live in their producing rank's CUDA context, are never freed, and events are
1301/// re-recorded per call — the pp.rs `BoundarySlot` discipline — so the per-token path has no
1302/// cuMemAlloc, no cross-stream free, and no host round-trip. Every buffer is fully overwritten
1303/// before its consumers run in the same call; nothing carries state between tokens.
1304/// Per-rank attn_gate row shards for the fused QKV+gate kernel, in the weight class the
1305/// fused kernels read (F32 mirror or raw checkpoint bf16).
1306pub enum StepTpGateShards<'a> {
1307    F32(&'a [crate::CudaSlice<f32>]),
1308    Bf16(&'a [crate::CudaSlice<u8>]),
1309}
1310
1311pub struct StepTpDecodeV2Ws {
1312    /// T-COLUMN verify slabs (spec MTP): per-rank [t, local_dim] projections computed by
1313    /// the weight-amortized qkvg_tcol kernel; the col-select door copies one column into
1314    /// the single-row buffers and everything downstream runs the unmodified t=1 program.
1315    pub(crate) tcol_q: Vec<CudaSlice<f32>>,
1316    pub(crate) tcol_k: Vec<CudaSlice<f32>>,
1317    pub(crate) tcol_v: Vec<CudaSlice<f32>>,
1318    pub(crate) tcol_g: Vec<CudaSlice<f32>>,
1319    pub(crate) tcol_in: Vec<CudaSlice<f32>>,
1320    pub(crate) tcol_cap: usize,
1321    /// MEMRA_TCOL_OPROJ slabs: per-rank stashed `gated` rows ([8, local_q_dim]), per-rank
1322    /// b4_tcol partials ([8, o_out]), a root-side peer pull of rank1's partial slab, and
1323    /// the root-side joined `mixed` slab. Armed lazily by the first stash.
1324    /// MEMRA_SPEC_FA2 slabs: per-rank stashed post-rope q rows ([2, local_q_dim]), gate
1325    /// rows ([2, heads/ranks]) and the two gated outputs the per-row combine writes
1326    /// ([2, local_q_dim]). Armed lazily by the first stash.
1327    pub(crate) fa2_q: Vec<CudaSlice<f32>>,
1328    pub(crate) fa2_gate: Vec<CudaSlice<f32>>,
1329    pub(crate) fa2_gated: Vec<CudaSlice<f32>>,
1330    pub(crate) fa2_cap: usize,
1331    tcol_gated: Vec<CudaSlice<f32>>,
1332    tcol_opart: Vec<CudaSlice<f32>>,
1333    tcol_opeer: Option<CudaSlice<f32>>,
1334    tcol_omix: Option<CudaSlice<f32>>,
1335    tcol_ocap: usize,
1336    // rank-context buffers, indexed by rank (pub(crate): the v2 driver in hybrid_forward
1337    // feeds them to the KV transaction and attention kernels between the two v2 phases)
1338    pub(crate) q_raw: Vec<CudaSlice<f32>>,
1339    pub(crate) k_raw: Vec<CudaSlice<f32>>,
1340    pub(crate) v_raw: Vec<CudaSlice<f32>>,
1341    pub(crate) q: Vec<CudaSlice<f32>>,
1342    pub(crate) k: Vec<CudaSlice<f32>>,
1343    pub(crate) pos: Vec<CudaSlice<i32>>,
1344    /// FUSION #1 last-block counters (one per rank; atomicInc auto-resets per launch).
1345    pub(crate) fuse_ctr: Vec<CudaSlice<u32>>,
1346    pub(crate) gate: Vec<CudaSlice<f32>>,
1347    pub(crate) attn_out: Vec<CudaSlice<f32>>,
1348    pub(crate) gated: Vec<CudaSlice<f32>>,
1349    /// [rank][block] O partials, each `o_out` wide, in the owning rank's context.
1350    o_partials: Vec<Vec<CudaSlice<f32>>>,
1351    /// Recorded on each rank's stream after its per-call work; root waits before peer reads.
1352    ev_rank: Vec<CudaEvent>,
1353    // root-context buffers
1354    peer_partial: CudaSlice<f32>,
1355    reduce_a: CudaSlice<f32>,
1356    reduce_b: CudaSlice<f32>,
1357    /// Never written; the canonical zero start of the v1 add chain.
1358    zeros: CudaSlice<f32>,
1359    pub(crate) k_shadow: CudaSlice<f32>,
1360    pub(crate) v_shadow: CudaSlice<f32>,
1361    ev_refresh: CudaEvent,
1362    ev_oproj: CudaEvent,
1363    // model-engine (e) context
1364    gate_e: CudaSlice<f32>,
1365    /// Per-token stages (e-ctx, fixed addresses): one eager e-stream copy each per layer; the
1366    /// rank flows raw-copy FROM them, which is exactly the shape graph capture needs.
1367    pub(crate) h_stage: Option<CudaSlice<f32>>,
1368    pub(crate) pos_stage: Option<CudaSlice<i32>>,
1369    /// Workspace-owned per-rank attention input rows (the stage flow copies into THESE, not
1370    /// the per-layer decode_input buffers — the workspace is shared across layers, so every
1371    /// captured/raw address it uses must be layer-invariant).
1372    attn_in: Vec<CudaSlice<f32>>,
1373    /// Cached raw pointers of the stage-flow operands (set when the stages arm).
1374    raw_h_stage: u64,
1375    raw_pos_stage: u64,
1376    raw_attn_in: Vec<u64>,
1377    raw_pos: Vec<u64>,
1378    raw_o_partial1: u64,
1379    raw_peer_partial: u64,
1380    raw_k1: u64,
1381    raw_v1: u64,
1382    raw_k_shadow: u64,
1383    raw_v_shadow: u64,
1384    /// Token-graph e-context mirrors (armed by the orchestrator): the root section
1385    /// raw-copies the reduced attention output and the shadow rows here so the e-glue
1386    /// children read same-context memory (cross-context kernel args are capture-illegal).
1387    raw_mixed_stage_e: u64,
1388    raw_reduce_a: u64,
1389    raw_shadow_stage_e: (u64, u64),
1390    ev_entry: CudaEvent,
1391    e_device: usize,
1392    // geometry pins
1393    local_q_dim: usize,
1394    local_kv_dim: usize,
1395    heads: usize,
1396    pub(crate) o_out: usize,
1397    o_block_cols: usize,
1398    blocks_per_rank: usize,
1399}
1400
1401impl TpE4m3HostBounce {
1402    pub fn new(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1403        Self::new_inner(devices, false, false, false, false)
1404    }
1405
1406    pub fn new_native_p2p(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1407        Self::new_inner(devices, false, true, false, false)
1408    }
1409
1410    pub fn new_native_p2p_device_arithmetic(
1411        devices: &[usize],
1412    ) -> Result<Self, Box<dyn std::error::Error>> {
1413        Self::new_inner(devices, false, true, true, false)
1414    }
1415
1416    pub(crate) fn new_configured(
1417        devices: &[usize],
1418        native_p2p: bool,
1419        ep_device_arithmetic: bool,
1420        bulk_p2p: bool,
1421    ) -> Result<Self, Box<dyn std::error::Error>> {
1422        Self::new_inner(devices, false, native_p2p, ep_device_arithmetic, bulk_p2p)
1423    }
1424
1425    /// Single-rank execution of the canonical checkpoint-block TP program.
1426    ///
1427    /// This is an oracle for distributed exactness, not a serving topology. It lets gates compare
1428    /// TP=1 and TP>1 with the same packing, kernel launches, and deterministic reduction order.
1429    pub fn new_single_rank_oracle(device: usize) -> Result<Self, Box<dyn std::error::Error>> {
1430        Self::new_inner(&[device], true, false, false, false)
1431    }
1432
1433    fn new_inner(
1434        devices: &[usize],
1435        allow_single_rank: bool,
1436        native_p2p: bool,
1437        ep_device_arithmetic: bool,
1438        bulk_p2p: bool,
1439    ) -> Result<Self, Box<dyn std::error::Error>> {
1440        if ep_device_arithmetic && !native_p2p {
1441            return Err("device-resident EP arithmetic requires native P2P".into());
1442        }
1443        if bulk_p2p && !native_p2p {
1444            return Err("bulk TP transport requires native P2P".into());
1445        }
1446        let minimum = if allow_single_rank { 1 } else { 2 };
1447        if !(minimum..=8).contains(&devices.len()) {
1448            return Err(format!(
1449                "TP reference requires {minimum}..=8 devices, got {}",
1450                devices.len()
1451            )
1452            .into());
1453        }
1454        let mut unique = devices.to_vec();
1455        unique.sort_unstable();
1456        unique.dedup();
1457        if unique.len() != devices.len() {
1458            return Err(format!("TP devices must be distinct, got {devices:?}").into());
1459        }
1460        let ranks = devices
1461            .iter()
1462            .map(|&device| Engine::new(device))
1463            .collect::<Result<Vec<_>, _>>()?;
1464        if native_p2p {
1465            configure_native_p2p(&ranks, devices)?;
1466        }
1467        if allow_single_rank {
1468            eprintln!(
1469                "[tp] canonical oracle transport=local device={} performance_claim=false",
1470                devices[0]
1471            );
1472        } else if native_p2p {
1473            if ep_device_arithmetic {
1474                eprintln!(
1475                    "[tp] correctness transport=native-p2p devices={devices:?} \
1476                     native_p2p=true activation=device-host-exact \
1477                     accumulation=device-host-exact output=root-readback \
1478                     bulk_p2p={bulk_p2p} performance_claim=false"
1479                );
1480            } else {
1481                eprintln!(
1482                    "[tp] correctness transport=native-p2p devices={devices:?} \
1483                     native_p2p=true activation=host-canonical bulk_p2p={bulk_p2p} \
1484                     performance_claim=false"
1485                );
1486            }
1487        } else {
1488            eprintln!(
1489                "[tp] correctness transport=host-bounce devices={devices:?} \
1490                 native_p2p=false performance_claim=false"
1491            );
1492        }
1493        Ok(Self {
1494            devices: devices.to_vec(),
1495            ranks,
1496            native_p2p,
1497            ep_device_arithmetic,
1498            bulk_p2p,
1499            decode_v2: std::sync::Mutex::new(Vec::new()),
1500        })
1501    }
1502
1503    pub fn devices(&self) -> &[usize] {
1504        &self.devices
1505    }
1506
1507    pub fn native_p2p(&self) -> bool {
1508        self.native_p2p
1509    }
1510
1511    pub fn bulk_p2p(&self) -> bool {
1512        self.bulk_p2p
1513    }
1514
1515    pub fn expert_activation_label(&self) -> &'static str {
1516        if self.ep_device_arithmetic {
1517            "device-host-exact"
1518        } else {
1519            "host-canonical"
1520        }
1521    }
1522
1523    pub fn expert_accumulation_label(&self) -> &'static str {
1524        self.expert_activation_label()
1525    }
1526
1527    pub fn expert_output_label(&self) -> &'static str {
1528        if self.ep_device_arithmetic {
1529            "root-readback"
1530        } else {
1531            "host-accumulated"
1532        }
1533    }
1534
1535    pub fn transport_label(&self) -> &'static str {
1536        if self.devices.len() == 1 {
1537            "local"
1538        } else if self.native_p2p {
1539            "native-p2p"
1540        } else {
1541            "host-bounce"
1542        }
1543    }
1544
1545    pub fn device_names(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
1546        self.ranks
1547            .iter()
1548            .map(|rank| rank.ctx().name().map_err(Into::into))
1549            .collect()
1550    }
1551
1552    /// Correctness-gate access to the engine that owns one TP rank.
1553    ///
1554    /// Model execution should prefer collective methods on this runtime. This accessor exists so
1555    /// focused gates can prove that the rank-local projection outputs remain device-resident
1556    /// through the next ownership boundary before that boundary is wired into serving.
1557    pub fn rank_engine(&self, rank: usize) -> Option<&Engine> {
1558        self.ranks.get(rank)
1559    }
1560
1561    pub fn allocate_tp_kv_cache(
1562        &self,
1563        kv_dim_k: usize,
1564        kv_dim_v: usize,
1565        capacity: usize,
1566    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1567        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, None)
1568    }
1569
1570    pub fn allocate_tp_swa_kv_cache(
1571        &self,
1572        kv_dim_k: usize,
1573        kv_dim_v: usize,
1574        capacity: usize,
1575        window: usize,
1576    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1577        if window == 0 {
1578            return Err("TP SWA KV window must be nonzero".into());
1579        }
1580        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, Some(window))
1581    }
1582
1583    fn allocate_tp_kv_cache_inner(
1584        &self,
1585        kv_dim_k: usize,
1586        kv_dim_v: usize,
1587        capacity: usize,
1588        window: Option<usize>,
1589    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1590        if capacity == 0 || capacity > i32::MAX as usize {
1591            return Err(
1592                format!("TP KV capacity must be in 1..={}, got {capacity}", i32::MAX).into(),
1593            );
1594        }
1595        let tp = self.ranks.len();
1596        let shape = crate::cache::tp_kv_rank_allocation_shape(kv_dim_k, kv_dim_v, tp)?;
1597        let physical_rows = window
1598            .map(|window| crate::cache::swa_ring_rows(window, capacity))
1599            .unwrap_or(capacity);
1600        let k_plane_bytes = physical_rows
1601            .checked_mul(shape.k_token_bytes)
1602            .and_then(|bytes| bytes.checked_add(8))
1603            .ok_or("TP KV K plane-byte overflow")?;
1604        let v_plane_bytes = physical_rows
1605            .checked_mul(shape.v_token_bytes)
1606            .and_then(|bytes| bytes.checked_add(8))
1607            .ok_or("TP KV V plane-byte overflow")?;
1608        let mut ranks = Vec::with_capacity(tp);
1609        for engine in &self.ranks {
1610            let _main = engine.gpu.enter_main()?;
1611            ranks.push(ResidentTpKvCacheRank::new(
1612                engine.alloc_u8(k_plane_bytes)?,
1613                engine.alloc_u8(v_plane_bytes)?,
1614                engine.htod_i32(&[0])?,
1615            ));
1616        }
1617        Ok(match window {
1618            Some(window) => ResidentTpKvCache::new_swa(
1619                ranks,
1620                shape.kv_dim_k,
1621                shape.kv_dim_v,
1622                shape.k_token_bytes,
1623                shape.v_token_bytes,
1624                capacity,
1625                window,
1626            ),
1627            None => ResidentTpKvCache::new(
1628                ranks,
1629                shape.kv_dim_k,
1630                shape.kv_dim_v,
1631                shape.k_token_bytes,
1632                shape.v_token_bytes,
1633                capacity,
1634            ),
1635        })
1636    }
1637
1638    pub fn grow_tp_kv_cache(
1639        &self,
1640        source: &ResidentTpKvCache,
1641        target_capacity: usize,
1642        rows: usize,
1643    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1644        self.validate_tp_kv_cache(source)?;
1645        let plan = source.prepare_grow(target_capacity, rows)?;
1646        let ranks = self.ranks.len();
1647        let global_k = source
1648            .kv_dim_k()
1649            .checked_mul(ranks)
1650            .ok_or("TP KV grow global K dimension overflow")?;
1651        let global_v = source
1652            .kv_dim_v()
1653            .checked_mul(ranks)
1654            .ok_or("TP KV grow global V dimension overflow")?;
1655        let mut target = match source.ring_window() {
1656            Some(window) => {
1657                self.allocate_tp_swa_kv_cache(global_k, global_v, target_capacity, window)?
1658            }
1659            None => self.allocate_tp_kv_cache(global_k, global_v, target_capacity)?,
1660        };
1661        self.validate_tp_kv_cache(&target)?;
1662
1663        for (rank, engine) in self.ranks.iter().enumerate() {
1664            let _main = engine.gpu.enter_main()?;
1665            let src = source
1666                .rank(rank)
1667                .ok_or_else(|| format!("TP KV grow source has no rank {rank}"))?;
1668            let dst = target
1669                .rank_mut(rank)
1670                .ok_or_else(|| format!("TP KV grow target has no rank {rank}"))?;
1671            if plan.k_bytes() > 0 {
1672                engine.copy_u8_range_into(
1673                    dst.k_mut(),
1674                    0,
1675                    src.k(),
1676                    plan.source_row() * source.k_tok_bytes(),
1677                    plan.k_bytes(),
1678                )?;
1679            }
1680            if plan.v_bytes() > 0 {
1681                engine.copy_u8_range_into(
1682                    dst.v_mut(),
1683                    0,
1684                    src.v(),
1685                    plan.source_row() * source.v_tok_bytes(),
1686                    plan.v_bytes(),
1687                )?;
1688            }
1689        }
1690        self.set_tp_kv_len_mirrors(&mut target, plan.rows())?;
1691
1692        // The caller publishes `target` and immediately drops `source`. Drain every rank's
1693        // stream so an async-pool free cannot recycle a source plane under an in-flight D2D copy.
1694        for engine in &self.ranks {
1695            let _main = engine.gpu.enter_main()?;
1696            engine.stream().synchronize()?;
1697        }
1698        let physical_copy_rows = plan.copy_rows();
1699        target.publish_grow(plan)?;
1700        eprintln!(
1701            "[step-tp-kv-grow] rows={} source_capacity={} target_capacity={} ranks={} \
1702             physical_copy_rows={} ring_window={:?} copy=rank-local-dtod \
1703             rank_streams_synchronized=true generation_preserved=true",
1704            rows,
1705            source.capacity(),
1706            target_capacity,
1707            ranks,
1708            physical_copy_rows,
1709            source.ring_window(),
1710        );
1711        Ok(target)
1712    }
1713
1714    pub fn hydrate_tp_kv_cache(
1715        &self,
1716        cache: &mut ResidentTpKvCache,
1717        rows: usize,
1718        k_rows: &[u8],
1719        v_rows: &[u8],
1720    ) -> Result<(), Box<dyn std::error::Error>> {
1721        self.hydrate_tp_kv_cache_from(cache, rows, 0, k_rows, v_rows)
1722    }
1723
1724    pub fn hydrate_tp_kv_cache_from(
1725        &self,
1726        cache: &mut ResidentTpKvCache,
1727        logical_len: usize,
1728        resident_start: usize,
1729        k_rows: &[u8],
1730        v_rows: &[u8],
1731    ) -> Result<(), Box<dyn std::error::Error>> {
1732        self.validate_tp_kv_cache(cache)?;
1733        if cache.committed_len() != 0 || cache.staged_len() != 0 {
1734            return Err(format!(
1735                "TP KV hydration requires an empty cache, got committed/staged={}/{}",
1736                cache.committed_len(),
1737                cache.staged_len()
1738            )
1739            .into());
1740        }
1741        if resident_start > logical_len || logical_len > cache.capacity() {
1742            return Err(format!(
1743                "TP KV hydration range [{resident_start},{logical_len}) exceeds capacity {}",
1744                cache.capacity(),
1745            )
1746            .into());
1747        }
1748        let rows = logical_len - resident_start;
1749        if rows > cache.physical_capacity() {
1750            return Err(format!(
1751                "TP KV hydration rows {rows} exceed physical capacity {}",
1752                cache.physical_capacity()
1753            )
1754            .into());
1755        }
1756        for rank in 0..self.ranks.len() {
1757            let k_rank =
1758                cache_rank_rows(k_rows, rows, cache.k_tok_bytes(), self.ranks.len(), rank)?;
1759            let v_rank =
1760                cache_rank_rows(v_rows, rows, cache.v_tok_bytes(), self.ranks.len(), rank)?;
1761            let engine = &self.ranks[rank];
1762            let _main = engine.gpu.enter_main()?;
1763            let rank_cache = cache
1764                .rank_mut(rank)
1765                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1766            engine.htod_u8_into(rank_cache.k_mut(), 0, &k_rank)?;
1767            engine.htod_u8_into(rank_cache.v_mut(), 0, &v_rank)?;
1768        }
1769        cache.publish_hydration(logical_len, resident_start)?;
1770        Ok(())
1771    }
1772
1773    pub fn append_tp_kv_transaction(
1774        &self,
1775        cache: &mut ResidentTpKvCache,
1776        transaction: TpKvTransaction,
1777        k_shards: &[CudaSlice<f32>],
1778        v_shards: &[CudaSlice<f32>],
1779        rows: usize,
1780    ) -> Result<(), Box<dyn std::error::Error>> {
1781        self.append_tp_kv_transaction_inner(cache, transaction, k_shards, v_shards, rows, false)
1782    }
1783
1784    /// `external_rank_appends`: the dcw path already wrote the rank rows (device-counter
1785    /// append) — run everything EXCEPT the per-rank quantize/append loop (plan validation,
1786    /// rebase arm — unreachable when the caller peeked — and the absolute len-mirror sets,
1787    /// which land the same value the in-stream inc produced).
1788    #[allow(clippy::too_many_arguments)]
1789    pub fn append_tp_kv_transaction_inner(
1790        &self,
1791        cache: &mut ResidentTpKvCache,
1792        transaction: TpKvTransaction,
1793        k_shards: &[CudaSlice<f32>],
1794        v_shards: &[CudaSlice<f32>],
1795        rows: usize,
1796        external_rank_appends: bool,
1797    ) -> Result<(), Box<dyn std::error::Error>> {
1798        self.validate_tp_kv_cache(cache)?;
1799        let plan = cache.prepare_append(transaction, rows)?;
1800        let target = plan.target();
1801        let expected_k = rows
1802            .checked_mul(cache.kv_dim_k())
1803            .ok_or("TP KV K append size overflow")?;
1804        let expected_v = rows
1805            .checked_mul(cache.kv_dim_v())
1806            .ok_or("TP KV V append size overflow")?;
1807        // external_rank_appends passes no shards — the graph's dcw appends already wrote
1808        // the rank rows, so this call is bookkeeping-only and the shard slices are unused.
1809        if !external_rank_appends
1810            && (k_shards.len() != self.ranks.len() || v_shards.len() != self.ranks.len())
1811        {
1812            return Err(format!(
1813                "TP KV append shard counts k={} v={} != ranks {}",
1814                k_shards.len(),
1815                v_shards.len(),
1816                self.ranks.len()
1817            )
1818            .into());
1819        }
1820        let kv_dim_k = cache.kv_dim_k();
1821        let kv_dim_v = cache.kv_dim_v();
1822        let k_tok_bytes = cache.k_tok_bytes();
1823        let v_tok_bytes = cache.v_tok_bytes();
1824        if let Some(KvRingAppend::Rebase {
1825            src_row,
1826            keep_rows,
1827            new_base,
1828            ..
1829        }) = plan.ring_append()
1830        {
1831            for rank in 0..self.ranks.len() {
1832                let engine = &self.ranks[rank];
1833                let _main = engine.gpu.enter_main()?;
1834                let rank_cache = cache
1835                    .rank_mut(rank)
1836                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1837                if keep_rows > 0 {
1838                    let k_len = keep_rows
1839                        .checked_mul(k_tok_bytes)
1840                        .ok_or("TP KV K rebase-byte overflow")?;
1841                    let v_len = keep_rows
1842                        .checked_mul(v_tok_bytes)
1843                        .ok_or("TP KV V rebase-byte overflow")?;
1844                    let mut k_tmp = engine.alloc_u8_uninit(k_len)?;
1845                    let mut v_tmp = engine.alloc_u8_uninit(v_len)?;
1846                    engine.copy_u8_range_into(
1847                        &mut k_tmp,
1848                        0,
1849                        rank_cache.k(),
1850                        src_row * k_tok_bytes,
1851                        k_len,
1852                    )?;
1853                    engine.copy_u8_range_into(
1854                        &mut v_tmp,
1855                        0,
1856                        rank_cache.v(),
1857                        src_row * v_tok_bytes,
1858                        v_len,
1859                    )?;
1860                    engine.copy_u8_into(rank_cache.k_mut(), 0, &k_tmp, k_len)?;
1861                    engine.copy_u8_into(rank_cache.v_mut(), 0, &v_tmp, v_len)?;
1862                }
1863                // dcw base mirror (graph increment A): physical row 0 now holds logical
1864                // row `new_base`; armed device mirrors track it (rebases are rare host
1865                // events, so a host set here is the whole maintenance cost).
1866                if rank_cache.base_d().is_some() {
1867                    let value = new_base as i32;
1868                    let rank_cache = cache
1869                        .rank_mut(rank)
1870                        .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1871                    if let Some(base_d) = rank_cache.base_d_mut() {
1872                        engine.set_i32_one(base_d, value)?;
1873                    }
1874                }
1875            }
1876        }
1877        cache.publish_append_rebase(plan)?;
1878        let write_row = plan.write_row();
1879        for rank in 0..self.ranks.len() {
1880            if external_rank_appends {
1881                break;
1882            }
1883            let engine = &self.ranks[rank];
1884            let _main = engine.gpu.enter_main()?;
1885            if k_shards[rank].len() != expected_k
1886                || v_shards[rank].len() != expected_v
1887                || k_shards[rank].ordinal() != engine.ctx().ordinal()
1888                || v_shards[rank].ordinal() != engine.ctx().ordinal()
1889            {
1890                return Err(format!(
1891                    "TP KV rank {rank} shard geometry/device k={}/{} v={}/{} \
1892                     != expected {expected_k}/{expected_v} on device {}",
1893                    k_shards[rank].len(),
1894                    k_shards[rank].ordinal(),
1895                    v_shards[rank].len(),
1896                    v_shards[rank].ordinal(),
1897                    engine.ctx().ordinal(),
1898                )
1899                .into());
1900            }
1901            let rank_cache = cache
1902                .rank_mut(rank)
1903                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1904            let (rank_k, rank_v) = rank_cache.planes_mut();
1905            engine.append_kv_quantized_rows(
1906                &k_shards[rank],
1907                &v_shards[rank],
1908                rank_k,
1909                rank_v,
1910                write_row,
1911                rows,
1912                kv_dim_k,
1913                kv_dim_v,
1914                k_tok_bytes,
1915                v_tok_bytes,
1916                Engine::kv_fp8_on(),
1917            )?;
1918        }
1919        if !external_rank_appends {
1920            // dcw appends advance the device counters with in-stream inc_i32; an absolute set
1921            // here would race the merged per-rank append (it reads len_d for its write row).
1922            self.set_tp_kv_len_mirrors(cache, target)?;
1923        }
1924        cache.publish_append_plan(plan)?;
1925        Ok(())
1926    }
1927
1928    pub fn commit_tp_kv_transaction(
1929        &self,
1930        cache: &mut ResidentTpKvCache,
1931        transaction: TpKvTransaction,
1932        accepted_rows: usize,
1933    ) -> Result<(), Box<dyn std::error::Error>> {
1934        self.validate_tp_kv_cache(cache)?;
1935        let target = cache.commit_target(transaction, accepted_rows)?;
1936        self.set_tp_kv_len_mirrors(cache, target)?;
1937        cache.publish_finalize(transaction, target)?;
1938        Ok(())
1939    }
1940
1941    /// Commit for the external-appends (token graph) path: host bookkeeping only, NO absolute
1942    /// len-mirror sets. The graph's in-stream inc_i32 owns the device counters; a rank-stream
1943    /// set here has no ordering edge against the NEXT token's graph launch (graph children do
1944    /// not wait on the rank streams), so it can land AFTER that graph's inc and drag the
1945    /// counter backward mid-token.
1946    pub fn commit_tp_kv_transaction_external(
1947        &self,
1948        cache: &mut ResidentTpKvCache,
1949        transaction: TpKvTransaction,
1950        accepted_rows: usize,
1951    ) -> Result<(), Box<dyn std::error::Error>> {
1952        self.validate_tp_kv_cache(cache)?;
1953        let target = cache.commit_target(transaction, accepted_rows)?;
1954        cache.publish_finalize(transaction, target)?;
1955        Ok(())
1956    }
1957
1958    pub fn rollback_tp_kv_transaction(
1959        &self,
1960        cache: &mut ResidentTpKvCache,
1961        transaction: TpKvTransaction,
1962    ) -> Result<(), Box<dyn std::error::Error>> {
1963        self.validate_tp_kv_cache(cache)?;
1964        cache.validate_transaction(transaction)?;
1965        let target = transaction.base_len();
1966        self.set_tp_kv_len_mirrors(cache, target)?;
1967        cache.publish_finalize(transaction, target)?;
1968        Ok(())
1969    }
1970
1971    pub fn tp_kv_device_lengths(
1972        &self,
1973        cache: &ResidentTpKvCache,
1974    ) -> Result<Vec<i32>, Box<dyn std::error::Error>> {
1975        self.validate_tp_kv_cache(cache)?;
1976        let mut lengths = Vec::with_capacity(self.ranks.len());
1977        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks()) {
1978            let _main = engine.gpu.enter_main()?;
1979            lengths.push(engine.dtoh_i32_one(rank_cache.len_d())?);
1980        }
1981        Ok(lengths)
1982    }
1983
1984    fn set_tp_kv_len_mirrors(
1985        &self,
1986        cache: &mut ResidentTpKvCache,
1987        len: usize,
1988    ) -> Result<(), Box<dyn std::error::Error>> {
1989        let len = i32::try_from(len).map_err(|_| "TP KV length exceeds i32 device mirror")?;
1990        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks_mut()) {
1991            let _main = engine.gpu.enter_main()?;
1992            engine.set_i32_one(rank_cache.len_d_mut(), len)?;
1993        }
1994        Ok(())
1995    }
1996
1997    fn validate_tp_kv_cache(
1998        &self,
1999        cache: &ResidentTpKvCache,
2000    ) -> Result<(), Box<dyn std::error::Error>> {
2001        if cache.ranks_len() != self.ranks.len() {
2002            return Err(format!(
2003                "TP KV cache ranks {} != runtime ranks {}",
2004                cache.ranks_len(),
2005                self.ranks.len()
2006            )
2007            .into());
2008        }
2009        let expected_k = cache
2010            .physical_capacity()
2011            .checked_mul(cache.k_tok_bytes())
2012            .and_then(|bytes| bytes.checked_add(8))
2013            .ok_or("TP KV K plane validation overflow")?;
2014        let expected_v = cache
2015            .physical_capacity()
2016            .checked_mul(cache.v_tok_bytes())
2017            .and_then(|bytes| bytes.checked_add(8))
2018            .ok_or("TP KV V plane validation overflow")?;
2019        for (rank, (engine, rank_cache)) in self.ranks.iter().zip(cache.ranks()).enumerate() {
2020            let device = engine.ctx().ordinal();
2021            if rank_cache.k().len() != expected_k
2022                || rank_cache.v().len() != expected_v
2023                || rank_cache.len_d().len() != 1
2024                || rank_cache.k().ordinal() != device
2025                || rank_cache.v().ordinal() != device
2026                || rank_cache.len_d().ordinal() != device
2027            {
2028                return Err(format!(
2029                    "TP KV rank {rank} residency does not match device {device} or plane geometry"
2030                )
2031                .into());
2032            }
2033        }
2034        Ok(())
2035    }
2036
2037    pub fn full(
2038        &self,
2039        matrix: E4m3BlockMatrix<'_>,
2040        activations: &[f32],
2041        tokens: usize,
2042    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2043        matrix.validate()?;
2044        validate_activations(activations, tokens, matrix.in_features)?;
2045        run_rank(&self.ranks[0], matrix, activations, tokens)
2046    }
2047
2048    /// Column-parallel projection. Weight output rows and their scale rows are partitioned across
2049    /// ranks. The input is host-broadcast, rank-local projections execute independently, and the
2050    /// output is host-gathered in rank order.
2051    pub fn column_parallel(
2052        &self,
2053        matrix: E4m3BlockMatrix<'_>,
2054        activations: &[f32],
2055        tokens: usize,
2056    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2057        matrix.validate()?;
2058        validate_activations(activations, tokens, matrix.in_features)?;
2059        let tp = self.ranks.len();
2060        if matrix.out_features % tp != 0 {
2061            return Err(format!(
2062                "column-parallel out_features {} is not divisible by TP={tp}",
2063                matrix.out_features
2064            )
2065            .into());
2066        }
2067        let local_out = matrix.out_features / tp;
2068        if local_out % FP8_BLOCK != 0 {
2069            return Err(format!(
2070                "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
2071                 E4M3 scale block"
2072            )
2073            .into());
2074        }
2075
2076        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2077        let mut rank_outputs = Vec::with_capacity(tp);
2078        for (rank_index, rank) in self.ranks.iter().enumerate() {
2079            let shard = column_shard(matrix, tp, rank_index)?;
2080            let output = run_rank(rank, shard, activations, tokens)?;
2081            let row_start = rank_index * local_out;
2082            for token in 0..tokens {
2083                gathered[token * matrix.out_features + row_start
2084                    ..token * matrix.out_features + row_start + local_out]
2085                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2086            }
2087            rank_outputs.push(output);
2088        }
2089        Ok(ColumnParallelResult {
2090            gathered,
2091            rank_outputs,
2092        })
2093    }
2094
2095    pub fn upload_column_parallel(
2096        &self,
2097        matrix: E4m3BlockMatrix<'_>,
2098    ) -> Result<ResidentColumnParallel, Box<dyn std::error::Error>> {
2099        matrix.validate()?;
2100        let tp = self.ranks.len();
2101        validate_column_shape(matrix, tp)?;
2102        let mut ranks = Vec::with_capacity(tp);
2103        for (rank_index, engine) in self.ranks.iter().enumerate() {
2104            ranks.push(upload_rank(engine, column_shard(matrix, tp, rank_index)?)?);
2105        }
2106        Ok(ResidentColumnParallel {
2107            ranks,
2108            out_features: matrix.out_features,
2109            in_features: matrix.in_features,
2110        })
2111    }
2112
2113    pub fn column_parallel_resident(
2114        &self,
2115        matrix: &ResidentColumnParallel,
2116        activations: &[f32],
2117        tokens: usize,
2118    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2119        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2120        validate_activations(activations, tokens, matrix.in_features)?;
2121        let local_out = matrix.out_features / self.ranks.len();
2122        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2123        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2124        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2125            let output = run_resident_rank(engine, shard, activations, tokens)?;
2126            let row_start = rank_index * local_out;
2127            for token in 0..tokens {
2128                gathered[token * matrix.out_features + row_start
2129                    ..token * matrix.out_features + row_start + local_out]
2130                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2131            }
2132            rank_outputs.push(output);
2133        }
2134        Ok(ColumnParallelResult {
2135            gathered,
2136            rank_outputs,
2137        })
2138    }
2139
2140    /// Row-parallel projection. Weight/input columns and their scale columns are partitioned
2141    /// across ranks. Rank-local partials return through host memory and are reduced in stable
2142    /// rank order.
2143    pub fn row_parallel(
2144        &self,
2145        matrix: E4m3BlockMatrix<'_>,
2146        activations: &[f32],
2147        tokens: usize,
2148    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2149        matrix.validate()?;
2150        validate_activations(activations, tokens, matrix.in_features)?;
2151        let tp = self.ranks.len();
2152        if matrix.in_features % tp != 0 {
2153            return Err(format!(
2154                "row-parallel in_features {} is not divisible by TP={tp}",
2155                matrix.in_features
2156            )
2157            .into());
2158        }
2159        let local_in = matrix.in_features / tp;
2160        if local_in % FP8_BLOCK != 0 {
2161            return Err(format!(
2162                "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
2163                 E4M3 scale block"
2164            )
2165            .into());
2166        }
2167
2168        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2169        let mut rank_partials = Vec::with_capacity(tp);
2170        for (rank_index, rank) in self.ranks.iter().enumerate() {
2171            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2172            let local_activations =
2173                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2174            let shard = E4m3BlockMatrix {
2175                codes: &codes,
2176                scales: &scales,
2177                out_features: matrix.out_features,
2178                in_features: local_in,
2179            };
2180            let partial = run_rank(rank, shard, &local_activations, tokens)?;
2181            for (sum, value) in reduced.iter_mut().zip(&partial) {
2182                *sum += *value;
2183            }
2184            rank_partials.push(partial);
2185        }
2186        Ok(RowParallelResult {
2187            reduced,
2188            rank_partials,
2189        })
2190    }
2191
2192    pub fn upload_row_parallel(
2193        &self,
2194        matrix: E4m3BlockMatrix<'_>,
2195    ) -> Result<ResidentRowParallel, Box<dyn std::error::Error>> {
2196        matrix.validate()?;
2197        let tp = self.ranks.len();
2198        validate_row_shape(matrix, tp)?;
2199        let local_in = matrix.in_features / tp;
2200        let mut ranks = Vec::with_capacity(tp);
2201        for (rank_index, engine) in self.ranks.iter().enumerate() {
2202            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2203            ranks.push(upload_rank(
2204                engine,
2205                E4m3BlockMatrix {
2206                    codes: &codes,
2207                    scales: &scales,
2208                    out_features: matrix.out_features,
2209                    in_features: local_in,
2210                },
2211            )?);
2212        }
2213        Ok(ResidentRowParallel {
2214            ranks,
2215            out_features: matrix.out_features,
2216            in_features: matrix.in_features,
2217        })
2218    }
2219
2220    pub fn row_parallel_resident(
2221        &self,
2222        matrix: &ResidentRowParallel,
2223        activations: &[f32],
2224        tokens: usize,
2225    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2226        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2227        validate_activations(activations, tokens, matrix.in_features)?;
2228        let tp = self.ranks.len();
2229        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2230        let mut rank_partials = Vec::with_capacity(tp);
2231        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2232            let local_activations =
2233                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2234            let partial = run_resident_rank(engine, shard, &local_activations, tokens)?;
2235            for (sum, value) in reduced.iter_mut().zip(&partial) {
2236                *sum += *value;
2237            }
2238            rank_partials.push(partial);
2239        }
2240        Ok(RowParallelResult {
2241            reduced,
2242            rank_partials,
2243        })
2244    }
2245
2246    pub fn upload_bf16_column_parallel(
2247        &self,
2248        matrix: Bf16Matrix<'_>,
2249    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2250        self.upload_bf16_column_parallel_inner(matrix, None, false)
2251    }
2252
2253    /// Step-3.7 column projection with one numerical program across TP1/TP2/TP4/TP8.
2254    pub fn upload_step_bf16_column_parallel(
2255        &self,
2256        matrix: Bf16Matrix<'_>,
2257    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2258        self.upload_step_bf16_column_parallel_inner(matrix, false)
2259    }
2260
2261    /// Load-time exact F32 expansion of a Step BF16 shard.
2262    ///
2263    /// The original BF16 allocation is released after the stream-ordered conversion. Decode then
2264    /// reuses the resident F32 values with the same topology-invariant output-row chunks.
2265    pub fn upload_step_bf16_column_parallel_f32_mirror(
2266        &self,
2267        matrix: Bf16Matrix<'_>,
2268    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2269        self.upload_step_bf16_column_parallel_inner(matrix, true)
2270    }
2271
2272    fn upload_step_bf16_column_parallel_inner(
2273        &self,
2274        matrix: Bf16Matrix<'_>,
2275        f32_mirror: bool,
2276    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2277        let canonical_chunk_rows =
2278            step_bf16_canonical_chunk_rows(matrix.out_features, self.ranks.len())?;
2279        self.upload_bf16_column_parallel_inner(matrix, Some(canonical_chunk_rows), f32_mirror)
2280    }
2281
2282    fn upload_bf16_column_parallel_inner(
2283        &self,
2284        matrix: Bf16Matrix<'_>,
2285        canonical_chunk_rows: Option<usize>,
2286        f32_mirror: bool,
2287    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2288        matrix.validate()?;
2289        let tp = self.ranks.len();
2290        if matrix.out_features % tp != 0 {
2291            return Err(format!(
2292                "BF16 column-parallel out_features {} is not divisible by TP={tp}",
2293                matrix.out_features
2294            )
2295            .into());
2296        }
2297        let mut ranks = Vec::with_capacity(tp);
2298        for (rank, engine) in self.ranks.iter().enumerate() {
2299            ranks.push(upload_bf16_rank(
2300                engine,
2301                bf16_column_shard(matrix, tp, rank)?,
2302                f32_mirror,
2303            )?);
2304        }
2305        Ok(ResidentBf16ColumnParallel {
2306            ranks,
2307            out_features: matrix.out_features,
2308            in_features: matrix.in_features,
2309            canonical_chunk_rows,
2310        })
2311    }
2312
2313    pub fn bf16_column_parallel_resident(
2314        &self,
2315        matrix: &ResidentBf16ColumnParallel,
2316        activations: &[f32],
2317        tokens: usize,
2318    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2319        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2320        validate_activations(activations, tokens, matrix.in_features)?;
2321        let local_out = matrix.out_features / self.ranks.len();
2322        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2323        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2324        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2325            let output = run_resident_bf16_rank(
2326                engine,
2327                shard,
2328                activations,
2329                tokens,
2330                matrix.canonical_chunk_rows,
2331            )?;
2332            for token in 0..tokens {
2333                let src = &output[token * local_out..(token + 1) * local_out];
2334                let dst_start = token * matrix.out_features + rank * local_out;
2335                gathered[dst_start..dst_start + local_out].copy_from_slice(src);
2336            }
2337            rank_outputs.push(output);
2338        }
2339        Ok(ColumnParallelResult {
2340            gathered,
2341            rank_outputs,
2342        })
2343    }
2344
2345    /// Native-P2P twin of [`Self::bf16_column_parallel_resident`].
2346    ///
2347    /// The host-canonical activation is uploaded once on rank zero and peer-broadcast to the
2348    /// remaining ranks. Rank-local outputs are peer-gathered in token-major order before one root
2349    /// readback. This removes per-rank host staging but deliberately still returns a host oracle;
2350    /// attention and KV ownership are separate milestones.
2351    pub fn bf16_column_parallel_resident_native(
2352        &self,
2353        matrix: &ResidentBf16ColumnParallel,
2354        activations: &[f32],
2355        tokens: usize,
2356    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2357        let rank_outputs =
2358            self.bf16_column_parallel_resident_device_shards(matrix, activations, tokens)?;
2359        let local_out = matrix.out_features / self.ranks.len();
2360        self.gather_native_column_shards(&rank_outputs, tokens, local_out)
2361    }
2362
2363    /// Keep Step BF16 column outputs resident on their owning TP ranks.
2364    ///
2365    /// Rank zero receives the host-canonical activation once and peer-broadcasts it when TP>1.
2366    /// Unlike [`Self::bf16_column_parallel_resident_native`], this method performs no output
2367    /// gather or readback. It is the correctness substrate for rank-local norm, RoPE, attention,
2368    /// and cache ownership; callers must not treat its existence as serving qualification.
2369    pub fn bf16_column_parallel_resident_device_shards(
2370        &self,
2371        matrix: &ResidentBf16ColumnParallel,
2372        activations: &[f32],
2373        tokens: usize,
2374    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2375        if self.ranks.len() > 1 && !self.native_p2p {
2376            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
2377        }
2378        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2379        validate_activations(activations, tokens, matrix.in_features)?;
2380
2381        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
2382        let root_input = {
2383            let root = &self.ranks[0];
2384            let _main = root.gpu.enter_main()?;
2385            root.htod(activations)?
2386        };
2387        // PRODUCER FENCE (2026-08-20 flake fix): the peer broadcast below reads this buffer from
2388        // the OTHER ranks' streams, and clone_htod is asynchronous on the root stream. Without
2389        // this fence a peer copy can overtake the in-flight H2D and replicate stale bytes — the
2390        // measured ~30%-of-boots prefill/decode argmax flake. Same discipline as
2391        // `upload_replicated_device_rows`.
2392        {
2393            let root = &self.ranks[0];
2394            let _main = root.gpu.enter_main()?;
2395            root.stream().synchronize()?;
2396        }
2397        rank_inputs.push(root_input);
2398        for engine in &self.ranks[1..] {
2399            let peer_input = {
2400                let _main = engine.gpu.enter_main()?;
2401                let mut peer_input = engine.uninit(activations.len())?;
2402                engine
2403                    .stream()
2404                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
2405                peer_input
2406            };
2407            rank_inputs.push(peer_input);
2408        }
2409
2410        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2411        for rank in 0..self.ranks.len() {
2412            rank_outputs.push(run_resident_bf16_rank_device(
2413                &self.ranks[rank],
2414                &matrix.ranks[rank],
2415                &rank_inputs[rank],
2416                tokens,
2417                matrix.canonical_chunk_rows,
2418                self.bulk_p2p,
2419            )?);
2420        }
2421        Ok(rank_outputs)
2422    }
2423
2424    /// Allocate one fixed-shape replicated batch without initializing its contents.
2425    ///
2426    /// Callers must refresh every rank before passing the batch to an operator.
2427    pub fn allocate_replicated_device_rows(
2428        &self,
2429        tokens: usize,
2430        width: usize,
2431    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2432        if self.ranks.len() > 1 && !self.native_p2p {
2433            return Err("replicated device rows require native P2P ranks".into());
2434        }
2435        let values = tokens
2436            .checked_mul(width)
2437            .ok_or("replicated device row size overflow")?;
2438        let rank_lengths = vec![values; self.ranks.len()];
2439        replicated_device_row_values(tokens, width, self.ranks.len(), &rank_lengths)?;
2440        let mut ranks = Vec::with_capacity(self.ranks.len());
2441        for engine in &self.ranks {
2442            let _main = engine.gpu.enter_main()?;
2443            ranks.push(engine.uninit(values)?);
2444        }
2445        Ok(ResidentReplicatedDeviceRows {
2446            ranks,
2447            tokens,
2448            width,
2449        })
2450    }
2451
2452    /// Replace a fixed-shape replicated batch from a root-device source.
2453    pub fn refresh_replicated_device_rows_from_root(
2454        &self,
2455        rows: &mut ResidentReplicatedDeviceRows,
2456        source: &CudaSlice<f32>,
2457    ) -> Result<(), Box<dyn std::error::Error>> {
2458        if self.ranks.len() > 1 && !self.native_p2p {
2459            return Err("replicated device rows require native P2P ranks".into());
2460        }
2461        validate_replicated_device_rows(&self.ranks, rows)?;
2462        let root = self
2463            .ranks
2464            .first()
2465            .ok_or("replicated rows have no root rank")?;
2466        let values = replicated_device_row_source_values(
2467            rows.tokens,
2468            rows.width,
2469            source.len(),
2470            source.ordinal(),
2471            root.ctx().ordinal(),
2472        )?;
2473        let (root_rows, peer_rows) = rows
2474            .ranks
2475            .split_first_mut()
2476            .ok_or("replicated rows have no root allocation")?;
2477        {
2478            let _main = root.gpu.enter_main()?;
2479            let mut destination = root_rows.slice_mut(0..values);
2480            root.stream()
2481                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
2482            root.stream().synchronize()?;
2483        }
2484        for (engine, peer_rows) in self.ranks.iter().skip(1).zip(peer_rows) {
2485            let _main = engine.gpu.enter_main()?;
2486            let mut destination = peer_rows.slice_mut(0..values);
2487            engine
2488                .stream()
2489                .memcpy_dtod(&root_rows.slice(0..values), &mut destination)?;
2490        }
2491        Ok(())
2492    }
2493
2494    /// Upload one canonical batch on rank zero and replicate it over native P2P.
2495    pub fn upload_replicated_device_rows(
2496        &self,
2497        rows: &[f32],
2498        tokens: usize,
2499        width: usize,
2500    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2501        if self.ranks.len() > 1 && !self.native_p2p {
2502            return Err("replicated device rows require native P2P ranks".into());
2503        }
2504        validate_activations(rows, tokens, width)?;
2505        let root = self
2506            .ranks
2507            .first()
2508            .ok_or("replicated rows have no root rank")?;
2509        let root_rows = {
2510            let _main = root.gpu.enter_main()?;
2511            root.htod(rows)?
2512        };
2513        {
2514            let _main = root.gpu.enter_main()?;
2515            root.stream().synchronize()?;
2516        }
2517        let mut ranks = Vec::with_capacity(self.ranks.len());
2518        ranks.push(root_rows);
2519        for engine in self.ranks.iter().skip(1) {
2520            let _main = engine.gpu.enter_main()?;
2521            let mut peer_rows = engine.uninit(rows.len())?;
2522            engine.stream().memcpy_dtod(&ranks[0], &mut peer_rows)?;
2523            ranks.push(peer_rows);
2524        }
2525        Ok(ResidentReplicatedDeviceRows {
2526            ranks,
2527            tokens,
2528            width,
2529        })
2530    }
2531
2532    /// Execute a column-parallel BF16 matrix directly from rank-local replicated inputs.
2533    pub fn bf16_column_parallel_resident_replicated_device_shards(
2534        &self,
2535        matrix: &ResidentBf16ColumnParallel,
2536        activations: &ResidentReplicatedDeviceRows,
2537    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2538        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2539        validate_replicated_device_rows(&self.ranks, activations)?;
2540        if activations.width != matrix.in_features {
2541            return Err(format!(
2542                "replicated BF16 column input width {} != matrix width {}",
2543                activations.width, matrix.in_features
2544            )
2545            .into());
2546        }
2547        let mut outputs = Vec::with_capacity(self.ranks.len());
2548        for rank in 0..self.ranks.len() {
2549            outputs.push(run_resident_bf16_rank_device(
2550                &self.ranks[rank],
2551                &matrix.ranks[rank],
2552                &activations.ranks[rank],
2553                activations.tokens,
2554                matrix.canonical_chunk_rows,
2555                self.bulk_p2p,
2556            )?);
2557        }
2558        Ok(outputs)
2559    }
2560
2561    /// Upload a BF16 router once on rank zero and retain its exact F32 expansion.
2562    #[allow(clippy::too_many_arguments)]
2563    pub fn upload_sigmoid_topk_router(
2564        &self,
2565        weight: Bf16Matrix<'_>,
2566        correction_bias: &[f32],
2567        active: Option<&[bool]>,
2568        experts_per_token: usize,
2569        scaling_factor: f32,
2570        route_norm: bool,
2571    ) -> Result<ResidentSigmoidTopKRouter, Box<dyn std::error::Error>> {
2572        weight.validate()?;
2573        if correction_bias.len() != weight.out_features
2574            || experts_per_token == 0
2575            || experts_per_token > weight.out_features
2576            || !correction_bias.iter().all(|value| value.is_finite())
2577            || !scaling_factor.is_finite()
2578            || scaling_factor <= 0.0
2579        {
2580            return Err(format!(
2581                "sigmoid router geometry weight={}x{} bias={} top_k={} scale={scaling_factor}",
2582                weight.out_features,
2583                weight.in_features,
2584                correction_bias.len(),
2585                experts_per_token,
2586            )
2587            .into());
2588        }
2589        let active_row = active
2590            .map(|mask| {
2591                if mask.len() != weight.out_features {
2592                    return Err(format!(
2593                        "sigmoid router active mask {} != experts {}",
2594                        mask.len(),
2595                        weight.out_features
2596                    ));
2597                }
2598                Ok(mask
2599                    .iter()
2600                    .map(|&enabled| u8::from(enabled))
2601                    .collect::<Vec<_>>())
2602            })
2603            .transpose()?
2604            .unwrap_or_else(|| vec![1; weight.out_features]);
2605        let active_count = active_row.iter().filter(|&&enabled| enabled != 0).count();
2606        crate::sigrouter_contract::validate_active_count(experts_per_token, active_count)?;
2607
2608        let root = self
2609            .ranks
2610            .first()
2611            .ok_or("sigmoid router runtime has no root rank")?;
2612        let _main = root.gpu.enter_main()?;
2613        let bf16 = root.htod_bytes(weight.bytes)?;
2614        let weight_f32 = root.bf16_to_f32(
2615            &bf16.slice(0..bf16.len()),
2616            weight.out_features * weight.in_features,
2617        )?;
2618        Ok(ResidentSigmoidTopKRouter {
2619            weight: weight_f32,
2620            correction_bias: root.htod(correction_bias)?,
2621            active: root.htod_bytes(&active_row)?,
2622            root_device: root.ctx().ordinal(),
2623            input_width: weight.in_features,
2624            expert_count: weight.out_features,
2625            experts_per_token,
2626            active_count,
2627            scaling_factor,
2628            route_norm,
2629        })
2630    }
2631
2632    /// Route rank-zero replicated rows and return the narrow host control result plus logits.
2633    ///
2634    /// The logits readback exists for independent oracle comparison. This method is a correctness
2635    /// surface; a serving scheduler may retain logits and selected routes on device.
2636    pub fn sigmoid_topk_replicated_device_rows_host(
2637        &self,
2638        router: &ResidentSigmoidTopKRouter,
2639        input: &ResidentReplicatedDeviceRows,
2640    ) -> Result<SigmoidTopKHostOutput, Box<dyn std::error::Error>> {
2641        validate_replicated_device_rows(&self.ranks, input)?;
2642        if input.width != router.input_width {
2643            return Err(format!(
2644                "sigmoid router input width {} != resident width {}",
2645                input.width, router.input_width
2646            )
2647            .into());
2648        }
2649        let root = self
2650            .ranks
2651            .first()
2652            .ok_or("sigmoid router runtime has no root rank")?;
2653        let _main = root.gpu.enter_main()?;
2654        if root.ctx().ordinal() != router.root_device
2655            || router.weight.ordinal() != router.root_device
2656            || router.correction_bias.ordinal() != router.root_device
2657            || router.active.ordinal() != router.root_device
2658        {
2659            return Err("sigmoid router root residency changed".into());
2660        }
2661        let logits = root.router_gemv(
2662            &router.weight,
2663            &input.ranks[0],
2664            router.input_width,
2665            router.expert_count,
2666            input.tokens,
2667        )?;
2668        let (selected, weights) = root.moe_router_sigmoid_topk_host(
2669            &logits,
2670            input.tokens,
2671            router.expert_count,
2672            router.experts_per_token,
2673            router.active_count,
2674            &router.correction_bias,
2675            &router.active,
2676            router.scaling_factor,
2677            router.route_norm,
2678        )?;
2679        Ok(SigmoidTopKHostOutput {
2680            logits: root.dtoh(&logits)?,
2681            selected,
2682            weights,
2683        })
2684    }
2685
2686    /// Replicate a full BF16 SwiGLU bank on every rank.
2687    pub fn upload_replicated_bf16_swiglu(
2688        &self,
2689        gate: Bf16Matrix<'_>,
2690        up: Bf16Matrix<'_>,
2691        down: Bf16Matrix<'_>,
2692    ) -> Result<ResidentReplicatedBf16SwiGlu, Box<dyn std::error::Error>> {
2693        gate.validate()?;
2694        up.validate()?;
2695        down.validate()?;
2696        if gate.in_features != up.in_features
2697            || gate.out_features != up.out_features
2698            || down.in_features != gate.out_features
2699            || down.out_features != gate.in_features
2700        {
2701            return Err(format!(
2702                "replicated BF16 SwiGLU geometry gate={}x{} up={}x{} down={}x{}",
2703                gate.out_features,
2704                gate.in_features,
2705                up.out_features,
2706                up.in_features,
2707                down.out_features,
2708                down.in_features,
2709            )
2710            .into());
2711        }
2712        let mut gate_ranks = Vec::with_capacity(self.ranks.len());
2713        let mut up_ranks = Vec::with_capacity(self.ranks.len());
2714        let mut down_ranks = Vec::with_capacity(self.ranks.len());
2715        for engine in &self.ranks {
2716            gate_ranks.push(upload_bf16_rank(engine, gate, false)?);
2717            up_ranks.push(upload_bf16_rank(engine, up, false)?);
2718            down_ranks.push(upload_bf16_rank(engine, down, false)?);
2719        }
2720        Ok(ResidentReplicatedBf16SwiGlu {
2721            gate: gate_ranks,
2722            up: up_ranks,
2723            down: down_ranks,
2724            input_width: gate.in_features,
2725            intermediate_width: gate.out_features,
2726        })
2727    }
2728
2729    /// Execute a fully replicated BF16 SwiGLU directly from replicated device rows.
2730    pub fn replicated_bf16_swiglu_resident_device(
2731        &self,
2732        mlp: &ResidentReplicatedBf16SwiGlu,
2733        input: &ResidentReplicatedDeviceRows,
2734        activation_limit: Option<f32>,
2735    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2736        validate_step_expert_activation_limit(activation_limit)?;
2737        validate_replicated_device_rows(&self.ranks, input)?;
2738        validate_resident_bf16_ranks(&self.ranks, &mlp.gate)?;
2739        validate_resident_bf16_ranks(&self.ranks, &mlp.up)?;
2740        validate_resident_bf16_ranks(&self.ranks, &mlp.down)?;
2741        if input.width != mlp.input_width
2742            || mlp.gate.len() != self.ranks.len()
2743            || mlp.up.len() != self.ranks.len()
2744            || mlp.down.len() != self.ranks.len()
2745        {
2746            return Err("replicated BF16 SwiGLU residency or input width changed".into());
2747        }
2748
2749        let mut outputs = Vec::with_capacity(self.ranks.len());
2750        for rank in 0..self.ranks.len() {
2751            let engine = &self.ranks[rank];
2752            let gate = run_resident_bf16_rank_device(
2753                engine,
2754                &mlp.gate[rank],
2755                &input.ranks[rank],
2756                input.tokens,
2757                None,
2758                self.bulk_p2p,
2759            )?;
2760            let up = run_resident_bf16_rank_device(
2761                engine,
2762                &mlp.up[rank],
2763                &input.ranks[rank],
2764                input.tokens,
2765                None,
2766                self.bulk_p2p,
2767            )?;
2768            let _main = engine.gpu.enter_main()?;
2769            let values = input
2770                .tokens
2771                .checked_mul(mlp.intermediate_width)
2772                .ok_or("replicated BF16 SwiGLU activation size overflow")?;
2773            let mut activation = engine.uninit(values)?;
2774            if let Some(limit) = activation_limit {
2775                engine.silu_clamped_mul_host_expf(&gate, &up, limit, &mut activation, values)?;
2776            } else {
2777                engine.silu_mul_host_expf(&gate, &up, &mut activation, values)?;
2778            }
2779            outputs.push(run_resident_bf16_rank_device(
2780                engine,
2781                &mlp.down[rank],
2782                &activation,
2783                input.tokens,
2784                None,
2785                self.bulk_p2p,
2786            )?);
2787        }
2788        Ok(ResidentReplicatedDeviceRows {
2789            ranks: outputs,
2790            tokens: input.tokens,
2791            width: mlp.input_width,
2792        })
2793    }
2794
2795    /// Apply the same RMS-norm row program independently on every replicated rank.
2796    pub fn rms_norm_replicated_device_rows(
2797        &self,
2798        input: &ResidentReplicatedDeviceRows,
2799        weight: &[f32],
2800        eps: f32,
2801    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2802        validate_replicated_device_rows(&self.ranks, input)?;
2803        if weight.len() != input.width || !eps.is_finite() || eps <= 0.0 {
2804            return Err(format!(
2805                "replicated RMS norm weight/eps {}/{} != width {}",
2806                weight.len(),
2807                eps,
2808                input.width
2809            )
2810            .into());
2811        }
2812        let mut ranks = Vec::with_capacity(self.ranks.len());
2813        for (rank, engine) in self.ranks.iter().enumerate() {
2814            let _main = engine.gpu.enter_main()?;
2815            let weight = engine.htod(weight)?;
2816            let mut output = engine.uninit(input.tokens * input.width)?;
2817            engine.rms_norm(
2818                &input.ranks[rank],
2819                &weight,
2820                &mut output,
2821                input.width,
2822                input.tokens,
2823                eps,
2824            )?;
2825            ranks.push(output);
2826        }
2827        Ok(ResidentReplicatedDeviceRows {
2828            ranks,
2829            tokens: input.tokens,
2830            width: input.width,
2831        })
2832    }
2833
2834    /// Add two replicated batches and RMS-normalize the exact residual on every rank.
2835    pub fn add_rms_norm_replicated_device_rows(
2836        &self,
2837        input: &ResidentReplicatedDeviceRows,
2838        update: &ResidentReplicatedDeviceRows,
2839        weight: &[f32],
2840        eps: f32,
2841    ) -> Result<
2842        (ResidentReplicatedDeviceRows, ResidentReplicatedDeviceRows),
2843        Box<dyn std::error::Error>,
2844    > {
2845        validate_replicated_device_rows(&self.ranks, input)?;
2846        validate_replicated_device_rows(&self.ranks, update)?;
2847        if input.tokens != update.tokens
2848            || input.width != update.width
2849            || weight.len() != input.width
2850            || !eps.is_finite()
2851            || eps <= 0.0
2852        {
2853            return Err(format!(
2854                "replicated add/RMS geometry input={}x{} update={}x{} weight={} eps={eps}",
2855                input.tokens,
2856                input.width,
2857                update.tokens,
2858                update.width,
2859                weight.len(),
2860            )
2861            .into());
2862        }
2863        let values = input.tokens * input.width;
2864        let mut residual_ranks = Vec::with_capacity(self.ranks.len());
2865        let mut normalized_ranks = Vec::with_capacity(self.ranks.len());
2866        for (rank, engine) in self.ranks.iter().enumerate() {
2867            let _main = engine.gpu.enter_main()?;
2868            let weight = engine.htod(weight)?;
2869            let mut residual = engine.uninit(values)?;
2870            let mut normalized = engine.uninit(values)?;
2871            engine.add_rms_norm(
2872                &input.ranks[rank],
2873                &update.ranks[rank],
2874                &weight,
2875                &mut residual,
2876                &mut normalized,
2877                input.width,
2878                input.tokens,
2879                eps,
2880            )?;
2881            residual_ranks.push(residual);
2882            normalized_ranks.push(normalized);
2883        }
2884        Ok((
2885            ResidentReplicatedDeviceRows {
2886                ranks: residual_ranks,
2887                tokens: input.tokens,
2888                width: input.width,
2889            },
2890            ResidentReplicatedDeviceRows {
2891                ranks: normalized_ranks,
2892                tokens: input.tokens,
2893                width: input.width,
2894            },
2895        ))
2896    }
2897
2898    pub fn collect_replicated_device_rows(
2899        &self,
2900        rows: &ResidentReplicatedDeviceRows,
2901    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
2902        validate_replicated_device_rows(&self.ranks, rows)?;
2903        let mut outputs = Vec::with_capacity(self.ranks.len());
2904        for (rank, engine) in self.ranks.iter().enumerate() {
2905            let _main = engine.gpu.enter_main()?;
2906            outputs.push(engine.dtoh(&rows.ranks[rank])?);
2907        }
2908        Ok(outputs)
2909    }
2910
2911    pub fn upload_bf16_row_parallel(
2912        &self,
2913        matrix: Bf16Matrix<'_>,
2914    ) -> Result<ResidentBf16RowParallel, Box<dyn std::error::Error>> {
2915        matrix.validate()?;
2916        let tp = self.ranks.len();
2917        if matrix.in_features % tp != 0 {
2918            return Err(format!(
2919                "BF16 row-parallel in_features {} is not divisible by TP={tp}",
2920                matrix.in_features
2921            )
2922            .into());
2923        }
2924        let mut ranks = Vec::with_capacity(tp);
2925        for (rank, engine) in self.ranks.iter().enumerate() {
2926            let shard = bf16_row_shard(matrix, tp, rank)?;
2927            ranks.push(upload_bf16_rank(
2928                engine,
2929                Bf16Matrix {
2930                    bytes: &shard,
2931                    out_features: matrix.out_features,
2932                    in_features: matrix.in_features / tp,
2933                },
2934                false,
2935            )?);
2936        }
2937        Ok(ResidentBf16RowParallel {
2938            ranks,
2939            out_features: matrix.out_features,
2940            in_features: matrix.in_features,
2941        })
2942    }
2943
2944    pub fn bf16_row_parallel_resident(
2945        &self,
2946        matrix: &ResidentBf16RowParallel,
2947        activations: &[f32],
2948        tokens: usize,
2949    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2950        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2951        validate_activations(activations, tokens, matrix.in_features)?;
2952        let tp = self.ranks.len();
2953        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2954        let mut rank_partials = Vec::with_capacity(tp);
2955        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2956            let local_activations =
2957                activation_shard(activations, tokens, matrix.in_features, tp, rank);
2958            let partial = run_resident_bf16_rank(engine, shard, &local_activations, tokens, None)?;
2959            for (sum, value) in reduced.iter_mut().zip(&partial) {
2960                *sum += value;
2961            }
2962            rank_partials.push(partial);
2963        }
2964        Ok(RowParallelResult {
2965            reduced,
2966            rank_partials,
2967        })
2968    }
2969
2970    /// Step-3.7 row projection split into the same eight global K blocks for TP1/TP2/TP4/TP8.
2971    pub fn upload_step_bf16_row_parallel(
2972        &self,
2973        matrix: Bf16Matrix<'_>,
2974    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
2975        self.upload_step_bf16_row_parallel_inner(matrix, false)
2976    }
2977
2978    pub fn upload_step_bf16_row_parallel_f32_mirror(
2979        &self,
2980        matrix: Bf16Matrix<'_>,
2981    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
2982        self.upload_step_bf16_row_parallel_inner(matrix, true)
2983    }
2984
2985    fn upload_step_bf16_row_parallel_inner(
2986        &self,
2987        matrix: Bf16Matrix<'_>,
2988        f32_mirror: bool,
2989    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
2990        matrix.validate()?;
2991        let tp = self.ranks.len();
2992        let canonical_chunk_cols = step_bf16_canonical_chunk_cols(matrix.in_features, tp)?;
2993        let local_in = matrix.in_features / tp;
2994        let blocks_per_rank = local_in / canonical_chunk_cols;
2995        let mut ranks = Vec::with_capacity(tp);
2996        for (rank, engine) in self.ranks.iter().enumerate() {
2997            let mut blocks = Vec::with_capacity(blocks_per_rank);
2998            for block in 0..blocks_per_rank {
2999                let global_block = rank * blocks_per_rank + block;
3000                let col_start = global_block * canonical_chunk_cols;
3001                let bytes = bf16_row_block(matrix, col_start, canonical_chunk_cols)?;
3002                blocks.push(upload_bf16_rank(
3003                    engine,
3004                    Bf16Matrix {
3005                        bytes: &bytes,
3006                        out_features: matrix.out_features,
3007                        in_features: canonical_chunk_cols,
3008                    },
3009                    f32_mirror,
3010                )?);
3011            }
3012            ranks.push(blocks);
3013        }
3014        Ok(ResidentStepBf16RowParallel {
3015            ranks,
3016            out_features: matrix.out_features,
3017            in_features: matrix.in_features,
3018            canonical_chunk_cols,
3019        })
3020    }
3021
3022    /// Host-staged exactness twin of [`Self::step_bf16_row_parallel_resident_native`].
3023    ///
3024    /// Block inputs and partials cross host memory, but every partial is added on the root device
3025    /// in global checkpoint-column order. Native transport must reproduce this result bitwise.
3026    pub fn step_bf16_row_parallel_resident(
3027        &self,
3028        matrix: &ResidentStepBf16RowParallel,
3029        activations: &[f32],
3030        tokens: usize,
3031    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3032        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3033        validate_activations(activations, tokens, matrix.in_features)?;
3034        let root = &self.ranks[0];
3035        let output_len = tokens
3036            .checked_mul(matrix.out_features)
3037            .ok_or("Step BF16 row output size overflow")?;
3038        let mut reduced = {
3039            let _main = root.gpu.enter_main()?;
3040            root.htod(&vec![0.0f32; output_len])?
3041        };
3042        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3043        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3044            for (block, resident) in blocks.iter().enumerate() {
3045                let global_block = rank * blocks_per_rank + block;
3046                let input = activation_shard(
3047                    activations,
3048                    tokens,
3049                    matrix.in_features,
3050                    PRODUCT_MAX_CARDS,
3051                    global_block,
3052                );
3053                let partial =
3054                    run_resident_bf16_rank(&self.ranks[rank], resident, &input, tokens, None)?;
3055                let next = {
3056                    let _main = root.gpu.enter_main()?;
3057                    let partial = root.htod(&partial)?;
3058                    let mut next = root.uninit(output_len)?;
3059                    root.add(&reduced, &partial, &mut next, output_len)?;
3060                    next
3061                };
3062                reduced = next;
3063            }
3064        }
3065        let _main = root.gpu.enter_main()?;
3066        root.dtoh(&reduced)
3067    }
3068
3069    /// Native-P2P Step row projection with canonical global K-block reduction.
3070    ///
3071    /// The full activation is uploaded once on the root. Each TP8-sized block is peer-scattered
3072    /// to its owning rank, its BF16 partial is peer-returned to the root, and root-device adds
3073    /// replay the same eight-block order as TP1 and the host-staged oracle.
3074    pub fn step_bf16_row_parallel_resident_native(
3075        &self,
3076        matrix: &ResidentStepBf16RowParallel,
3077        activations: &[f32],
3078        tokens: usize,
3079    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3080        if self.ranks.len() > 1 && !self.native_p2p {
3081            return Err("native Step BF16 row parallelism requires P2P ranks".into());
3082        }
3083        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3084        validate_activations(activations, tokens, matrix.in_features)?;
3085        let root = &self.ranks[0];
3086        let root_input = {
3087            let _main = root.gpu.enter_main()?;
3088            root.htod(activations)?
3089        };
3090        let output_len = tokens
3091            .checked_mul(matrix.out_features)
3092            .ok_or("native Step BF16 row output size overflow")?;
3093        let mut reduced = {
3094            let _main = root.gpu.enter_main()?;
3095            root.htod(&vec![0.0f32; output_len])?
3096        };
3097        // PRODUCER FENCE (2026-08-20 flake fix): the non-bulk arm below peer-reads root_input
3098        // from the other ranks' streams while root's clone_htod may still be in flight.
3099        {
3100            let _main = root.gpu.enter_main()?;
3101            root.stream().synchronize()?;
3102        }
3103        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3104        let mut block_input_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3105        let mut root_packed_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3106        let mut remote_partial_keepalive = Vec::new();
3107        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3108            for (block, resident) in blocks.iter().enumerate() {
3109                let global_block = rank * blocks_per_rank + block;
3110                let col_start = global_block * matrix.canonical_chunk_cols;
3111                let block_len = tokens
3112                    .checked_mul(matrix.canonical_chunk_cols)
3113                    .ok_or("native Step BF16 row block size overflow")?;
3114                let block_input = if self.bulk_p2p {
3115                    let root_packed = {
3116                        let _main = root.gpu.enter_main()?;
3117                        let mut root_packed = root.uninit(block_len)?;
3118                        root.copy_rows_strided(
3119                            &root_input,
3120                            &mut root_packed,
3121                            matrix.canonical_chunk_cols,
3122                            tokens,
3123                            matrix.in_features,
3124                            col_start,
3125                        )?;
3126                        root_packed
3127                    };
3128                    if rank == 0 {
3129                        root_packed
3130                    } else {
3131                        // PRODUCER FENCE (2026-08-20 flake fix): the pack kernel runs on the
3132                        // root stream; this rank's peer read must not overtake it.
3133                        {
3134                            let _main = root.gpu.enter_main()?;
3135                            root.stream().synchronize()?;
3136                        }
3137                        let engine = &self.ranks[rank];
3138                        let _main = engine.gpu.enter_main()?;
3139                        let mut block_input = engine.uninit(block_len)?;
3140                        engine
3141                            .stream()
3142                            .memcpy_dtod(&root_packed, &mut block_input)?;
3143                        root_packed_keepalive.push(root_packed);
3144                        block_input
3145                    }
3146                } else {
3147                    let engine = &self.ranks[rank];
3148                    let _main = engine.gpu.enter_main()?;
3149                    let mut block_input = engine.uninit(block_len)?;
3150                    for token in 0..tokens {
3151                        let source_start = token * matrix.in_features + col_start;
3152                        let source = root_input
3153                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3154                        let destination_start = token * matrix.canonical_chunk_cols;
3155                        let mut destination = block_input.slice_mut(
3156                            destination_start..destination_start + matrix.canonical_chunk_cols,
3157                        );
3158                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3159                    }
3160                    block_input
3161                };
3162                let partial = run_resident_bf16_rank_device(
3163                    &self.ranks[rank],
3164                    resident,
3165                    &block_input,
3166                    tokens,
3167                    None,
3168                    self.bulk_p2p,
3169                )?;
3170                block_input_keepalive.push(block_input);
3171                let root_partial = if rank == 0 {
3172                    partial
3173                } else {
3174                    // PRODUCER FENCE (2026-08-20 flake fix): the partial was produced by this
3175                    // rank's kernel on its own stream; root's peer read must not overtake it.
3176                    {
3177                        let engine = &self.ranks[rank];
3178                        let _main = engine.gpu.enter_main()?;
3179                        engine.stream().synchronize()?;
3180                    }
3181                    let _main = root.gpu.enter_main()?;
3182                    let mut peer_partial = root.uninit(output_len)?;
3183                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
3184                    remote_partial_keepalive.push(partial);
3185                    peer_partial
3186                };
3187                let next = {
3188                    let _main = root.gpu.enter_main()?;
3189                    let mut next = root.uninit(output_len)?;
3190                    root.add(&reduced, &root_partial, &mut next, output_len)?;
3191                    next
3192                };
3193                reduced = next;
3194            }
3195        }
3196        let output = {
3197            let _main = root.gpu.enter_main()?;
3198            root.dtoh(&reduced)?
3199        };
3200        drop(remote_partial_keepalive);
3201        drop(root_packed_keepalive);
3202        drop(block_input_keepalive);
3203        Ok(output)
3204    }
3205
3206    /// Reduce rank-local Step attention shards in canonical TP8 K-block order and keep the result
3207    /// on the root device.
3208    pub fn step_bf16_row_parallel_resident_root_device(
3209        &self,
3210        matrix: &ResidentStepBf16RowParallel,
3211        rank_activations: &[CudaSlice<f32>],
3212        tokens: usize,
3213    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3214        if self.ranks.len() > 1 && !self.native_p2p {
3215            return Err(
3216                "device-resident Step BF16 row parallelism requires native P2P ranks".into(),
3217            );
3218        }
3219        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3220        let local_width = matrix.in_features / self.ranks.len();
3221        let shard_len = tokens
3222            .checked_mul(local_width)
3223            .ok_or("device Step BF16 row shard size overflow")?;
3224        if tokens == 0
3225            || rank_activations.len() != self.ranks.len()
3226            || rank_activations
3227                .iter()
3228                .zip(&self.ranks)
3229                .any(|(rows, engine)| {
3230                    rows.len() != shard_len || rows.ordinal() != engine.ctx().ordinal()
3231                })
3232        {
3233            return Err("device Step BF16 row activation shard geometry changed".into());
3234        }
3235
3236        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3237        let mut block_inputs = Vec::with_capacity(self.ranks.len());
3238        let mut partials = Vec::with_capacity(self.ranks.len());
3239        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3240            if blocks.len() != blocks_per_rank {
3241                return Err(format!(
3242                    "device Step BF16 row rank {rank} blocks {} != {blocks_per_rank}",
3243                    blocks.len()
3244                )
3245                .into());
3246            }
3247            let engine = &self.ranks[rank];
3248            let _main = engine.gpu.enter_main()?;
3249            let mut rank_inputs = Vec::with_capacity(blocks_per_rank);
3250            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
3251            for (block, resident) in blocks.iter().enumerate() {
3252                let block_len = tokens
3253                    .checked_mul(matrix.canonical_chunk_cols)
3254                    .ok_or("device Step BF16 row block size overflow")?;
3255                let mut block_input = engine.uninit(block_len)?;
3256                let local_col_start = block * matrix.canonical_chunk_cols;
3257                if self.bulk_p2p {
3258                    engine.copy_rows_strided(
3259                        &rank_activations[rank],
3260                        &mut block_input,
3261                        matrix.canonical_chunk_cols,
3262                        tokens,
3263                        local_width,
3264                        local_col_start,
3265                    )?;
3266                } else {
3267                    for token in 0..tokens {
3268                        let source_start = token * local_width + local_col_start;
3269                        let source = rank_activations[rank]
3270                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3271                        let destination_start = token * matrix.canonical_chunk_cols;
3272                        let mut destination = block_input.slice_mut(
3273                            destination_start..destination_start + matrix.canonical_chunk_cols,
3274                        );
3275                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3276                    }
3277                }
3278                let partial = run_resident_bf16_rank_device(
3279                    engine,
3280                    resident,
3281                    &block_input,
3282                    tokens,
3283                    None,
3284                    self.bulk_p2p,
3285                )?;
3286                rank_inputs.push(block_input);
3287                rank_partials.push(partial);
3288            }
3289            block_inputs.push(rank_inputs);
3290            partials.push(rank_partials);
3291        }
3292        for engine in self.ranks.iter().skip(1) {
3293            let _main = engine.gpu.enter_main()?;
3294            engine.stream().synchronize()?;
3295        }
3296
3297        let output_len = tokens
3298            .checked_mul(matrix.out_features)
3299            .ok_or("device Step BF16 row output size overflow")?;
3300        let root = &self.ranks[0];
3301        let _main = root.gpu.enter_main()?;
3302        let mut reduced = root.htod(&vec![0.0f32; output_len])?;
3303        let mut remote_partials = Vec::new();
3304        for (rank, rank_partials) in partials.into_iter().enumerate() {
3305            for partial in rank_partials {
3306                let root_partial = if rank == 0 {
3307                    partial
3308                } else {
3309                    let mut peer_partial = root.uninit(output_len)?;
3310                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
3311                    remote_partials.push(partial);
3312                    peer_partial
3313                };
3314                let mut next = root.uninit(output_len)?;
3315                root.add(&reduced, &root_partial, &mut next, output_len)?;
3316                reduced = next;
3317            }
3318        }
3319        root.stream().synchronize()?;
3320        drop(remote_partials);
3321        drop(block_inputs);
3322        Ok(reduced)
3323    }
3324
3325    /// Reduce rank-local Step attention shards, then replicate the canonical root result.
3326    pub fn step_bf16_row_parallel_resident_replicated_device(
3327        &self,
3328        matrix: &ResidentStepBf16RowParallel,
3329        rank_activations: &[CudaSlice<f32>],
3330        tokens: usize,
3331    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3332        let reduced =
3333            self.step_bf16_row_parallel_resident_root_device(matrix, rank_activations, tokens)?;
3334        let output_len = tokens
3335            .checked_mul(matrix.out_features)
3336            .ok_or("device Step BF16 row output size overflow")?;
3337        let mut ranks = Vec::with_capacity(self.ranks.len());
3338        ranks.push(reduced);
3339        for engine in self.ranks.iter().skip(1) {
3340            let _main = engine.gpu.enter_main()?;
3341            let mut peer_output = engine.uninit(output_len)?;
3342            engine.stream().memcpy_dtod(&ranks[0], &mut peer_output)?;
3343            ranks.push(peer_output);
3344        }
3345        Ok(ResidentReplicatedDeviceRows {
3346            ranks,
3347            tokens,
3348            width: matrix.out_features,
3349        })
3350    }
3351
3352    pub fn upload_expert(
3353        &self,
3354        gate: E4m3BlockMatrix<'_>,
3355        up: E4m3BlockMatrix<'_>,
3356        down: E4m3BlockMatrix<'_>,
3357    ) -> Result<ResidentTpExpert, Box<dyn std::error::Error>> {
3358        if gate.in_features != up.in_features || gate.out_features != up.out_features {
3359            return Err("TP expert gate/up dimensions differ".into());
3360        }
3361        if down.in_features != gate.out_features || down.out_features != gate.in_features {
3362            return Err(format!(
3363                "TP expert down {}x{} does not invert gate/up {}x{}",
3364                down.out_features, down.in_features, gate.out_features, gate.in_features
3365            )
3366            .into());
3367        }
3368        Ok(ResidentTpExpert {
3369            gate: self.upload_column_parallel(gate)?,
3370            up: self.upload_column_parallel(up)?,
3371            down: self.upload_row_parallel(down)?,
3372            input_width: gate.in_features,
3373            expert_width: gate.out_features,
3374        })
3375    }
3376
3377    pub fn run_expert(
3378        &self,
3379        expert: &ResidentTpExpert,
3380        input: &[f32],
3381        tokens: usize,
3382    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3383        validate_activations(input, tokens, expert.input_width)?;
3384        let gate = self.column_parallel_resident(&expert.gate, input, tokens)?;
3385        let up = self.column_parallel_resident(&expert.up, input, tokens)?;
3386        let activated: Vec<f32> = gate
3387            .gathered
3388            .iter()
3389            .zip(&up.gathered)
3390            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
3391            .collect();
3392        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
3393        Ok(self
3394            .row_parallel_resident(&expert.down, &activated, tokens)?
3395            .reduced)
3396    }
3397
3398    pub fn upload_expert_parallel(
3399        &self,
3400        gate: E4m3ExpertBank<'_>,
3401        up: E4m3ExpertBank<'_>,
3402        down: E4m3ExpertBank<'_>,
3403    ) -> Result<ResidentExpertParallel, Box<dyn std::error::Error>> {
3404        gate.validate()?;
3405        up.validate()?;
3406        down.validate()?;
3407        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
3408            return Err("EP gate/up/down expert counts differ".into());
3409        }
3410        if gate.in_features != up.in_features || gate.out_features != up.out_features {
3411            return Err("EP gate/up dimensions differ".into());
3412        }
3413        if down.in_features != gate.out_features || down.out_features != gate.in_features {
3414            return Err(format!(
3415                "EP down {}x{} does not invert gate/up {}x{}",
3416                down.out_features, down.in_features, gate.out_features, gate.in_features
3417            )
3418            .into());
3419        }
3420        if gate.expert_count % self.ranks.len() != 0 {
3421            return Err(format!(
3422                "EP expert count {} is not divisible by {} ranks",
3423                gate.expert_count,
3424                self.ranks.len()
3425            )
3426            .into());
3427        }
3428
3429        let per_rank = gate.expert_count / self.ranks.len();
3430        let mut ranks = Vec::with_capacity(self.ranks.len());
3431        for (rank, engine) in self.ranks.iter().enumerate() {
3432            let expert_range = rank * per_rank..(rank + 1) * per_rank;
3433            ranks.push(ResidentEpRank {
3434                gate: upload_expert_bank_rank(engine, gate, expert_range.clone())?,
3435                up: upload_expert_bank_rank(engine, up, expert_range.clone())?,
3436                down: upload_expert_bank_rank(engine, down, expert_range)?,
3437            });
3438        }
3439        Ok(ResidentExpertParallel {
3440            ranks,
3441            expert_count: gate.expert_count,
3442            input_width: gate.in_features,
3443            expert_width: gate.out_features,
3444        })
3445    }
3446
3447    /// Prepare the official Step gate-only grouped-FP8 projection oracle on rank zero.
3448    ///
3449    /// This intentionally does not alter the resident EP path. It owns a full rank-local tensor
3450    /// bank solely so the grouped projection can be compared with the existing per-route oracle
3451    /// without routing, transport, or combine changing underneath it.
3452    #[allow(clippy::too_many_arguments)]
3453    pub fn prepare_step_grouped_fp8_gate(
3454        &self,
3455        gate: E4m3ExpertBank<'_>,
3456        up: E4m3ExpertBank<'_>,
3457        down: E4m3ExpertBank<'_>,
3458        input: &[f32],
3459        tokens: usize,
3460        selected: &[usize],
3461        activation_limit: Option<f32>,
3462    ) -> Result<PreparedStepGroupedFp8Gate, Box<dyn std::error::Error>> {
3463        gate.validate()?;
3464        up.validate()?;
3465        down.validate()?;
3466        validate_step_expert_activation_limit(activation_limit)?;
3467        if gate.expert_count != STEP_GROUPED_FP8_EXPERTS
3468            || up.expert_count != STEP_GROUPED_FP8_EXPERTS
3469            || down.expert_count != STEP_GROUPED_FP8_EXPERTS
3470        {
3471            return Err(format!(
3472                "official Step grouped FP8 gate requires {STEP_GROUPED_FP8_EXPERTS} experts, \
3473                 got gate/up/down={}/{}/{}",
3474                gate.expert_count, up.expert_count, down.expert_count,
3475            )
3476            .into());
3477        }
3478        if gate.in_features != up.in_features
3479            || gate.out_features != STEP_GROUPED_FP8_WIDTH
3480            || up.out_features != STEP_GROUPED_FP8_WIDTH
3481            || down.in_features != STEP_GROUPED_FP8_WIDTH
3482            || down.out_features != gate.in_features
3483        {
3484            return Err(format!(
3485                "official Step grouped FP8 geometry gate={}x{} up={}x{} down={}x{}",
3486                gate.out_features,
3487                gate.in_features,
3488                up.out_features,
3489                up.in_features,
3490                down.out_features,
3491                down.in_features,
3492            )
3493            .into());
3494        }
3495        validate_activations(input, tokens, gate.in_features)?;
3496        let pairs = tokens
3497            .checked_mul(STEP_GROUPED_FP8_TOP_K)
3498            .ok_or("official Step grouped FP8 route count overflow")?;
3499        if selected.len() != pairs {
3500            return Err(format!(
3501                "official Step grouped FP8 routes {} != {tokens}x{STEP_GROUPED_FP8_TOP_K} \
3502                 ({pairs})",
3503                selected.len()
3504            )
3505            .into());
3506        }
3507        for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
3508            let mut unique = routes.to_vec();
3509            unique.sort_unstable();
3510            unique.dedup();
3511            if unique.len() != STEP_GROUPED_FP8_TOP_K {
3512                return Err(format!(
3513                    "official Step grouped FP8 token {token} routes are not top-8 unique: \
3514                     {routes:?}"
3515                )
3516                .into());
3517            }
3518        }
3519
3520        let engine = self
3521            .ranks
3522            .first()
3523            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
3524        let _main = engine.gpu.enter_main()?;
3525        let expert_range = 0..STEP_GROUPED_FP8_EXPERTS;
3526        let gate = upload_expert_bank_rank(engine, gate, expert_range.clone())?;
3527        let up = upload_expert_bank_rank(engine, up, expert_range.clone())?;
3528        let down = upload_expert_bank_rank(engine, down, expert_range)?;
3529        let input = engine.htod(input)?;
3530        let route_csr = ExpertCsr::from_token_routes(
3531            STEP_GROUPED_FP8_EXPERTS,
3532            tokens,
3533            STEP_GROUPED_FP8_TOP_K,
3534            selected,
3535        )?
3536        .upload(engine)?;
3537        let pair_rows = (0..pairs).collect::<Vec<_>>();
3538        let down_csr =
3539            ExpertCsr::from_pair_rows(STEP_GROUPED_FP8_EXPERTS, pairs, selected, &pair_rows)?
3540                .upload(engine)?;
3541        let gate_workspace =
3542            Fp8GroupedWorkspace::new(engine, gate.in_features, gate.out_features, tokens, pairs)?;
3543        let up_workspace =
3544            Fp8GroupedWorkspace::new(engine, up.in_features, up.out_features, tokens, pairs)?;
3545        let down_workspace =
3546            Fp8GroupedWorkspace::new(engine, down.in_features, down.out_features, pairs, pairs)?;
3547        let activation = engine.uninit(pairs * STEP_GROUPED_FP8_WIDTH)?;
3548        Ok(PreparedStepGroupedFp8Gate {
3549            device: engine.ctx().ordinal(),
3550            gate,
3551            up,
3552            down,
3553            input,
3554            route_csr,
3555            down_csr,
3556            gate_workspace,
3557            up_workspace,
3558            down_workspace,
3559            activation,
3560            activation_limit,
3561            tokens,
3562            pairs,
3563        })
3564    }
3565
3566    /// Execute one prepared gate/up/activation/down projection sequence on rank zero.
3567    pub fn run_step_grouped_fp8_gate(
3568        &self,
3569        plan: &mut PreparedStepGroupedFp8Gate,
3570    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
3571        let engine = self
3572            .ranks
3573            .first()
3574            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
3575        if engine.ctx().ordinal() != plan.device {
3576            return Err(format!(
3577                "official Step grouped FP8 plan device {} != rank-zero device {}",
3578                plan.device,
3579                engine.ctx().ordinal()
3580            )
3581            .into());
3582        }
3583        let _main = engine.gpu.enter_main()?;
3584
3585        plan.gate_workspace.quantize(engine, &plan.input)?;
3586        plan.gate_workspace.project(
3587            engine,
3588            &plan.gate.codes,
3589            &plan.gate.scales,
3590            &plan.route_csr,
3591            plan.gate.code_stride,
3592            plan.gate.scale_stride,
3593            1.0,
3594        )?;
3595        plan.up_workspace.quantize(engine, &plan.input)?;
3596        plan.up_workspace.project(
3597            engine,
3598            &plan.up.codes,
3599            &plan.up.scales,
3600            &plan.route_csr,
3601            plan.up.code_stride,
3602            plan.up.scale_stride,
3603            1.0,
3604        )?;
3605        if let Some(limit) = plan.activation_limit {
3606            engine.silu_clamped_mul_host_expf(
3607                plan.gate_workspace.output(),
3608                plan.up_workspace.output(),
3609                limit,
3610                &mut plan.activation,
3611                plan.pairs * STEP_GROUPED_FP8_WIDTH,
3612            )?;
3613        } else {
3614            engine.silu_mul_host_expf(
3615                plan.gate_workspace.output(),
3616                plan.up_workspace.output(),
3617                &mut plan.activation,
3618                plan.pairs * STEP_GROUPED_FP8_WIDTH,
3619            )?;
3620        }
3621        plan.down_workspace.quantize(engine, &plan.activation)?;
3622        plan.down_workspace.project(
3623            engine,
3624            &plan.down.codes,
3625            &plan.down.scales,
3626            &plan.down_csr,
3627            plan.down.code_stride,
3628            plan.down.scale_stride,
3629            1.0,
3630        )?;
3631
3632        Ok(StepGroupedFp8ProjectionOutput {
3633            gate: engine.dtoh(plan.gate_workspace.output())?,
3634            up: engine.dtoh(plan.up_workspace.output())?,
3635            down: engine.dtoh(plan.down_workspace.output())?,
3636        })
3637    }
3638
3639    pub fn prepare_step_grouped_expert_parallel_gate(
3640        &self,
3641        experts: &ResidentExpertParallel,
3642        input: &[f32],
3643        tokens: usize,
3644        selected: &[usize],
3645        activation_limit: Option<f32>,
3646    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
3647        self.prepare_step_grouped_expert_parallel_gate_with_capacity(
3648            experts,
3649            input,
3650            tokens,
3651            selected,
3652            activation_limit,
3653            tokens,
3654        )
3655    }
3656
3657    #[allow(clippy::too_many_arguments)]
3658    pub fn prepare_step_grouped_expert_parallel_gate_with_capacity(
3659        &self,
3660        experts: &ResidentExpertParallel,
3661        input: &[f32],
3662        tokens: usize,
3663        selected: &[usize],
3664        activation_limit: Option<f32>,
3665        max_tokens: usize,
3666    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
3667        if !self.native_p2p || !self.ep_device_arithmetic {
3668            return Err(
3669                "Step owner-grouped FP8 requires native P2P and device-resident arithmetic".into(),
3670            );
3671        }
3672        validate_step_expert_activation_limit(activation_limit)?;
3673        validate_ep_residency(&self.ranks, experts)?;
3674        validate_activations(input, tokens, experts.input_width)?;
3675        if max_tokens < tokens || max_tokens > i32::MAX as usize {
3676            return Err(format!(
3677                "official Step owner-grouped FP8 tokens {tokens} exceed capacity {max_tokens}"
3678            )
3679            .into());
3680        }
3681        if experts.expert_count != STEP_GROUPED_FP8_EXPERTS
3682            || experts.expert_width != STEP_GROUPED_FP8_WIDTH
3683        {
3684            return Err(format!(
3685                "official Step owner-grouped FP8 requires {} experts at width {}, got {} at {}",
3686                STEP_GROUPED_FP8_EXPERTS,
3687                STEP_GROUPED_FP8_WIDTH,
3688                experts.expert_count,
3689                experts.expert_width,
3690            )
3691            .into());
3692        }
3693        validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
3694        let max_pairs = max_tokens
3695            .checked_mul(STEP_GROUPED_FP8_TOP_K)
3696            .ok_or("official Step owner-grouped FP8 capacity route count overflow")?;
3697        let input_capacity = max_tokens
3698            .checked_mul(experts.input_width)
3699            .ok_or("official Step owner-grouped FP8 input capacity overflow")?;
3700
3701        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
3702        for engine in &self.ranks {
3703            let _main = engine.gpu.enter_main()?;
3704            rank_inputs.push(engine.uninit(input_capacity)?);
3705        }
3706
3707        let mut owners = Vec::with_capacity(self.ranks.len());
3708        for (owner_rank, rank) in experts.ranks.iter().enumerate() {
3709            if rank.gate.expert_range != rank.up.expert_range
3710                || rank.gate.expert_range != rank.down.expert_range
3711            {
3712                return Err(format!(
3713                    "owner-grouped FP8 rank {} gate/up/down expert ranges differ",
3714                    owner_rank
3715                )
3716                .into());
3717            }
3718            let local_experts = rank.gate.expert_range.len();
3719            let engine = &self.ranks[owner_rank];
3720            let _main = engine.gpu.enter_main()?;
3721            let route_csr =
3722                DeviceExpertCsr::with_capacity(engine, local_experts, max_tokens, max_pairs)?;
3723            let down_csr =
3724                DeviceExpertCsr::with_capacity(engine, local_experts, max_pairs, max_pairs)?;
3725            let gate_workspace = Fp8GroupedWorkspace::new(
3726                engine,
3727                experts.input_width,
3728                experts.expert_width,
3729                max_tokens,
3730                max_pairs,
3731            )?;
3732            let up_workspace = Fp8GroupedWorkspace::new(
3733                engine,
3734                experts.input_width,
3735                experts.expert_width,
3736                max_tokens,
3737                max_pairs,
3738            )?;
3739            let down_workspace = Fp8GroupedWorkspace::new(
3740                engine,
3741                experts.expert_width,
3742                experts.input_width,
3743                max_pairs,
3744                max_pairs,
3745            )?;
3746            let activation = engine.uninit(
3747                max_pairs
3748                    .checked_mul(experts.expert_width)
3749                    .ok_or("official Step owner-grouped FP8 activation capacity overflow")?,
3750            )?;
3751            owners.push(PreparedStepGroupedExpertOwner {
3752                rank: owner_rank,
3753                global_pairs: Vec::new(),
3754                route_csr,
3755                down_csr,
3756                gate_workspace,
3757                up_workspace,
3758                down_workspace,
3759                activation,
3760            });
3761        }
3762
3763        let mut plan = PreparedStepGroupedExpertParallelGate {
3764            rank_inputs,
3765            owners,
3766            activation_limit,
3767            tokens: 0,
3768            pairs: 0,
3769            max_tokens,
3770            max_pairs,
3771            input_width: experts.input_width,
3772            expert_width: experts.expert_width,
3773            generation: 0,
3774            executed_generation: None,
3775            ready: false,
3776        };
3777        self.refresh_step_grouped_expert_parallel_gate(
3778            experts, &mut plan, input, tokens, selected,
3779        )?;
3780        Ok(plan)
3781    }
3782
3783    fn prepare_step_grouped_expert_parallel_refresh(
3784        &self,
3785        experts: &ResidentExpertParallel,
3786        plan: &PreparedStepGroupedExpertParallelGate,
3787        tokens: usize,
3788        selected: &[usize],
3789    ) -> Result<(usize, u64, Vec<Option<StepGroupedExpertOwnerSchedule>>), Box<dyn std::error::Error>>
3790    {
3791        validate_ep_residency(&self.ranks, experts)?;
3792        if plan.rank_inputs.len() != self.ranks.len()
3793            || plan.owners.len() != self.ranks.len()
3794            || plan.input_width != experts.input_width
3795            || plan.expert_width != experts.expert_width
3796            || tokens > plan.max_tokens
3797        {
3798            return Err(format!(
3799                "Step owner-grouped FP8 refresh geometry changed ranks={}/{} owners={}/{} \
3800                 input={}/{} expert={}/{} tokens={}/{}",
3801                plan.rank_inputs.len(),
3802                self.ranks.len(),
3803                plan.owners.len(),
3804                self.ranks.len(),
3805                plan.input_width,
3806                experts.input_width,
3807                plan.expert_width,
3808                experts.expert_width,
3809                tokens,
3810                plan.max_tokens,
3811            )
3812            .into());
3813        }
3814        let pairs = validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
3815        if pairs > plan.max_pairs {
3816            return Err(format!(
3817                "Step owner-grouped FP8 route count {pairs} exceeds capacity {}",
3818                plan.max_pairs
3819            )
3820            .into());
3821        }
3822        let next_generation = plan
3823            .generation
3824            .checked_add(1)
3825            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
3826        let owner_routes = partition_expert_owner_routes(
3827            experts.expert_count,
3828            self.ranks.len(),
3829            tokens,
3830            STEP_GROUPED_FP8_TOP_K,
3831            selected,
3832        )?;
3833        let mut schedules = Vec::with_capacity(self.ranks.len());
3834        for routes in owner_routes {
3835            if routes.selected.is_empty() {
3836                schedules.push(None);
3837                continue;
3838            }
3839            let local_experts = experts.ranks[routes.rank].gate.expert_range.len();
3840            let local_pairs = routes.selected.len();
3841            let route_csr = ExpertCsr::from_pair_rows(
3842                local_experts,
3843                tokens,
3844                &routes.selected,
3845                &routes.token_rows,
3846            )?;
3847            let down_rows = (0..local_pairs).collect::<Vec<_>>();
3848            let down_csr = ExpertCsr::from_pair_rows(
3849                local_experts,
3850                local_pairs,
3851                &routes.selected,
3852                &down_rows,
3853            )?;
3854            schedules.push(Some(StepGroupedExpertOwnerSchedule {
3855                global_pairs: routes.global_pairs,
3856                route_csr,
3857                down_csr,
3858            }));
3859        }
3860        Ok((pairs, next_generation, schedules))
3861    }
3862
3863    fn commit_step_grouped_expert_parallel_refresh(
3864        &self,
3865        plan: &mut PreparedStepGroupedExpertParallelGate,
3866        tokens: usize,
3867        pairs: usize,
3868        next_generation: u64,
3869        schedules: Vec<Option<StepGroupedExpertOwnerSchedule>>,
3870    ) -> Result<(), Box<dyn std::error::Error>> {
3871        for (owner, schedule) in plan.owners.iter_mut().zip(schedules) {
3872            let engine = &self.ranks[owner.rank];
3873            let _main = engine.gpu.enter_main()?;
3874            if let Some(schedule) = schedule {
3875                owner.route_csr.refresh(engine, &schedule.route_csr)?;
3876                owner.down_csr.refresh(engine, &schedule.down_csr)?;
3877                owner.global_pairs = schedule.global_pairs;
3878            } else {
3879                owner.route_csr.clear();
3880                owner.down_csr.clear();
3881                owner.global_pairs.clear();
3882            }
3883        }
3884        plan.tokens = tokens;
3885        plan.pairs = pairs;
3886        plan.generation = next_generation;
3887        plan.ready = true;
3888        Ok(())
3889    }
3890
3891    pub fn refresh_step_grouped_expert_parallel_gate(
3892        &self,
3893        experts: &ResidentExpertParallel,
3894        plan: &mut PreparedStepGroupedExpertParallelGate,
3895        input: &[f32],
3896        tokens: usize,
3897        selected: &[usize],
3898    ) -> Result<(), Box<dyn std::error::Error>> {
3899        validate_activations(input, tokens, experts.input_width)?;
3900        let (pairs, next_generation, schedules) =
3901            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
3902
3903        plan.ready = false;
3904        plan.executed_generation = None;
3905        {
3906            let root = &self.ranks[0];
3907            let _main = root.gpu.enter_main()?;
3908            let mut destination = plan.rank_inputs[0].slice_mut(0..input.len());
3909            root.stream().memcpy_htod(input, &mut destination)?;
3910            root.stream().synchronize()?;
3911        }
3912        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
3913        let root_input = &root_inputs[0];
3914        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
3915            let engine = &self.ranks[rank + 1];
3916            let _main = engine.gpu.enter_main()?;
3917            let mut destination = peer_input.slice_mut(0..input.len());
3918            engine
3919                .stream()
3920                .memcpy_dtod(&root_input.slice(0..input.len()), &mut destination)?;
3921        }
3922        self.commit_step_grouped_expert_parallel_refresh(
3923            plan,
3924            tokens,
3925            pairs,
3926            next_generation,
3927            schedules,
3928        )
3929    }
3930
3931    /// Refresh routes and inputs from an already-resident rank-zero activation.
3932    ///
3933    /// The caller must order the source producer before this call. The root copy is completed
3934    /// before peer dispatch, while CSR and workspace allocations retain their stable addresses.
3935    pub fn refresh_step_grouped_expert_parallel_gate_from_root_device(
3936        &self,
3937        experts: &ResidentExpertParallel,
3938        plan: &mut PreparedStepGroupedExpertParallelGate,
3939        input: &CudaSlice<f32>,
3940        tokens: usize,
3941        selected: &[usize],
3942    ) -> Result<(), Box<dyn std::error::Error>> {
3943        let input_values = tokens
3944            .checked_mul(experts.input_width)
3945            .ok_or("Step owner-grouped FP8 input size overflow")?;
3946        let root = self
3947            .ranks
3948            .first()
3949            .ok_or("Step owner-grouped FP8 runtime has no root rank")?;
3950        if input.len() < input_values || input.ordinal() != root.ctx().ordinal() {
3951            return Err(format!(
3952                "Step owner-grouped FP8 root input len/device {}/{} does not cover {} values on \
3953                 device {}",
3954                input.len(),
3955                input.ordinal(),
3956                input_values,
3957                root.ctx().ordinal(),
3958            )
3959            .into());
3960        }
3961        let (pairs, next_generation, schedules) =
3962            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
3963
3964        plan.ready = false;
3965        plan.executed_generation = None;
3966        {
3967            let _main = root.gpu.enter_main()?;
3968            let mut destination = plan.rank_inputs[0].slice_mut(0..input_values);
3969            root.stream()
3970                .memcpy_dtod(&input.slice(0..input_values), &mut destination)?;
3971            root.stream().synchronize()?;
3972        }
3973        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
3974        let root_input = &root_inputs[0];
3975        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
3976            let engine = &self.ranks[rank + 1];
3977            let _main = engine.gpu.enter_main()?;
3978            let mut destination = peer_input.slice_mut(0..input_values);
3979            engine
3980                .stream()
3981                .memcpy_dtod(&root_input.slice(0..input_values), &mut destination)?;
3982        }
3983        self.commit_step_grouped_expert_parallel_refresh(
3984            plan,
3985            tokens,
3986            pairs,
3987            next_generation,
3988            schedules,
3989        )
3990    }
3991
3992    /// Replace a fixed route plan's rank inputs from an already replicated device batch.
3993    ///
3994    /// Route CSR remains unchanged. Advancing the generation invalidates every prior projection
3995    /// and combine result, so callers must refresh combine metadata before executing again.
3996    pub fn refresh_step_grouped_expert_parallel_inputs_from_replicated(
3997        &self,
3998        experts: &ResidentExpertParallel,
3999        plan: &mut PreparedStepGroupedExpertParallelGate,
4000        input: &ResidentReplicatedDeviceRows,
4001    ) -> Result<(), Box<dyn std::error::Error>> {
4002        validate_ep_residency(&self.ranks, experts)?;
4003        validate_replicated_device_rows(&self.ranks, input)?;
4004        if !plan.ready
4005            || input.tokens != plan.tokens
4006            || input.width != plan.input_width
4007            || input.tokens > plan.max_tokens
4008            || plan.rank_inputs.len() != self.ranks.len()
4009            || plan.owners.len() != self.ranks.len()
4010            || plan.input_width != experts.input_width
4011            || plan.expert_width != experts.expert_width
4012        {
4013            return Err("Step owner-grouped replicated input geometry changed".into());
4014        }
4015        let values = input
4016            .tokens
4017            .checked_mul(input.width)
4018            .ok_or("Step owner-grouped replicated input size overflow")?;
4019        let next_generation = plan
4020            .generation
4021            .checked_add(1)
4022            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4023        plan.ready = false;
4024        plan.executed_generation = None;
4025        for (rank, engine) in self.ranks.iter().enumerate() {
4026            let _main = engine.gpu.enter_main()?;
4027            let mut destination = plan.rank_inputs[rank].slice_mut(0..values);
4028            engine
4029                .stream()
4030                .memcpy_dtod(&input.ranks[rank], &mut destination)?;
4031        }
4032        plan.generation = next_generation;
4033        plan.ready = true;
4034        Ok(())
4035    }
4036
4037    pub fn execute_step_grouped_expert_parallel_gate(
4038        &self,
4039        experts: &ResidentExpertParallel,
4040        plan: &mut PreparedStepGroupedExpertParallelGate,
4041    ) -> Result<(), Box<dyn std::error::Error>> {
4042        validate_ep_residency(&self.ranks, experts)?;
4043        if !plan.ready
4044            || plan.rank_inputs.len() != self.ranks.len()
4045            || plan.owners.len() != self.ranks.len()
4046            || plan.input_width != experts.input_width
4047            || plan.expert_width != experts.expert_width
4048        {
4049            return Err("Step owner-grouped FP8 plan is not ready or its geometry changed".into());
4050        }
4051        plan.executed_generation = None;
4052
4053        for owner in &mut plan.owners {
4054            if owner.global_pairs.is_empty() {
4055                continue;
4056            }
4057            let engine = &self.ranks[owner.rank];
4058            let bank = &experts.ranks[owner.rank];
4059            let _main = engine.gpu.enter_main()?;
4060            let local_pairs = owner.global_pairs.len();
4061            owner.gate_workspace.quantize_for_shape(
4062                engine,
4063                &plan.rank_inputs[owner.rank],
4064                plan.tokens,
4065                local_pairs,
4066            )?;
4067            owner.gate_workspace.project(
4068                engine,
4069                &bank.gate.codes,
4070                &bank.gate.scales,
4071                &owner.route_csr,
4072                bank.gate.code_stride,
4073                bank.gate.scale_stride,
4074                1.0,
4075            )?;
4076            owner.up_workspace.quantize_for_shape(
4077                engine,
4078                &plan.rank_inputs[owner.rank],
4079                plan.tokens,
4080                local_pairs,
4081            )?;
4082            owner.up_workspace.project(
4083                engine,
4084                &bank.up.codes,
4085                &bank.up.scales,
4086                &owner.route_csr,
4087                bank.up.code_stride,
4088                bank.up.scale_stride,
4089                1.0,
4090            )?;
4091        }
4092        for owner in &mut plan.owners {
4093            if owner.global_pairs.is_empty() {
4094                continue;
4095            }
4096            let engine = &self.ranks[owner.rank];
4097            let _main = engine.gpu.enter_main()?;
4098            let values = owner.global_pairs.len() * plan.expert_width;
4099            if let Some(limit) = plan.activation_limit {
4100                engine.silu_clamped_mul_host_expf(
4101                    owner.gate_workspace.output(),
4102                    owner.up_workspace.output(),
4103                    limit,
4104                    &mut owner.activation,
4105                    values,
4106                )?;
4107            } else {
4108                engine.silu_mul_host_expf(
4109                    owner.gate_workspace.output(),
4110                    owner.up_workspace.output(),
4111                    &mut owner.activation,
4112                    values,
4113                )?;
4114            }
4115        }
4116        for owner in &mut plan.owners {
4117            if owner.global_pairs.is_empty() {
4118                continue;
4119            }
4120            let engine = &self.ranks[owner.rank];
4121            let bank = &experts.ranks[owner.rank];
4122            let _main = engine.gpu.enter_main()?;
4123            let local_pairs = owner.global_pairs.len();
4124            owner.down_workspace.quantize_for_shape(
4125                engine,
4126                &owner.activation,
4127                local_pairs,
4128                local_pairs,
4129            )?;
4130            owner.down_workspace.project(
4131                engine,
4132                &bank.down.codes,
4133                &bank.down.scales,
4134                &owner.down_csr,
4135                bank.down.code_stride,
4136                bank.down.scale_stride,
4137                1.0,
4138            )?;
4139        }
4140        plan.executed_generation = Some(plan.generation);
4141        Ok(())
4142    }
4143
4144    pub fn collect_step_grouped_expert_parallel_gate(
4145        &self,
4146        plan: &PreparedStepGroupedExpertParallelGate,
4147    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4148        if !plan.ready || plan.executed_generation != Some(plan.generation) {
4149            return Err("Step owner-grouped FP8 projection is stale or has not executed".into());
4150        }
4151        let mut gate = vec![0.0f32; plan.pairs * plan.expert_width];
4152        let mut up = vec![0.0f32; plan.pairs * plan.expert_width];
4153        let mut down = vec![0.0f32; plan.pairs * plan.input_width];
4154        for owner in &plan.owners {
4155            if owner.global_pairs.is_empty() {
4156                continue;
4157            }
4158            let engine = &self.ranks[owner.rank];
4159            let _main = engine.gpu.enter_main()?;
4160            let owner_gate = engine.dtoh_view(
4161                &owner
4162                    .gate_workspace
4163                    .output()
4164                    .slice(0..owner.gate_workspace.output_len()),
4165            )?;
4166            let owner_up = engine.dtoh_view(
4167                &owner
4168                    .up_workspace
4169                    .output()
4170                    .slice(0..owner.up_workspace.output_len()),
4171            )?;
4172            let owner_down = engine.dtoh_view(
4173                &owner
4174                    .down_workspace
4175                    .output()
4176                    .slice(0..owner.down_workspace.output_len()),
4177            )?;
4178            for (local_pair, &global_pair) in owner.global_pairs.iter().enumerate() {
4179                let local_expert = local_pair * plan.expert_width;
4180                let global_expert = global_pair * plan.expert_width;
4181                gate[global_expert..global_expert + plan.expert_width]
4182                    .copy_from_slice(&owner_gate[local_expert..local_expert + plan.expert_width]);
4183                up[global_expert..global_expert + plan.expert_width]
4184                    .copy_from_slice(&owner_up[local_expert..local_expert + plan.expert_width]);
4185
4186                let local_hidden = local_pair * plan.input_width;
4187                let global_hidden = global_pair * plan.input_width;
4188                down[global_hidden..global_hidden + plan.input_width]
4189                    .copy_from_slice(&owner_down[local_hidden..local_hidden + plan.input_width]);
4190            }
4191        }
4192        Ok(StepGroupedFp8ProjectionOutput { gate, up, down })
4193    }
4194
4195    pub fn run_step_grouped_expert_parallel_gate(
4196        &self,
4197        experts: &ResidentExpertParallel,
4198        plan: &mut PreparedStepGroupedExpertParallelGate,
4199    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4200        self.execute_step_grouped_expert_parallel_gate(experts, plan)?;
4201        self.collect_step_grouped_expert_parallel_gate(plan)
4202    }
4203
4204    pub fn prepare_step_grouped_expert_parallel_combine(
4205        &self,
4206        plan: &PreparedStepGroupedExpertParallelGate,
4207        route_weights: &[f32],
4208    ) -> Result<PreparedPeerWeightedRouteCombine, Box<dyn std::error::Error>> {
4209        if !self.native_p2p || !self.ep_device_arithmetic || !plan.ready {
4210            return Err(
4211                "Step owner-grouped combine requires a ready native-P2P device plan".into(),
4212            );
4213        }
4214        let owner_pairs = plan
4215            .owners
4216            .iter()
4217            .map(|owner| owner.global_pairs.as_slice())
4218            .collect::<Vec<_>>();
4219        let shape = validate_weighted_route_combine(
4220            plan.input_width,
4221            STEP_GROUPED_FP8_TOP_K,
4222            plan.max_tokens,
4223            plan.tokens,
4224            &owner_pairs,
4225            route_weights,
4226        )?;
4227        if shape.max_pairs != plan.max_pairs {
4228            return Err(format!(
4229                "Step owner-grouped combine capacity {} != projection capacity {}",
4230                shape.max_pairs, plan.max_pairs
4231            )
4232            .into());
4233        }
4234        let root = self
4235            .ranks
4236            .first()
4237            .ok_or("Step owner-grouped combine has no root rank")?;
4238        let slot_values = shape
4239            .max_pairs
4240            .checked_mul(plan.input_width)
4241            .ok_or("Step owner-grouped combine slot capacity overflow")?;
4242        let output_values = plan
4243            .max_tokens
4244            .checked_mul(plan.input_width)
4245            .ok_or("Step owner-grouped combine output capacity overflow")?;
4246        let (root_device, owners, peer_staging, slots, weights, output) = {
4247            let _main = root.gpu.enter_main()?;
4248            let mut owners = Vec::with_capacity(plan.owners.len());
4249            for _ in &plan.owners {
4250                owners.push(PreparedPeerWeightedRouteOwner {
4251                    token_rows: root.htod_i32(&vec![0; shape.max_pairs])?,
4252                    slots: root.htod_i32(&vec![0; shape.max_pairs])?,
4253                    weights: root.htod(&vec![0.0; shape.max_pairs])?,
4254                    active_pairs: 0,
4255                });
4256            }
4257            (
4258                root.ctx().ordinal(),
4259                owners,
4260                root.uninit(slot_values)?,
4261                root.uninit(slot_values)?,
4262                root.uninit(shape.max_pairs)?,
4263                root.uninit(output_values)?,
4264            )
4265        };
4266        let mut peer_devices = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4267        let mut peer_outputs = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4268        for engine in self.ranks.iter().skip(1) {
4269            let _main = engine.gpu.enter_main()?;
4270            peer_devices.push(engine.ctx().ordinal());
4271            peer_outputs.push(engine.uninit(output_values)?);
4272        }
4273        let mut combine = PreparedPeerWeightedRouteCombine {
4274            root_device,
4275            owners,
4276            peer_staging,
4277            slots,
4278            weights,
4279            output,
4280            peer_devices,
4281            peer_outputs,
4282            width: plan.input_width,
4283            experts_per_token: STEP_GROUPED_FP8_TOP_K,
4284            max_tokens: plan.max_tokens,
4285            max_pairs: shape.max_pairs,
4286            tokens: 0,
4287            pairs: 0,
4288            projection_generation: 0,
4289            output_generation: None,
4290            broadcast_generation: None,
4291            ready: false,
4292        };
4293        self.refresh_step_grouped_expert_parallel_combine(plan, &mut combine, route_weights)?;
4294        Ok(combine)
4295    }
4296
4297    pub fn refresh_step_grouped_expert_parallel_combine(
4298        &self,
4299        plan: &PreparedStepGroupedExpertParallelGate,
4300        combine: &mut PreparedPeerWeightedRouteCombine,
4301        route_weights: &[f32],
4302    ) -> Result<(), Box<dyn std::error::Error>> {
4303        let output_capacity = combine
4304            .max_tokens
4305            .checked_mul(combine.width)
4306            .ok_or("Step owner-grouped combine output capacity overflow")?;
4307        if !plan.ready
4308            || combine.owners.len() != plan.owners.len()
4309            || combine.peer_devices.len() + 1 != self.ranks.len()
4310            || combine.peer_outputs.len() + 1 != self.ranks.len()
4311            || combine.width != plan.input_width
4312            || combine.experts_per_token != STEP_GROUPED_FP8_TOP_K
4313            || combine.max_tokens != plan.max_tokens
4314            || combine.max_pairs != plan.max_pairs
4315            || combine.output.len() < output_capacity
4316            || combine
4317                .peer_outputs
4318                .iter()
4319                .any(|output| output.len() < output_capacity)
4320        {
4321            return Err("Step owner-grouped combine/projection geometry changed".into());
4322        }
4323        if self
4324            .ranks
4325            .iter()
4326            .skip(1)
4327            .zip(&combine.peer_devices)
4328            .any(|(engine, &device)| engine.ctx().ordinal() != device)
4329        {
4330            return Err("Step owner-grouped combine peer devices changed".into());
4331        }
4332        let owner_pairs = plan
4333            .owners
4334            .iter()
4335            .map(|owner| owner.global_pairs.as_slice())
4336            .collect::<Vec<_>>();
4337        let shape = validate_weighted_route_combine(
4338            combine.width,
4339            combine.experts_per_token,
4340            combine.max_tokens,
4341            plan.tokens,
4342            &owner_pairs,
4343            route_weights,
4344        )?;
4345        if shape.max_pairs != combine.max_pairs {
4346            return Err("Step owner-grouped combine capacity changed during refresh".into());
4347        }
4348        let metadata = owner_pairs
4349            .iter()
4350            .map(|pairs| {
4351                let token_rows = pairs
4352                    .iter()
4353                    .map(|&pair| (pair / combine.experts_per_token) as i32)
4354                    .collect::<Vec<_>>();
4355                let slots = pairs
4356                    .iter()
4357                    .map(|&pair| (pair % combine.experts_per_token) as i32)
4358                    .collect::<Vec<_>>();
4359                let weights = pairs
4360                    .iter()
4361                    .map(|&pair| route_weights[pair])
4362                    .collect::<Vec<_>>();
4363                (token_rows, slots, weights)
4364            })
4365            .collect::<Vec<_>>();
4366
4367        combine.ready = false;
4368        combine.output_generation = None;
4369        combine.broadcast_generation = None;
4370        let root = self
4371            .ranks
4372            .first()
4373            .ok_or("Step owner-grouped combine has no root rank")?;
4374        let _main = root.gpu.enter_main()?;
4375        if root.ctx().ordinal() != combine.root_device {
4376            return Err(format!(
4377                "Step owner-grouped combine root device changed {} != {}",
4378                root.ctx().ordinal(),
4379                combine.root_device
4380            )
4381            .into());
4382        }
4383        for (owner, (token_rows, slots, weights)) in combine.owners.iter_mut().zip(metadata) {
4384            if token_rows.is_empty() {
4385                owner.active_pairs = 0;
4386                continue;
4387            }
4388            root.htod_i32_into(&mut owner.token_rows, &token_rows)?;
4389            root.htod_i32_into(&mut owner.slots, &slots)?;
4390            let mut weight_prefix = owner.weights.slice_mut(0..weights.len());
4391            root.stream().memcpy_htod(&weights, &mut weight_prefix)?;
4392            owner.active_pairs = token_rows.len();
4393        }
4394        combine.tokens = plan.tokens;
4395        combine.pairs = shape.pairs;
4396        combine.projection_generation = plan.generation;
4397        combine.ready = true;
4398        Ok(())
4399    }
4400
4401    pub fn execute_step_grouped_expert_parallel_combine(
4402        &self,
4403        plan: &PreparedStepGroupedExpertParallelGate,
4404        combine: &mut PreparedPeerWeightedRouteCombine,
4405    ) -> Result<(), Box<dyn std::error::Error>> {
4406        if !plan.ready
4407            || plan.executed_generation != Some(plan.generation)
4408            || !combine.ready
4409            || combine.tokens != plan.tokens
4410            || combine.pairs != plan.pairs
4411            || combine.width != plan.input_width
4412            || combine.owners.len() != plan.owners.len()
4413            || combine.projection_generation != plan.generation
4414        {
4415            return Err("Step owner-grouped combine is stale or its geometry changed".into());
4416        }
4417        combine.output_generation = None;
4418        combine.broadcast_generation = None;
4419        for owner in &plan.owners {
4420            if owner.rank == 0 || owner.global_pairs.is_empty() {
4421                continue;
4422            }
4423            let engine = &self.ranks[owner.rank];
4424            let _main = engine.gpu.enter_main()?;
4425            engine.stream().synchronize()?;
4426        }
4427        let root = self
4428            .ranks
4429            .first()
4430            .ok_or("Step owner-grouped combine has no root rank")?;
4431        let _main = root.gpu.enter_main()?;
4432        if root.ctx().ordinal() != combine.root_device {
4433            return Err("Step owner-grouped combine is not resident on the root device".into());
4434        }
4435        for (index, owner) in plan.owners.iter().enumerate() {
4436            let metadata = &combine.owners[index];
4437            if owner.global_pairs.len() != metadata.active_pairs {
4438                return Err(format!(
4439                    "Step owner-grouped combine owner {index} rows {} != metadata {}",
4440                    owner.global_pairs.len(),
4441                    metadata.active_pairs
4442                )
4443                .into());
4444            }
4445            if metadata.active_pairs == 0 {
4446                continue;
4447            }
4448            let values = metadata
4449                .active_pairs
4450                .checked_mul(combine.width)
4451                .ok_or("Step owner-grouped combine peer value count overflow")?;
4452            if owner.rank == 0 {
4453                root.scatter_slot(
4454                    owner.down_workspace.output(),
4455                    &metadata.token_rows,
4456                    &metadata.slots,
4457                    &metadata.weights,
4458                    &mut combine.slots,
4459                    &mut combine.weights,
4460                    combine.width,
4461                    combine.experts_per_token,
4462                    metadata.active_pairs,
4463                )?;
4464            } else {
4465                let source = owner.down_workspace.output().slice(0..values);
4466                let mut destination = combine.peer_staging.slice_mut(0..values);
4467                root.stream().memcpy_dtod(&source, &mut destination)?;
4468                root.scatter_slot(
4469                    &combine.peer_staging,
4470                    &metadata.token_rows,
4471                    &metadata.slots,
4472                    &metadata.weights,
4473                    &mut combine.slots,
4474                    &mut combine.weights,
4475                    combine.width,
4476                    combine.experts_per_token,
4477                    metadata.active_pairs,
4478                )?;
4479            }
4480        }
4481        root.reduce_slots_host(
4482            &combine.slots,
4483            &combine.weights,
4484            &mut combine.output,
4485            combine.width,
4486            combine.experts_per_token,
4487            combine.tokens,
4488        )?;
4489        combine.output_generation = Some(plan.generation);
4490        Ok(())
4491    }
4492
4493    pub fn collect_step_grouped_expert_parallel_combine(
4494        &self,
4495        plan: &PreparedStepGroupedExpertParallelGate,
4496        combine: &PreparedPeerWeightedRouteCombine,
4497    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4498        if !plan.ready
4499            || combine.output_generation != Some(plan.generation)
4500            || combine.projection_generation != plan.generation
4501        {
4502            return Err("Step owner-grouped combine output is stale or has not executed".into());
4503        }
4504        let root = self
4505            .ranks
4506            .first()
4507            .ok_or("Step owner-grouped combine has no root rank")?;
4508        let _main = root.gpu.enter_main()?;
4509        if root.ctx().ordinal() != combine.root_device {
4510            return Err("Step owner-grouped combine is not resident on the root device".into());
4511        }
4512        root.dtoh_view(&combine.output.slice(0..combine.tokens * combine.width))
4513    }
4514
4515    /// Copy the active root combine result into a caller-owned engine on the same CUDA device.
4516    ///
4517    /// The persistent combine buffer remains reusable by the next route generation; the returned
4518    /// allocation follows the serving runtime's ordinary transient-output ownership.
4519    pub fn copy_step_grouped_expert_parallel_combine_root(
4520        &self,
4521        plan: &PreparedStepGroupedExpertParallelGate,
4522        combine: &PreparedPeerWeightedRouteCombine,
4523        destination: &Engine,
4524    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
4525        if !plan.ready
4526            || combine.output_generation != Some(plan.generation)
4527            || combine.projection_generation != plan.generation
4528        {
4529            return Err("Step owner-grouped combine output is stale or has not executed".into());
4530        }
4531        let root = self
4532            .ranks
4533            .first()
4534            .ok_or("Step owner-grouped combine has no root rank")?;
4535        if root.ctx().ordinal() != combine.root_device
4536            || destination.ctx().ordinal() != combine.root_device
4537        {
4538            return Err(format!(
4539                "Step owner-grouped combine root/destination devices {}/{} != {}",
4540                root.ctx().ordinal(),
4541                destination.ctx().ordinal(),
4542                combine.root_device,
4543            )
4544            .into());
4545        }
4546        let values = combine
4547            .tokens
4548            .checked_mul(combine.width)
4549            .ok_or("Step owner-grouped combine copy size overflow")?;
4550        {
4551            let _main = root.gpu.enter_main()?;
4552            root.stream().synchronize()?;
4553        }
4554        let _main = destination.gpu.enter_main()?;
4555        let mut output = destination.uninit(values)?;
4556        destination
4557            .stream()
4558            .memcpy_dtod(&combine.output.slice(0..values), &mut output)?;
4559        Ok(output)
4560    }
4561
4562    pub fn broadcast_step_grouped_expert_parallel_combine(
4563        &self,
4564        plan: &PreparedStepGroupedExpertParallelGate,
4565        combine: &mut PreparedPeerWeightedRouteCombine,
4566    ) -> Result<(), Box<dyn std::error::Error>> {
4567        if !plan.ready
4568            || combine.output_generation != Some(plan.generation)
4569            || combine.projection_generation != plan.generation
4570            || combine.peer_devices.len() + 1 != self.ranks.len()
4571            || combine.peer_outputs.len() + 1 != self.ranks.len()
4572        {
4573            return Err("Step owner-grouped combine output cannot be broadcast".into());
4574        }
4575        combine.broadcast_generation = None;
4576        let values = combine
4577            .tokens
4578            .checked_mul(combine.width)
4579            .ok_or("Step owner-grouped combine broadcast size overflow")?;
4580        {
4581            let root = self
4582                .ranks
4583                .first()
4584                .ok_or("Step owner-grouped combine has no root rank")?;
4585            let _main = root.gpu.enter_main()?;
4586            if root.ctx().ordinal() != combine.root_device {
4587                return Err("Step owner-grouped combine root device changed".into());
4588            }
4589            root.stream().synchronize()?;
4590        }
4591        let source = &combine.output;
4592        for (index, destination_buffer) in combine.peer_outputs.iter_mut().enumerate() {
4593            let engine = &self.ranks[index + 1];
4594            let _main = engine.gpu.enter_main()?;
4595            if engine.ctx().ordinal() != combine.peer_devices[index] {
4596                return Err(format!(
4597                    "Step owner-grouped combine peer {} device changed",
4598                    index + 1
4599                )
4600                .into());
4601            }
4602            let mut destination = destination_buffer.slice_mut(0..values);
4603            engine
4604                .stream()
4605                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
4606        }
4607        combine.broadcast_generation = Some(plan.generation);
4608        Ok(())
4609    }
4610
4611    pub fn collect_step_grouped_expert_parallel_broadcast(
4612        &self,
4613        plan: &PreparedStepGroupedExpertParallelGate,
4614        combine: &PreparedPeerWeightedRouteCombine,
4615    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
4616        if !plan.ready
4617            || combine.output_generation != Some(plan.generation)
4618            || combine.broadcast_generation != Some(plan.generation)
4619            || combine.peer_outputs.len() + 1 != self.ranks.len()
4620        {
4621            return Err("Step owner-grouped combine broadcast is stale or incomplete".into());
4622        }
4623        let values = combine
4624            .tokens
4625            .checked_mul(combine.width)
4626            .ok_or("Step owner-grouped combine collection size overflow")?;
4627        let mut outputs = Vec::with_capacity(self.ranks.len());
4628        {
4629            let root = &self.ranks[0];
4630            let _main = root.gpu.enter_main()?;
4631            outputs.push(root.dtoh_view(&combine.output.slice(0..values))?);
4632        }
4633        for (index, output) in combine.peer_outputs.iter().enumerate() {
4634            let engine = &self.ranks[index + 1];
4635            let _main = engine.gpu.enter_main()?;
4636            outputs.push(engine.dtoh_view(&output.slice(0..values))?);
4637        }
4638        Ok(outputs)
4639    }
4640
4641    /// Add routed and replicated shared-expert outputs, then add the attention residual.
4642    pub fn finish_step_grouped_expert_parallel_layer(
4643        &self,
4644        plan: &PreparedStepGroupedExpertParallelGate,
4645        combine: &PreparedPeerWeightedRouteCombine,
4646        shared: &ResidentReplicatedDeviceRows,
4647        residual: &ResidentReplicatedDeviceRows,
4648    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
4649        validate_replicated_device_rows(&self.ranks, shared)?;
4650        validate_replicated_device_rows(&self.ranks, residual)?;
4651        if !plan.ready
4652            || plan.executed_generation != Some(plan.generation)
4653            || combine.output_generation != Some(plan.generation)
4654            || combine.broadcast_generation != Some(plan.generation)
4655            || combine.projection_generation != plan.generation
4656            || combine.peer_outputs.len() + 1 != self.ranks.len()
4657            || shared.tokens != combine.tokens
4658            || residual.tokens != combine.tokens
4659            || shared.width != combine.width
4660            || residual.width != combine.width
4661        {
4662            return Err("Step full-layer finish inputs are stale or their geometry changed".into());
4663        }
4664        let values = combine
4665            .tokens
4666            .checked_mul(combine.width)
4667            .ok_or("Step full-layer output size overflow")?;
4668        let mut ranks = Vec::with_capacity(self.ranks.len());
4669        for rank in 0..self.ranks.len() {
4670            let engine = &self.ranks[rank];
4671            let _main = engine.gpu.enter_main()?;
4672            let routed = if rank == 0 {
4673                &combine.output
4674            } else {
4675                &combine.peer_outputs[rank - 1]
4676            };
4677            let mut ffn = engine.uninit(values)?;
4678            engine.add(routed, &shared.ranks[rank], &mut ffn, values)?;
4679            let mut output = engine.uninit(values)?;
4680            engine.add(&residual.ranks[rank], &ffn, &mut output, values)?;
4681            ranks.push(output);
4682        }
4683        Ok(ResidentReplicatedDeviceRows {
4684            ranks,
4685            tokens: combine.tokens,
4686            width: combine.width,
4687        })
4688    }
4689
4690    pub fn run_step_grouped_expert_parallel_combine(
4691        &self,
4692        plan: &PreparedStepGroupedExpertParallelGate,
4693        combine: &mut PreparedPeerWeightedRouteCombine,
4694    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4695        self.execute_step_grouped_expert_parallel_combine(plan, combine)?;
4696        self.collect_step_grouped_expert_parallel_combine(plan, combine)
4697    }
4698
4699    pub fn upload_tensor_parallel(
4700        &self,
4701        gate: E4m3ExpertBank<'_>,
4702        up: E4m3ExpertBank<'_>,
4703        down: E4m3ExpertBank<'_>,
4704    ) -> Result<ResidentTensorParallel, Box<dyn std::error::Error>> {
4705        gate.validate()?;
4706        up.validate()?;
4707        down.validate()?;
4708        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
4709            return Err("TP gate/up/down expert counts differ".into());
4710        }
4711        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4712            return Err("TP gate/up dimensions differ".into());
4713        }
4714        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4715            return Err(format!(
4716                "TP down {}x{} does not invert gate/up {}x{}",
4717                down.out_features, down.in_features, gate.out_features, gate.in_features
4718            )
4719            .into());
4720        }
4721        let tp = self.ranks.len();
4722        validate_column_bank_shape(gate, tp)?;
4723        validate_column_bank_shape(up, tp)?;
4724        validate_row_bank_shape(down, tp)?;
4725
4726        let mut gate_ranks = Vec::with_capacity(tp);
4727        let mut up_ranks = Vec::with_capacity(tp);
4728        let mut down_ranks = Vec::with_capacity(tp);
4729        for (rank, engine) in self.ranks.iter().enumerate() {
4730            gate_ranks.push(upload_column_bank_rank(engine, gate, tp, rank)?);
4731            up_ranks.push(upload_column_bank_rank(engine, up, tp, rank)?);
4732            down_ranks.push(upload_row_bank_rank(engine, down, tp, rank)?);
4733        }
4734        Ok(ResidentTensorParallel {
4735            bank: ResidentTpExpertBank {
4736                gate: gate_ranks,
4737                up: up_ranks,
4738                down: down_ranks,
4739                expert_count: gate.expert_count,
4740                input_width: gate.in_features,
4741                expert_width: gate.out_features,
4742            },
4743        })
4744    }
4745
4746    pub fn run_tensor_parallel_routes(
4747        &self,
4748        experts: &ResidentTensorParallel,
4749        input: &[f32],
4750        tokens: usize,
4751        selected: &[usize],
4752        route_weights: &[f32],
4753        experts_per_token: usize,
4754    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4755        validate_tp_bank_residency(&self.ranks, &experts.bank)?;
4756        validate_activations(input, tokens, experts.bank.input_width)?;
4757        let pairs = tokens
4758            .checked_mul(experts_per_token)
4759            .ok_or("TP route count overflow")?;
4760        if selected.len() != pairs || route_weights.len() != pairs {
4761            return Err(format!(
4762                "TP routes selected={} weights={} != tokens {tokens} x experts/token \
4763                 {experts_per_token} ({pairs})",
4764                selected.len(),
4765                route_weights.len(),
4766            )
4767            .into());
4768        }
4769        if !route_weights.iter().all(|weight| weight.is_finite()) {
4770            return Err("TP route weights contain a non-finite value".into());
4771        }
4772
4773        let mut output = vec![0.0f32; tokens * experts.bank.input_width];
4774        for token in 0..tokens {
4775            let input_row =
4776                &input[token * experts.bank.input_width..(token + 1) * experts.bank.input_width];
4777            for slot in 0..experts_per_token {
4778                let pair = token * experts_per_token + slot;
4779                let expert = selected[pair];
4780                if expert >= experts.bank.expert_count {
4781                    return Err(format!(
4782                        "TP selected expert {expert} outside 0..{}",
4783                        experts.bank.expert_count
4784                    )
4785                    .into());
4786                }
4787                let down = if self.native_p2p {
4788                    self.run_tensor_parallel_expert_native(&experts.bank, expert, input_row)?
4789                } else {
4790                    let gate =
4791                        self.run_column_bank_expert(&experts.bank.gate, expert, input_row)?;
4792                    let up = self.run_column_bank_expert(&experts.bank.up, expert, input_row)?;
4793                    let activated: Vec<f32> = gate
4794                        .iter()
4795                        .zip(&up)
4796                        .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
4797                        .collect();
4798                    debug_assert_eq!(activated.len(), experts.bank.expert_width);
4799                    self.run_row_bank_expert(&experts.bank.down, expert, &activated)?
4800                };
4801                let weight = route_weights[pair];
4802                for (sum, value) in output
4803                    [token * experts.bank.input_width..(token + 1) * experts.bank.input_width]
4804                    .iter_mut()
4805                    .zip(down)
4806                {
4807                    *sum += weight * value;
4808                }
4809            }
4810        }
4811        Ok(output)
4812    }
4813
4814    fn run_column_bank_expert(
4815        &self,
4816        ranks: &[ResidentE4m3ExpertBankRank],
4817        expert: usize,
4818        input: &[f32],
4819    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4820        let local_out = ranks
4821            .first()
4822            .ok_or("TP column bank has no ranks")?
4823            .out_features;
4824        let mut gathered = vec![0.0f32; local_out * ranks.len()];
4825        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
4826            let shard = run_resident_bank_expert(engine, bank, expert, input, 1)?;
4827            gathered[rank * local_out..(rank + 1) * local_out].copy_from_slice(&shard);
4828        }
4829        Ok(gathered)
4830    }
4831
4832    fn run_row_bank_expert(
4833        &self,
4834        ranks: &[ResidentE4m3ExpertBankRank],
4835        expert: usize,
4836        input: &[f32],
4837    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4838        let local_in = ranks.first().ok_or("TP row bank has no ranks")?.in_features;
4839        if input.len() != local_in * ranks.len() {
4840            return Err(format!(
4841                "TP row input {} != {} ranks x {local_in}",
4842                input.len(),
4843                ranks.len()
4844            )
4845            .into());
4846        }
4847        let out_features = ranks[0].out_features;
4848        let mut reduced = vec![0.0f32; out_features];
4849        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
4850            let blocks = bank
4851                .k_blocks
4852                .ok_or("TP row bank is not packed in native K-block order")?;
4853            if blocks * FP8_BLOCK != local_in {
4854                return Err(format!(
4855                    "TP row bank has {blocks} blocks but local input width is {local_in}"
4856                )
4857                .into());
4858            }
4859            for block in 0..blocks {
4860                let global_start = rank * local_in + block * FP8_BLOCK;
4861                let partial = run_resident_bank_expert_block(
4862                    engine,
4863                    bank,
4864                    expert,
4865                    block,
4866                    &input[global_start..global_start + FP8_BLOCK],
4867                )?;
4868                for (sum, value) in reduced.iter_mut().zip(partial) {
4869                    *sum += value;
4870                }
4871            }
4872        }
4873        Ok(reduced)
4874    }
4875
4876    fn run_tensor_parallel_expert_native(
4877        &self,
4878        bank: &ResidentTpExpertBank,
4879        expert: usize,
4880        input: &[f32],
4881    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4882        if !self.native_p2p || self.ranks.len() < 2 {
4883            return Err("native TP expert execution requires at least two P2P ranks".into());
4884        }
4885        let local_out = bank
4886            .gate
4887            .first()
4888            .ok_or("native TP gate bank has no ranks")?
4889            .out_features;
4890        if local_out * self.ranks.len() != bank.expert_width {
4891            return Err(format!(
4892                "native TP gate shards {}x{local_out} != expert width {}",
4893                self.ranks.len(),
4894                bank.expert_width
4895            )
4896            .into());
4897        }
4898
4899        // The caller's routed input is already host-canonical. Upload once on rank zero, then
4900        // broadcast over peer copies so no other rank receives a host-staged duplicate.
4901        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
4902        let root_input = {
4903            let root = &self.ranks[0];
4904            let _main = root.gpu.enter_main()?;
4905            root.htod(input)?
4906        };
4907        rank_inputs.push(root_input);
4908        for engine in &self.ranks[1..] {
4909            let peer_input = {
4910                let _main = engine.gpu.enter_main()?;
4911                let mut peer_input = engine.uninit(input.len())?;
4912                engine
4913                    .stream()
4914                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
4915                peer_input
4916            };
4917            rank_inputs.push(peer_input);
4918        }
4919
4920        let mut gate_shards = Vec::with_capacity(self.ranks.len());
4921        let mut up_shards = Vec::with_capacity(self.ranks.len());
4922        for rank in 0..self.ranks.len() {
4923            gate_shards.push(run_resident_bank_expert_device(
4924                &self.ranks[rank],
4925                &bank.gate[rank],
4926                expert,
4927                &rank_inputs[rank],
4928                1,
4929            )?);
4930            up_shards.push(run_resident_bank_expert_device(
4931                &self.ranks[rank],
4932                &bank.up[rank],
4933                expert,
4934                &rank_inputs[rank],
4935                1,
4936            )?);
4937        }
4938
4939        // Preserve the established canonical activation program for the first native transport
4940        // milestone. The shards move to rank zero over P2P; only the scalar activation expression
4941        // executes on host. A later device-activation increment must earn its own exactness gate.
4942        let gate = self.gather_native_column_shards(&gate_shards, 1, local_out)?;
4943        let up = self.gather_native_column_shards(&up_shards, 1, local_out)?;
4944        let activated = gate
4945            .iter()
4946            .zip(&up)
4947            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
4948            .collect::<Vec<_>>();
4949        debug_assert_eq!(activated.len(), bank.expert_width);
4950
4951        let root_activated = {
4952            let root = &self.ranks[0];
4953            let _main = root.gpu.enter_main()?;
4954            root.htod(&activated)?
4955        };
4956        let mut rank_activated = Vec::with_capacity(self.ranks.len());
4957        for (rank, engine) in self.ranks.iter().enumerate() {
4958            let start = rank * local_out;
4959            let source = root_activated.slice(start..start + local_out);
4960            let local = {
4961                let _main = engine.gpu.enter_main()?;
4962                let mut local = engine.uninit(local_out)?;
4963                engine.stream().memcpy_dtod(&source, &mut local)?;
4964                local
4965            };
4966            rank_activated.push(local);
4967        }
4968
4969        let out_features = bank
4970            .down
4971            .first()
4972            .ok_or("native TP down bank has no ranks")?
4973            .out_features;
4974        let mut reduced = {
4975            let root = &self.ranks[0];
4976            let _main = root.gpu.enter_main()?;
4977            root.htod(&vec![0.0f32; out_features])?
4978        };
4979        let mut remote_partial_keepalive = Vec::new();
4980        for rank in 0..self.ranks.len() {
4981            let down = &bank.down[rank];
4982            let blocks = down
4983                .k_blocks
4984                .ok_or("native TP row bank is not packed in checkpoint-block order")?;
4985            if blocks * FP8_BLOCK != local_out {
4986                return Err(format!(
4987                    "native TP rank {rank} has {blocks} blocks but local activation width is \
4988                     {local_out}"
4989                )
4990                .into());
4991            }
4992            for block in 0..blocks {
4993                let start = block * FP8_BLOCK;
4994                let input_block = rank_activated[rank].slice(start..start + FP8_BLOCK);
4995                let partial = run_resident_bank_expert_block_device(
4996                    &self.ranks[rank],
4997                    down,
4998                    expert,
4999                    block,
5000                    &input_block,
5001                )?;
5002                let root_partial = if rank == 0 {
5003                    partial
5004                } else {
5005                    let root = &self.ranks[0];
5006                    let _main = root.gpu.enter_main()?;
5007                    let mut peer_partial = root.uninit(out_features)?;
5008                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
5009                    remote_partial_keepalive.push(partial);
5010                    peer_partial
5011                };
5012                let next = {
5013                    let root = &self.ranks[0];
5014                    let _main = root.gpu.enter_main()?;
5015                    let mut next = root.uninit(out_features)?;
5016                    root.add(&reduced, &root_partial, &mut next, out_features)?;
5017                    next
5018                };
5019                reduced = next;
5020            }
5021        }
5022        let output = {
5023            let root = &self.ranks[0];
5024            let _main = root.gpu.enter_main()?;
5025            root.dtoh(&reduced)?
5026        };
5027        drop(remote_partial_keepalive);
5028        Ok(output)
5029    }
5030
5031    /// Gather token-major rank-local columns into one canonical root-device matrix.
5032    pub fn gather_native_column_shards_device(
5033        &self,
5034        shards: &[CudaSlice<f32>],
5035        tokens: usize,
5036        local_out: usize,
5037    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5038        let shard_len = tokens
5039            .checked_mul(local_out)
5040            .ok_or("native TP gather shard size overflow")?;
5041        if shards.len() != self.ranks.len() || shards.iter().any(|shard| shard.len() != shard_len) {
5042            return Err("native TP gather shard geometry mismatch".into());
5043        }
5044        // PRODUCER FENCE (2026-08-20 flake fix): the root stream peer-reads shards produced on
5045        // the other ranks' streams; without fencing those producers the copy can read a partial
5046        // kernel output.
5047        for engine in &self.ranks[1..] {
5048            let _main = engine.gpu.enter_main()?;
5049            engine.stream().synchronize()?;
5050        }
5051        let root = &self.ranks[0];
5052        let _main = root.gpu.enter_main()?;
5053        let global_out = shards
5054            .len()
5055            .checked_mul(local_out)
5056            .ok_or("native TP gather output width overflow")?;
5057        let gathered_len = tokens
5058            .checked_mul(global_out)
5059            .ok_or("native TP gather output size overflow")?;
5060        let mut gathered = root.uninit(gathered_len)?;
5061        if self.bulk_p2p {
5062            root.place_rows_strided(&shards[0], &mut gathered, local_out, tokens, global_out, 0)?;
5063            if shards.len() > 1 {
5064                let mut staging = root.uninit(shard_len)?;
5065                for (rank, shard) in shards.iter().enumerate().skip(1) {
5066                    root.stream().memcpy_dtod(shard, &mut staging)?;
5067                    root.place_rows_strided(
5068                        &staging,
5069                        &mut gathered,
5070                        local_out,
5071                        tokens,
5072                        global_out,
5073                        rank * local_out,
5074                    )?;
5075                }
5076            }
5077        } else {
5078            for token in 0..tokens {
5079                for (rank, shard) in shards.iter().enumerate() {
5080                    let source = shard.slice(token * local_out..(token + 1) * local_out);
5081                    let start = token * global_out + rank * local_out;
5082                    let mut destination = gathered.slice_mut(start..start + local_out);
5083                    root.stream().memcpy_dtod(&source, &mut destination)?;
5084                }
5085            }
5086        }
5087        Ok(gathered)
5088    }
5089
5090    pub fn gather_native_column_shards(
5091        &self,
5092        shards: &[CudaSlice<f32>],
5093        tokens: usize,
5094        local_out: usize,
5095    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5096        let gathered = self.gather_native_column_shards_device(shards, tokens, local_out)?;
5097        let root = &self.ranks[0];
5098        let _main = root.gpu.enter_main()?;
5099        root.dtoh(&gathered)
5100    }
5101
5102    pub(crate) fn decode_v2_workspace(&self) -> &std::sync::Mutex<Vec<StepTpDecodeV2Ws>> {
5103        &self.decode_v2
5104    }
5105
5106    /// Build the v2 decode-attention workspace for this layer's geometry on first use, or
5107    /// return the index of the matching one. Attention geometry varies across the trunk
5108    /// (per-layer query-head counts), so workspaces are keyed by their geometry pins — a
5109    /// handful exist per model, never one per layer.
5110    ///
5111    /// Refuses non-F32-resident projections: the v2 driver's bit-exactness claim against v1
5112    /// holds per residency class, and only the mirror class has no per-call weight expansion
5113    /// to hide allocation churn behind.
5114    pub(crate) fn decode_v2_ensure(
5115        &self,
5116        e: &Engine,
5117        q_m: &ResidentBf16ColumnParallel,
5118        k_m: &ResidentBf16ColumnParallel,
5119        v_m: &ResidentBf16ColumnParallel,
5120        o_m: &ResidentStepBf16RowParallel,
5121        heads: usize,
5122    ) -> Result<usize, Box<dyn std::error::Error>> {
5123        if self.ranks.len() > 1 && !self.native_p2p {
5124            return Err("step TP decode v2 requires native P2P ranks".into());
5125        }
5126        let ranks = self.ranks.len();
5127        // Residency contract: the canonical-chunk (non-fused) program needs the F32 mirror;
5128        // the fused-kernel door also reads raw checkpoint bf16 directly (halving the weight
5129        // traffic), so bf16 residency is accepted when that door is on.
5130        let fused_door = step_tp_qkv_fused_enabled()?;
5131        let arm_ok = |weight: &ResidentBf16Weight| match weight {
5132            ResidentBf16Weight::F32(_) => true,
5133            ResidentBf16Weight::Bf16(_) => fused_door,
5134        };
5135        for matrix in [q_m, k_m, v_m] {
5136            validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
5137            if matrix.out_features % ranks != 0 || matrix.in_features != q_m.in_features {
5138                return Err("step TP decode v2 QKV geometry mismatch".into());
5139            }
5140            for rank in &matrix.ranks {
5141                if !arm_ok(&rank.weight) {
5142                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5143                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5144                        .into());
5145                }
5146            }
5147        }
5148        validate_step_bf16_row_residency(&self.ranks, o_m)?;
5149        for blocks in &o_m.ranks {
5150            for block in blocks {
5151                if !arm_ok(&block.weight) {
5152                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5153                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5154                        .into());
5155                }
5156            }
5157        }
5158        if v_m.out_features != k_m.out_features
5159            || o_m.in_features != q_m.out_features
5160            || heads == 0
5161            || heads % ranks != 0
5162        {
5163            return Err("step TP decode v2 K/V/O geometry mismatch".into());
5164        }
5165        let local_q_dim = q_m.out_features / ranks;
5166        let local_kv_dim = k_m.out_features / ranks;
5167        let o_out = o_m.out_features;
5168        let o_block_cols = o_m.canonical_chunk_cols;
5169        let blocks_per_rank = o_m.ranks.first().map(Vec::len).unwrap_or(0);
5170        if blocks_per_rank == 0
5171            || o_m
5172                .ranks
5173                .iter()
5174                .any(|blocks| blocks.len() != blocks_per_rank)
5175            || blocks_per_rank * o_block_cols * ranks != o_m.in_features
5176        {
5177            return Err("step TP decode v2 O canonical block grid mismatch".into());
5178        }
5179
5180        let mut guard = self
5181            .decode_v2
5182            .lock()
5183            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5184        if let Some(index) = guard.iter().position(|ws| {
5185            ws.local_q_dim == local_q_dim
5186                && ws.local_kv_dim == local_kv_dim
5187                && ws.heads == heads
5188                && ws.o_out == o_out
5189                && ws.o_block_cols == o_block_cols
5190                && ws.blocks_per_rank == blocks_per_rank
5191                && ws.e_device == e.ctx().ordinal()
5192                && ws.q.len() == ranks
5193        }) {
5194            return Ok(index);
5195        }
5196
5197        let mut q_raw = Vec::with_capacity(ranks);
5198        let mut k_raw = Vec::with_capacity(ranks);
5199        let mut v_raw = Vec::with_capacity(ranks);
5200        let mut q = Vec::with_capacity(ranks);
5201        let mut k = Vec::with_capacity(ranks);
5202        let mut pos = Vec::with_capacity(ranks);
5203        let mut gate = Vec::with_capacity(ranks);
5204        let mut attn_out = Vec::with_capacity(ranks);
5205        let mut gated = Vec::with_capacity(ranks);
5206        let mut fuse_ctr = Vec::with_capacity(ranks);
5207        let mut o_partials = Vec::with_capacity(ranks);
5208        let mut ev_rank = Vec::with_capacity(ranks);
5209        let direct_join = oproj_direct_on();
5210        for (rank, engine) in self.ranks.iter().enumerate() {
5211            let _main = engine.gpu.enter_main()?;
5212            q_raw.push(engine.uninit(local_q_dim)?);
5213            k_raw.push(engine.uninit(local_kv_dim)?);
5214            v_raw.push(engine.uninit(local_kv_dim)?);
5215            q.push(engine.uninit(local_q_dim)?);
5216            k.push(engine.uninit(local_kv_dim)?);
5217            pos.push(engine.htod_i32(&[0])?);
5218            fuse_ctr.push(engine.stream().clone_htod(&[0u32])?);
5219            gate.push(engine.uninit(heads / ranks)?);
5220            attn_out.push(engine.uninit(local_q_dim)?);
5221            gated.push(engine.uninit(local_q_dim)?);
5222            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
5223            for _ in 0..blocks_per_rank {
5224                // Direct join: peer ranks' partials live on ROOT so the b4 kernel's
5225                // stores land there over P2P (UVA) and no pull copy is needed.
5226                if direct_join && rank != 0 {
5227                    let root = &self.ranks[0];
5228                    let _root_main = root.gpu.enter_main()?;
5229                    rank_partials.push(root.uninit(o_out)?);
5230                } else {
5231                    rank_partials.push(engine.uninit(o_out)?);
5232                }
5233            }
5234            o_partials.push(rank_partials);
5235            ev_rank.push(engine.ctx().new_event(None)?);
5236        }
5237        let root = &self.ranks[0];
5238        let (peer_partial, reduce_a, reduce_b, zeros, k_shadow, v_shadow, ev_refresh, ev_oproj) = {
5239            let _main = root.gpu.enter_main()?;
5240            (
5241                root.uninit(o_out)?,
5242                root.uninit(o_out)?,
5243                root.uninit(o_out)?,
5244                root.htod(&vec![0.0f32; o_out])?,
5245                root.uninit(ranks * local_kv_dim)?,
5246                root.uninit(ranks * local_kv_dim)?,
5247                root.ctx().new_event(None)?,
5248                root.ctx().new_event(None)?,
5249            )
5250        };
5251        let (gate_e, ev_entry) = {
5252            let _main = e.gpu.enter_main()?;
5253            (e.uninit(heads)?, e.ctx().new_event(None)?)
5254        };
5255        let raw_attn_in = Vec::new();
5256        let raw_pos = Vec::new();
5257        guard.push(StepTpDecodeV2Ws {
5258            tcol_q: Vec::new(),
5259            tcol_k: Vec::new(),
5260            tcol_v: Vec::new(),
5261            tcol_g: Vec::new(),
5262            tcol_in: Vec::new(),
5263            tcol_cap: 0,
5264            fa2_q: Vec::new(),
5265            fa2_gate: Vec::new(),
5266            fa2_gated: Vec::new(),
5267            fa2_cap: 0,
5268            tcol_gated: Vec::new(),
5269            tcol_opart: Vec::new(),
5270            tcol_opeer: None,
5271            tcol_omix: None,
5272            tcol_ocap: 0,
5273            q_raw,
5274            k_raw,
5275            v_raw,
5276            q,
5277            k,
5278            pos,
5279            fuse_ctr,
5280            gate,
5281            attn_out,
5282            gated,
5283            o_partials,
5284            ev_rank,
5285            peer_partial,
5286            reduce_a,
5287            reduce_b,
5288            zeros,
5289            k_shadow,
5290            v_shadow,
5291            ev_refresh,
5292            ev_oproj,
5293            gate_e,
5294            attn_in: Vec::new(),
5295            h_stage: None,
5296            pos_stage: None,
5297            raw_h_stage: 0,
5298            raw_pos_stage: 0,
5299            raw_attn_in,
5300            raw_pos,
5301            raw_o_partial1: 0,
5302            raw_peer_partial: 0,
5303            raw_k1: 0,
5304            raw_v1: 0,
5305            raw_k_shadow: 0,
5306            raw_v_shadow: 0,
5307            raw_mixed_stage_e: 0,
5308            raw_reduce_a: 0,
5309            raw_shadow_stage_e: (0, 0),
5310            ev_entry,
5311            e_device: e.ctx().ordinal(),
5312            local_q_dim,
5313            local_kv_dim,
5314            heads,
5315            o_out,
5316            o_block_cols,
5317            blocks_per_rank,
5318        });
5319        eprintln!(
5320            "[step-tp-decode-v2] workspace ranks={ranks} local_q={local_q_dim} \
5321             local_kv={local_kv_dim} heads={heads} o_blocks={blocks_per_rank}x{o_block_cols} \
5322             residency=persistent ordering=evented performance_claim=false"
5323        );
5324        Ok(guard.len() - 1)
5325    }
5326
5327    /// v2 phase 1: replicate the layer input, project QKV, norm, rope, and stage the gate —
5328    /// all into the persistent workspace, ordered by events instead of host syncs.
5329    ///
5330    /// The caller must have queued every producer of `h`, `pos_d`, and `gate_raw` on `e`'s
5331    /// stream BEFORE this call: `ev_entry` is recorded once here and every rank stream waits
5332    /// on it (the entry fence also guards workspace reuse across layers — any consumer of the
5333    /// previous layer's outputs was queued on `e`'s stream before this record).
5334    #[allow(clippy::too_many_arguments)]
5335    /// T-COLUMN verify precompute (spec MTP): stage T input rows to every rank and run the
5336    /// weight-amortized qkvg_tcol per rank into the ws slabs. Rope/norm/append stay per
5337    /// column in the unmodified t=1 program (defer_norm_rope contract). Bit-exact per
5338    /// column vs the t=1 kernel by construction.
5339    #[allow(clippy::too_many_arguments)]
5340    pub fn decode_v2_input_qkv_tcol(
5341        &self,
5342        ws_index: usize,
5343        e: &Engine,
5344        h_t: &CudaSlice<f32>,
5345        t: usize,
5346        q_m: &ResidentBf16ColumnParallel,
5347        k_m: &ResidentBf16ColumnParallel,
5348        v_m: &ResidentBf16ColumnParallel,
5349        gate_shards: Option<StepTpGateShards<'_>>,
5350    ) -> Result<(), Box<dyn std::error::Error>> {
5351        let ranks = self.ranks.len();
5352        let mut guard = self
5353            .decode_v2
5354            .lock()
5355            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5356        let ws = guard
5357            .get_mut(ws_index)
5358            .ok_or("step TP decode v2 workspace index out of range")?;
5359        let in_f = q_m.in_features;
5360        if h_t.len() < t * in_f || t == 0 || t > 8 {
5361            return Err("decode_v2_input_qkv_tcol geometry".into());
5362        }
5363        // Lazily arm the slabs to capacity.
5364        if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
5365            ws.tcol_q.clear();
5366            ws.tcol_k.clear();
5367            ws.tcol_v.clear();
5368            ws.tcol_g.clear();
5369            ws.tcol_in.clear();
5370            for engine in &self.ranks {
5371                let _m = engine.gpu.enter_main()?;
5372                ws.tcol_q.push(engine.uninit(8 * ws.local_q_dim)?);
5373                ws.tcol_k.push(engine.uninit(8 * ws.local_kv_dim)?);
5374                ws.tcol_v.push(engine.uninit(8 * ws.local_kv_dim)?);
5375                ws.tcol_g
5376                    .push(engine.uninit(8 * (ws.heads / ranks).max(1))?);
5377                ws.tcol_in.push(engine.uninit(8 * in_f)?);
5378            }
5379            ws.tcol_cap = 8;
5380        }
5381        // Stage the T input rows on e, fence, per-rank pull + tcol launch.
5382        use cudarc::driver::DevicePtr;
5383        let raw_src = {
5384            let _main = e.gpu.enter_main()?;
5385            let stream = e.stream();
5386            let (p, _g) = h_t.device_ptr(&stream);
5387            ws.ev_entry.record(&stream)?;
5388            p as u64
5389        };
5390        for rank in 0..ranks {
5391            let engine = &self.ranks[rank];
5392            let _main = engine.gpu.enter_main()?;
5393            engine.stream().wait(&ws.ev_entry)?;
5394            let raw_dst = {
5395                let stream = engine.stream();
5396                let (p, _g) = ws.tcol_in[rank].device_ptr(&stream);
5397                p as u64
5398            };
5399            raw_copy_bytes(raw_dst, raw_src, t * in_f * 4, engine)?;
5400            let out_g = match &gate_shards {
5401                Some(_) => ws.heads / ranks,
5402                None => 0,
5403            };
5404            match (
5405                &q_m.ranks[rank].weight,
5406                &k_m.ranks[rank].weight,
5407                &v_m.ranks[rank].weight,
5408            ) {
5409                (
5410                    ResidentBf16Weight::Bf16(wq),
5411                    ResidentBf16Weight::Bf16(wk),
5412                    ResidentBf16Weight::Bf16(wv),
5413                ) => {
5414                    let wg = match &gate_shards {
5415                        Some(StepTpGateShards::Bf16(shards)) => &shards[rank],
5416                        Some(StepTpGateShards::F32(_)) => {
5417                            return Err(
5418                                "tcol verify: gate shard class does not match bf16 QKV".into()
5419                            );
5420                        }
5421                        None => wq,
5422                    };
5423                    let StepTpDecodeV2Ws {
5424                        tcol_q,
5425                        tcol_k,
5426                        tcol_v,
5427                        tcol_g,
5428                        tcol_in,
5429                        local_q_dim,
5430                        local_kv_dim,
5431                        ..
5432                    } = &mut *ws;
5433                    // MEMRA_TCOL_REFKERN=1 (bisect): fill the slabs via the t=1 kernel per
5434                    // column — separates driver bugs from tcol-kernel bugs.
5435                    static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
5436                    let refk = *REFK
5437                        .get_or_init(|| std::env::var("MEMRA_TCOL_REFKERN").as_deref() == Ok("1"));
5438                    if refk {
5439                        let lq = *local_q_dim;
5440                        let lkv = *local_kv_dim;
5441                        let mut hrow = engine.uninit(in_f)?;
5442                        let mut qr = engine.uninit(lq)?;
5443                        let mut kr = engine.uninit(lkv)?;
5444                        let mut vr = engine.uninit(lkv)?;
5445                        let mut gr = engine.uninit(out_g.max(1))?;
5446                        for c in 0..t {
5447                            {
5448                                let mut dst = hrow.slice_mut(0..in_f);
5449                                engine.stream().memcpy_dtod(
5450                                    &tcol_in[rank].slice(c * in_f..(c + 1) * in_f),
5451                                    &mut dst,
5452                                )?;
5453                            }
5454                            engine.matvec_bf16_qkvg_into(
5455                                wq, wk, wv, wg, &hrow, &mut qr, &mut kr, &mut vr, &mut gr, in_f,
5456                                lq, lkv, out_g,
5457                            )?;
5458                            let stream = engine.stream();
5459                            {
5460                                let mut dst = tcol_q[rank].slice_mut(c * lq..(c + 1) * lq);
5461                                stream.memcpy_dtod(&qr.slice(0..lq), &mut dst)?;
5462                            }
5463                            {
5464                                let mut dst = tcol_k[rank].slice_mut(c * lkv..(c + 1) * lkv);
5465                                stream.memcpy_dtod(&kr.slice(0..lkv), &mut dst)?;
5466                            }
5467                            {
5468                                let mut dst = tcol_v[rank].slice_mut(c * lkv..(c + 1) * lkv);
5469                                stream.memcpy_dtod(&vr.slice(0..lkv), &mut dst)?;
5470                            }
5471                            if out_g > 0 {
5472                                let mut dst = tcol_g[rank].slice_mut(c * out_g..(c + 1) * out_g);
5473                                stream.memcpy_dtod(&gr.slice(0..out_g), &mut dst)?;
5474                            }
5475                        }
5476                    } else {
5477                        engine.matvec_bf16_qkvg_tcol_into(
5478                            wq,
5479                            wk,
5480                            wv,
5481                            wg,
5482                            &tcol_in[rank],
5483                            &mut tcol_q[rank],
5484                            &mut tcol_k[rank],
5485                            &mut tcol_v[rank],
5486                            &mut tcol_g[rank],
5487                            in_f,
5488                            *local_q_dim,
5489                            *local_kv_dim,
5490                            out_g,
5491                            t,
5492                        )?;
5493                    }
5494                }
5495                _ => return Err("tcol verify requires bf16-resident fused QKV".into()),
5496            }
5497        }
5498        Ok(())
5499    }
5500
5501    /// MEMRA_TCOL_OPROJ eligibility: the defer replaces exactly the o_fused direct-join
5502    /// finish (bf16 b4 kernel, 2 ranks, 4 canonical blocks) with the shadow gathers
5503    /// skipped — so it requires the same doors that arm dictate that finish shape.
5504    pub(crate) fn decode_v2_oproj_tcol_eligible(
5505        &self,
5506        ws: &StepTpDecodeV2Ws,
5507        o_m: &ResidentStepBf16RowParallel,
5508    ) -> bool {
5509        self.ranks.len() == 2
5510            && ws.blocks_per_rank == 4
5511            && step_tp_qkv_fused_enabled().unwrap_or(false)
5512            && no_local_shadow_on()
5513            && std::env::var("MEMRA_B4_X2").as_deref() != Ok("1")
5514            && o_m
5515                .ranks
5516                .iter()
5517                .flatten()
5518                .all(|block| matches!(block.weight, ResidentBf16Weight::Bf16(_)))
5519    }
5520
5521    /// MEMRA_SPEC_FA2 stash: copy this column's per-rank post-rope q and gate rows into
5522    /// the fa2 slabs (rank-stream ordered behind the rope/append that produced them), and
5523    /// give `e` the same anti-dependency wait the skipped finish provided (next column's
5524    /// h/pos re-staging must not overtake this column's rank pulls).
5525    pub(crate) fn decode_v2_stash_fa2(
5526        &self,
5527        ws: &mut StepTpDecodeV2Ws,
5528        e: &Engine,
5529        col: usize,
5530    ) -> Result<(), Box<dyn std::error::Error>> {
5531        let ranks = self.ranks.len();
5532        if col >= 2 {
5533            return Err("decode_v2_stash_fa2 column out of range".into());
5534        }
5535        let lq = ws.local_q_dim;
5536        let lg = (ws.heads / ranks).max(1);
5537        if ws.fa2_cap == 0 || ws.fa2_q.len() != ranks {
5538            ws.fa2_q.clear();
5539            ws.fa2_gate.clear();
5540            ws.fa2_gated.clear();
5541            for engine in &self.ranks {
5542                let _m = engine.gpu.enter_main()?;
5543                ws.fa2_q.push(engine.uninit(2 * lq)?);
5544                ws.fa2_gate.push(engine.uninit(2 * lg)?);
5545                ws.fa2_gated.push(engine.uninit(2 * lq)?);
5546            }
5547            ws.fa2_cap = 2;
5548        }
5549        for rank in 0..ranks {
5550            let engine = &self.ranks[rank];
5551            let _main = engine.gpu.enter_main()?;
5552            {
5553                let mut dst = ws.fa2_q[rank].slice_mut(col * lq..(col + 1) * lq);
5554                engine
5555                    .stream()
5556                    .memcpy_dtod(&ws.q[rank].slice(0..lq), &mut dst)?;
5557            }
5558            {
5559                let mut dst = ws.fa2_gate[rank].slice_mut(col * lg..(col + 1) * lg);
5560                engine
5561                    .stream()
5562                    .memcpy_dtod(&ws.gate[rank].slice(0..lg), &mut dst)?;
5563            }
5564            ws.ev_rank[rank].record(&engine.stream())?;
5565        }
5566        {
5567            let _main = e.gpu.enter_main()?;
5568            for ev in ws.ev_rank.iter() {
5569                e.stream().wait(ev)?;
5570            }
5571        }
5572        Ok(())
5573    }
5574
5575    /// MEMRA_TCOL_OPROJ stash: copy this column's per-rank `gated` rows into the o-tcol
5576    /// slabs (rank-stream ordered behind the attention kernels that produced them). The
5577    /// per-column finish choreography is skipped entirely; `decode_v2_oproj_tcol` joins
5578    /// every column afterwards.
5579    pub(crate) fn decode_v2_stash_gated(
5580        &self,
5581        ws: &mut StepTpDecodeV2Ws,
5582        e: &Engine,
5583        col: usize,
5584    ) -> Result<(), Box<dyn std::error::Error>> {
5585        let ranks = self.ranks.len();
5586        if col >= 8 {
5587            return Err("decode_v2_stash_gated column out of range".into());
5588        }
5589        let lq = ws.local_q_dim;
5590        if ws.tcol_ocap == 0 || ws.tcol_gated.len() != ranks {
5591            ws.tcol_gated.clear();
5592            ws.tcol_opart.clear();
5593            for engine in &self.ranks {
5594                let _m = engine.gpu.enter_main()?;
5595                ws.tcol_gated.push(engine.uninit(8 * lq)?);
5596                ws.tcol_opart.push(engine.uninit(8 * ws.o_out)?);
5597            }
5598            let root = &self.ranks[0];
5599            let _m = root.gpu.enter_main()?;
5600            ws.tcol_opeer = Some(root.uninit(8 * ws.o_out)?);
5601            ws.tcol_omix = Some(root.uninit(8 * ws.o_out)?);
5602            ws.tcol_ocap = 8;
5603        }
5604        for rank in 0..ranks {
5605            let engine = &self.ranks[rank];
5606            let _main = engine.gpu.enter_main()?;
5607            let mut dst = ws.tcol_gated[rank].slice_mut(col * lq..(col + 1) * lq);
5608            engine
5609                .stream()
5610                .memcpy_dtod(&ws.gated[rank].slice(0..lq), &mut dst)?;
5611            // The skipped finish's e-wait was ALSO the anti-dependency guard: it ordered
5612            // e's NEXT column's h/pos re-staging behind this column's rank-side raw pulls.
5613            // Record each rank here and make e wait — same protection, no o_proj work.
5614            ws.ev_rank[rank].record(&engine.stream())?;
5615        }
5616        {
5617            let _main = e.gpu.enter_main()?;
5618            for ev in ws.ev_rank.iter() {
5619                e.stream().wait(ev)?;
5620            }
5621        }
5622        Ok(())
5623    }
5624
5625    /// MEMRA_TCOL_OPROJ join: one weight-amortized b4_tcol per rank over the stashed
5626    /// `gated` slabs (per-column FP order == the t=1 b4 kernel), one peer pull of rank1's
5627    /// partial slab, one elementwise slab add on the root (independent elements — each
5628    /// column's add is the exact direct-join `add(p0, p1)`), then the joined `mixed` slab
5629    /// lands on `e`. Returns [t, o_out] on the model engine.
5630    pub(crate) fn decode_v2_oproj_tcol(
5631        &self,
5632        ws_index: usize,
5633        e: &Engine,
5634        o_m: &ResidentStepBf16RowParallel,
5635        t: usize,
5636    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5637        let ranks = self.ranks.len();
5638        let mut guard = self
5639            .decode_v2
5640            .lock()
5641            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5642        let ws = guard
5643            .get_mut(ws_index)
5644            .ok_or("step TP decode v2 workspace index out of range")?;
5645        if ranks != 2 || ws.blocks_per_rank != 4 || t == 0 || t > 8 || ws.tcol_ocap < t {
5646            return Err("decode_v2_oproj_tcol geometry".into());
5647        }
5648        for rank in 0..ranks {
5649            let engine = &self.ranks[rank];
5650            let _main = engine.gpu.enter_main()?;
5651            let mut weights = Vec::with_capacity(4);
5652            for block in 0..4 {
5653                let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
5654                    return Err("tcol o_proj requires bf16-resident O blocks".into());
5655                };
5656                weights.push(weight);
5657            }
5658            {
5659                let StepTpDecodeV2Ws {
5660                    tcol_gated,
5661                    tcol_opart,
5662                    local_q_dim,
5663                    o_block_cols,
5664                    o_out,
5665                    ..
5666                } = &mut *ws;
5667                // MEMRA_TCOL_OPROJ_REF=1 (bisect): fill the partial slab via the t=1 b4
5668                // kernel per column — separates choreography bugs from tcol-kernel bugs.
5669                static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
5670                let refk = *REFK
5671                    .get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ_REF").as_deref() == Ok("1"));
5672                if refk {
5673                    let lq = *local_q_dim;
5674                    let mut xr = engine.uninit(lq)?;
5675                    let mut yr = engine.uninit(*o_out)?;
5676                    for c in 0..t {
5677                        {
5678                            let mut dst = xr.slice_mut(0..lq);
5679                            engine.stream().memcpy_dtod(
5680                                &tcol_gated[rank].slice(c * lq..(c + 1) * lq),
5681                                &mut dst,
5682                            )?;
5683                        }
5684                        engine.matvec_bf16_b4_into(
5685                            [weights[0], weights[1], weights[2], weights[3]],
5686                            &xr,
5687                            &mut yr,
5688                            *o_block_cols,
5689                            *o_out,
5690                        )?;
5691                        let mut dst = tcol_opart[rank].slice_mut(c * *o_out..(c + 1) * *o_out);
5692                        engine
5693                            .stream()
5694                            .memcpy_dtod(&yr.slice(0..*o_out), &mut dst)?;
5695                    }
5696                } else {
5697                    engine.matvec_bf16_b4_tcol_into(
5698                        [weights[0], weights[1], weights[2], weights[3]],
5699                        &tcol_gated[rank],
5700                        &mut tcol_opart[rank],
5701                        *o_block_cols,
5702                        *o_out,
5703                        t,
5704                    )?;
5705                }
5706            }
5707            if rank != 0 {
5708                ws.ev_rank[rank].record(&engine.stream())?;
5709            }
5710        }
5711        let root = &self.ranks[0];
5712        {
5713            let _main = root.gpu.enter_main()?;
5714            for ev in ws.ev_rank.iter().skip(1) {
5715                root.stream().wait(ev)?;
5716            }
5717            {
5718                let StepTpDecodeV2Ws {
5719                    tcol_opart,
5720                    tcol_opeer,
5721                    tcol_omix,
5722                    o_out,
5723                    ..
5724                } = &mut *ws;
5725                let opeer = tcol_opeer.as_mut().ok_or("tcol o_proj slabs not armed")?;
5726                let omix = tcol_omix.as_mut().ok_or("tcol o_proj slabs not armed")?;
5727                {
5728                    let mut dst = opeer.slice_mut(0..t * *o_out);
5729                    root.stream()
5730                        .memcpy_dtod(&tcol_opart[1].slice(0..t * *o_out), &mut dst)?;
5731                }
5732                // Elementwise over the whole slab: per element identical to the per-column
5733                // direct-join add (independent lanes, same operand values).
5734                root.add(&tcol_opart[0], opeer, omix, t * *o_out)?;
5735            }
5736            ws.ev_oproj.record(&root.stream())?;
5737        }
5738        let _main = e.gpu.enter_main()?;
5739        e.stream().wait(&ws.ev_oproj)?;
5740        let mut out = e.uninit(t * ws.o_out)?;
5741        let omix = ws.tcol_omix.as_ref().ok_or("tcol o_proj slabs not armed")?;
5742        e.stream().memcpy_dtod(
5743            &omix.slice(0..t * ws.o_out),
5744            &mut out.slice_mut(0..t * ws.o_out),
5745        )?;
5746        Ok(out)
5747    }
5748
5749    pub(crate) fn decode_v2_input_qkv(
5750        &self,
5751        ws: &mut StepTpDecodeV2Ws,
5752        e: &Engine,
5753        h: &CudaSlice<f32>,
5754        pos_d: &CudaSlice<i32>,
5755        gate_raw: Option<&CudaSlice<f32>>,
5756        gate_shards: Option<StepTpGateShards<'_>>,
5757        decode_input: &mut ResidentReplicatedDeviceRows,
5758        q_m: &ResidentBf16ColumnParallel,
5759        k_m: &ResidentBf16ColumnParallel,
5760        v_m: &ResidentBf16ColumnParallel,
5761        q_norm: &[CudaSlice<f32>],
5762        k_norm: &[CudaSlice<f32>],
5763        head_dim: usize,
5764        n_rot: usize,
5765        rope_base: f32,
5766        rope_freqs: &[Option<&CudaSlice<f32>>],
5767        rms_eps: f32,
5768        defer_norm_rope: bool,
5769        tcol_col: Option<usize>,
5770    ) -> Result<(), Box<dyn std::error::Error>> {
5771        let ranks = self.ranks.len();
5772        validate_replicated_device_rows(&self.ranks, decode_input)?;
5773        if decode_input.tokens != 1
5774            || decode_input.width != q_m.in_features
5775            || pos_d.len() != 1
5776            || gate_raw.is_some_and(|gate| gate.len() != ws.heads)
5777            || gate_raw.is_none() != gate_shards.is_some()
5778            || gate_shards.as_ref().is_some_and(|shards| match shards {
5779                StepTpGateShards::F32(shards) => shards.len() != ranks,
5780                StepTpGateShards::Bf16(shards) => shards.len() != ranks,
5781            })
5782            || q_norm.len() != ranks
5783            || k_norm.len() != ranks
5784            || rope_freqs.len() != ranks
5785            || e.ctx().ordinal() != ws.e_device
5786        {
5787            return Err("step TP decode v2 input geometry mismatch".into());
5788        }
5789
5790        let qkv_fused = step_tp_qkv_fused_enabled()?;
5791        if gate_shards.is_some() && !qkv_fused {
5792            return Err("step TP decode v2 gate shards require MEMRA_STEP_TP_QKV_FUSED=1".into());
5793        }
5794        let values = decode_input.width;
5795        if h.len() != values {
5796            return Err(format!(
5797                "step TP decode v2 hidden width {} != replicated width {values}",
5798                h.len()
5799            )
5800            .into());
5801        }
5802
5803        if qkv_fused {
5804            // STAGE-BASED flow (graph increment A): h and pos land in fixed e-context stages
5805            // (one e-stream copy each), the entry event covers them, and every rank raw-copies
5806            // from the stages on its own stream — exactly the shape graph capture wraps.
5807            if ws.h_stage.is_none() {
5808                use cudarc::driver::DevicePtr;
5809                let _main = e.gpu.enter_main()?;
5810                let h_stage = e.uninit(values)?;
5811                let pos_stage = e.htod_i32(&[0])?;
5812                {
5813                    let stream = e.stream();
5814                    let (hp, _g0) = h_stage.device_ptr(&stream);
5815                    let (pp, _g1) = pos_stage.device_ptr(&stream);
5816                    ws.raw_h_stage = hp as u64;
5817                    ws.raw_pos_stage = pp as u64;
5818                }
5819                ws.h_stage = Some(h_stage);
5820                ws.pos_stage = Some(pos_stage);
5821                for rank in 0..ranks {
5822                    use cudarc::driver::DevicePtr;
5823                    let engine = &self.ranks[rank];
5824                    let _rmain = engine.gpu.enter_main()?;
5825                    let attn_in = engine.uninit(values)?;
5826                    let (dp, pp) = {
5827                        let stream = engine.stream();
5828                        let (dp, _g2) = attn_in.device_ptr(&stream);
5829                        let (pp, _g3) = ws.pos[rank].device_ptr(&stream);
5830                        (dp as u64, pp as u64)
5831                    };
5832                    ws.raw_attn_in.push(dp);
5833                    ws.raw_pos.push(pp);
5834                    ws.attn_in.push(attn_in);
5835                }
5836                {
5837                    use cudarc::driver::DevicePtr;
5838                    let root = &self.ranks[0];
5839                    let _rmain = root.gpu.enter_main()?;
5840                    let stream = root.stream();
5841                    let (a, _g) = ws.peer_partial.device_ptr(&stream);
5842                    let (b, _g) = ws.k_shadow.device_ptr(&stream);
5843                    let (c, _g) = ws.v_shadow.device_ptr(&stream);
5844                    ws.raw_peer_partial = a as u64;
5845                    ws.raw_k_shadow = b as u64;
5846                    ws.raw_v_shadow = c as u64;
5847                }
5848                {
5849                    use cudarc::driver::DevicePtr;
5850                    let rank1 = &self.ranks[1];
5851                    let _rmain = rank1.gpu.enter_main()?;
5852                    let stream = rank1.stream();
5853                    let (a, _g) = ws.o_partials[1][0].device_ptr(&stream);
5854                    let (b, _g) = ws.k[1].device_ptr(&stream);
5855                    let (c, _g) = ws.v_raw[1].device_ptr(&stream);
5856                    ws.raw_o_partial1 = a as u64;
5857                    ws.raw_k1 = b as u64;
5858                    ws.raw_v1 = c as u64;
5859                }
5860            }
5861            {
5862                let _main = e.gpu.enter_main()?;
5863                {
5864                    // (Always staged: a tcol column below the dcw floor falls back to the
5865                    // normal fused arm, which reads h through this stage.)
5866                    let h_stage = ws.h_stage.as_mut().expect("stage armed above");
5867                    let mut dst = h_stage.slice_mut(0..values);
5868                    e.stream().memcpy_dtod(&h.slice(0..values), &mut dst)?;
5869                }
5870                {
5871                    let pos_stage = ws.pos_stage.as_mut().expect("stage armed above");
5872                    let mut dst = pos_stage.slice_mut(0..1);
5873                    e.stream().memcpy_dtod(&pos_d.slice(0..1), &mut dst)?;
5874                }
5875                ws.ev_entry.record(&e.stream())?;
5876            }
5877            for rank in 0..ranks {
5878                let engine = &self.ranks[rank];
5879                let _main = engine.gpu.enter_main()?;
5880                engine.stream().wait(&ws.ev_entry)?;
5881            }
5882        } else {
5883            // Evented replicate flow (the pre-stage shape, kept for the non-fused class).
5884            {
5885                let _main = e.gpu.enter_main()?;
5886                if let Some(gate_raw) = gate_raw {
5887                    let mut gate_dst = ws.gate_e.slice_mut(0..ws.heads);
5888                    e.stream()
5889                        .memcpy_dtod(&gate_raw.slice(0..ws.heads), &mut gate_dst)?;
5890                }
5891                ws.ev_entry.record(&e.stream())?;
5892            }
5893            {
5894                let root = &self.ranks[0];
5895                let _main = root.gpu.enter_main()?;
5896                root.stream().wait(&ws.ev_entry)?;
5897                let mut destination = decode_input.ranks[0].slice_mut(0..values);
5898                root.stream()
5899                    .memcpy_dtod(&h.slice(0..values), &mut destination)?;
5900                ws.ev_refresh.record(&root.stream())?;
5901            }
5902            for rank in 1..ranks {
5903                let engine = &self.ranks[rank];
5904                let _main = engine.gpu.enter_main()?;
5905                engine.stream().wait(&ws.ev_refresh)?;
5906                let (root_rows, peer_rows) = decode_input.ranks.split_at_mut(rank);
5907                let mut destination = peer_rows[0].slice_mut(0..values);
5908                engine
5909                    .stream()
5910                    .memcpy_dtod(&root_rows[0].slice(0..values), &mut destination)?;
5911            }
5912        }
5913        for rank in 0..ranks {
5914            self.decode_v2_input_qkv_rank(
5915                ws,
5916                pos_d,
5917                decode_input,
5918                q_m,
5919                k_m,
5920                v_m,
5921                q_norm,
5922                k_norm,
5923                head_dim,
5924                n_rot,
5925                rope_base,
5926                rope_freqs,
5927                rms_eps,
5928                gate_shards.as_ref(),
5929                qkv_fused,
5930                defer_norm_rope,
5931                rank,
5932                tcol_col,
5933            )?;
5934        }
5935        Ok(())
5936    }
5937
5938    /// One rank's slice of `decode_v2_input_qkv` (projection, norm+rope, gate staging) — the
5939    /// per-device issue unit the whole-token graph captures on that rank's stream.
5940    #[allow(clippy::too_many_arguments)]
5941    pub(crate) fn decode_v2_input_qkv_rank(
5942        &self,
5943        ws: &mut StepTpDecodeV2Ws,
5944        pos_d: &CudaSlice<i32>,
5945        decode_input: &mut ResidentReplicatedDeviceRows,
5946        q_m: &ResidentBf16ColumnParallel,
5947        k_m: &ResidentBf16ColumnParallel,
5948        v_m: &ResidentBf16ColumnParallel,
5949        q_norm: &[CudaSlice<f32>],
5950        k_norm: &[CudaSlice<f32>],
5951        head_dim: usize,
5952        n_rot: usize,
5953        rope_base: f32,
5954        rope_freqs: &[Option<&CudaSlice<f32>>],
5955        rms_eps: f32,
5956        gate_shards: Option<&StepTpGateShards<'_>>,
5957        qkv_fused: bool,
5958        defer_norm_rope: bool,
5959        rank: usize,
5960        tcol_col: Option<usize>,
5961    ) -> Result<(), Box<dyn std::error::Error>> {
5962        let ranks = self.ranks.len();
5963        let local_heads = ws.local_q_dim / head_dim;
5964        let local_kv_heads = ws.local_kv_dim / head_dim;
5965        let engine = &self.ranks[rank];
5966        let _main = engine.gpu.enter_main()?;
5967        let ws_e_device = ws.e_device;
5968        // T-COLUMN SELECT (spec verify): the projections for this column were precomputed
5969        // by the weight-amortized tcol kernel — copy the column into the single-row buffers
5970        // (pure f32 moves, bit-exact) and skip the per-column matvec. Rope/norm/append run
5971        // below exactly as in the t=1 program.
5972        if qkv_fused && tcol_col.is_some() {
5973            let c = tcol_col.expect("checked");
5974            if ws.tcol_cap == 0 || ws.tcol_q.len() != ranks {
5975                return Err("tcol select without precompute".into());
5976            }
5977            // The select skips the matvec but NOT the position: rope/append below still
5978            // read this rank's pos buffer, which only the (skipped) stage path fills for
5979            // peer-device ranks. Stage it here or rank1 ropes at the previous position.
5980            if engine.ctx().ordinal() != ws_e_device {
5981                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
5982            }
5983            let StepTpDecodeV2Ws {
5984                tcol_q,
5985                tcol_k,
5986                tcol_v,
5987                tcol_g,
5988                q_raw,
5989                k_raw,
5990                v_raw,
5991                gate,
5992                local_q_dim,
5993                local_kv_dim,
5994                heads,
5995                ..
5996            } = &mut *ws;
5997            let lg = *heads / ranks;
5998            let stream = engine.stream();
5999            {
6000                let mut dst = q_raw[rank].slice_mut(0..*local_q_dim);
6001                stream.memcpy_dtod(
6002                    &tcol_q[rank].slice(c * *local_q_dim..(c + 1) * *local_q_dim),
6003                    &mut dst,
6004                )?;
6005            }
6006            {
6007                let mut dst = k_raw[rank].slice_mut(0..*local_kv_dim);
6008                stream.memcpy_dtod(
6009                    &tcol_k[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
6010                    &mut dst,
6011                )?;
6012            }
6013            {
6014                let mut dst = v_raw[rank].slice_mut(0..*local_kv_dim);
6015                stream.memcpy_dtod(
6016                    &tcol_v[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
6017                    &mut dst,
6018                )?;
6019            }
6020            if lg > 0 {
6021                let mut dst = gate[rank].slice_mut(0..lg);
6022                stream.memcpy_dtod(&tcol_g[rank].slice(c * lg..(c + 1) * lg), &mut dst)?;
6023            }
6024            if !defer_norm_rope {
6025                // Below the dcw floor (or a non-defer shape) the col-select cannot apply:
6026                // fall through and recompute this column's QKV from the REAL h row — the
6027                // caller always passes it. The slab copies above are dead stores.
6028            } else {
6029                return Ok(());
6030            }
6031        }
6032        if qkv_fused {
6033            // Stage-based input: raw copies from the fixed e-context stages (capture-safe;
6034            // eager ordering comes from the caller's ev_entry wait on this stream). The rank
6035            // SHARING e's device reads the stages directly — same context (probed), ordering
6036            // identical (ev_entry / graph edge), bytes identical: the copies are pure waste.
6037            let same_dev = engine.ctx().ordinal() == ws.e_device;
6038            if !same_dev {
6039                raw_copy_bytes(
6040                    ws.raw_attn_in[rank],
6041                    ws.raw_h_stage,
6042                    q_m.in_features * 4,
6043                    engine,
6044                )?;
6045                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
6046            }
6047            let StepTpDecodeV2Ws {
6048                q_raw,
6049                k_raw,
6050                v_raw,
6051                gate,
6052                gate_e,
6053                attn_in,
6054                h_stage,
6055                heads,
6056                local_q_dim,
6057                local_kv_dim,
6058                ..
6059            } = &mut *ws;
6060            let input_ref: &CudaSlice<f32> = if same_dev {
6061                h_stage
6062                    .as_ref()
6063                    .ok_or("step TP decode v2 stage not armed")?
6064            } else {
6065                &attn_in[rank]
6066            };
6067            match (
6068                &q_m.ranks[rank].weight,
6069                &k_m.ranks[rank].weight,
6070                &v_m.ranks[rank].weight,
6071            ) {
6072                (
6073                    ResidentBf16Weight::F32(wq),
6074                    ResidentBf16Weight::F32(wk),
6075                    ResidentBf16Weight::F32(wv),
6076                ) => {
6077                    let (wg, out_g) = match &gate_shards {
6078                        Some(StepTpGateShards::F32(shards)) => (&shards[rank], *heads / ranks),
6079                        Some(StepTpGateShards::Bf16(_)) => {
6080                            return Err("step TP decode v2 gate shard class does not \
6081                                            match the F32 projections"
6082                                .into());
6083                        }
6084                        // out_g = 0: the kernel never reads wg; any resident buffer works.
6085                        None => (&*gate_e, 0),
6086                    };
6087                    engine.matvec_f32_qkv_into(
6088                        wq,
6089                        wk,
6090                        wv,
6091                        wg,
6092                        input_ref,
6093                        &mut q_raw[rank],
6094                        &mut k_raw[rank],
6095                        &mut v_raw[rank],
6096                        &mut gate[rank],
6097                        q_m.in_features,
6098                        *local_q_dim,
6099                        *local_kv_dim,
6100                        out_g,
6101                    )?;
6102                }
6103                (
6104                    ResidentBf16Weight::Bf16(wq),
6105                    ResidentBf16Weight::Bf16(wk),
6106                    ResidentBf16Weight::Bf16(wv),
6107                ) => {
6108                    let (wg, out_g) = match &gate_shards {
6109                        Some(StepTpGateShards::Bf16(shards)) => (&shards[rank], *heads / ranks),
6110                        Some(StepTpGateShards::F32(_)) => {
6111                            return Err("step TP decode v2 gate shard class does not \
6112                                            match the bf16 projections"
6113                                .into());
6114                        }
6115                        None => (wq, 0),
6116                    };
6117                    engine.matvec_bf16_qkvg_into(
6118                        wq,
6119                        wk,
6120                        wv,
6121                        wg,
6122                        input_ref,
6123                        &mut q_raw[rank],
6124                        &mut k_raw[rank],
6125                        &mut v_raw[rank],
6126                        &mut gate[rank],
6127                        q_m.in_features,
6128                        *local_q_dim,
6129                        *local_kv_dim,
6130                        out_g,
6131                    )?;
6132                }
6133                _ => {
6134                    return Err("step TP decode v2 QKV projections mix residency classes".into());
6135                }
6136            }
6137        } else {
6138            for (matrix, local_out, raw) in [
6139                (q_m, ws.local_q_dim, &mut ws.q_raw),
6140                (k_m, ws.local_kv_dim, &mut ws.k_raw),
6141                (v_m, ws.local_kv_dim, &mut ws.v_raw),
6142            ] {
6143                let ResidentBf16Weight::F32(values_w) = &matrix.ranks[rank].weight else {
6144                    return Err("step TP decode v2 lost its F32 projection residency".into());
6145                };
6146                let chunk_rows = matrix.canonical_chunk_rows.unwrap_or(local_out);
6147                engine.linear_f32_resident_canonical_rows_t1_into(
6148                    &decode_input.ranks[rank],
6149                    values_w,
6150                    &mut raw[rank],
6151                    matrix.in_features,
6152                    local_out,
6153                    chunk_rows,
6154                )?;
6155            }
6156        }
6157        if qkv_fused && defer_norm_rope {
6158            // FUSION #1 defers norm+rope to the caller's fused rope+append+inc launch.
6159        } else if qkv_fused {
6160            // Fused norm+rope: one launch; the position comes from the rank-local staged
6161            // copy (raw-copied above from the fixed e-context pos stage — capture-safe).
6162            let StepTpDecodeV2Ws {
6163                q_raw,
6164                k_raw,
6165                q,
6166                k,
6167                pos,
6168                pos_stage,
6169                ..
6170            } = &mut *ws;
6171            let same_dev = engine.ctx().ordinal() == ws_e_device;
6172            let pos_ref: &CudaSlice<i32> = if same_dev {
6173                pos_stage
6174                    .as_ref()
6175                    .ok_or("step TP decode v2 pos stage not armed")?
6176            } else {
6177                &pos[rank]
6178            };
6179            engine.qk_norm_rope_into(
6180                &q_raw[rank],
6181                &k_raw[rank],
6182                &q_norm[rank],
6183                &k_norm[rank],
6184                &mut q[rank],
6185                &mut k[rank],
6186                pos_ref,
6187                head_dim,
6188                n_rot,
6189                local_heads,
6190                local_kv_heads,
6191                rms_eps,
6192                rope_base,
6193                1.0,
6194                rope_freqs[rank],
6195            )?;
6196        } else {
6197            engine.rms_norm(
6198                &ws.q_raw[rank],
6199                &q_norm[rank],
6200                &mut ws.q[rank],
6201                head_dim,
6202                local_heads,
6203                rms_eps,
6204            )?;
6205            engine.rms_norm(
6206                &ws.k_raw[rank],
6207                &k_norm[rank],
6208                &mut ws.k[rank],
6209                head_dim,
6210                local_kv_heads,
6211                rms_eps,
6212            )?;
6213            {
6214                let mut pos_dst = ws.pos[rank].slice_mut(0..1);
6215                engine
6216                    .stream()
6217                    .memcpy_dtod(&pos_d.slice(0..1), &mut pos_dst)?;
6218            }
6219            engine.rope_neox2(
6220                &mut ws.q[rank],
6221                &mut ws.k[rank],
6222                &ws.pos[rank],
6223                head_dim,
6224                n_rot,
6225                local_heads,
6226                local_kv_heads,
6227                1,
6228                rope_base,
6229                1.0,
6230                rope_freqs[rank],
6231            )?;
6232        }
6233        if gate_shards.is_none() {
6234            let gate_start = rank * (ws.heads / ranks);
6235            let mut gate_dst = ws.gate[rank].slice_mut(0..ws.heads / ranks);
6236            engine.stream().memcpy_dtod(
6237                &ws.gate_e.slice(gate_start..gate_start + ws.heads / ranks),
6238                &mut gate_dst,
6239            )?;
6240        }
6241        Ok(())
6242    }
6243
6244    /// One rank's O-partial slice of `decode_v2_finish` — the per-device issue unit the
6245    /// whole-token graph captures on that rank's stream (the rank-done event stays with the
6246    /// eager caller; graphs order via parent edges instead).
6247    pub(crate) fn decode_v2_finish_rank_partial(
6248        &self,
6249        ws: &mut StepTpDecodeV2Ws,
6250        o_m: &ResidentStepBf16RowParallel,
6251        o_fused: bool,
6252        rank: usize,
6253    ) -> Result<(), Box<dyn std::error::Error>> {
6254        let engine = &self.ranks[rank];
6255        let _main = engine.gpu.enter_main()?;
6256        if o_fused {
6257            let StepTpDecodeV2Ws {
6258                gated,
6259                o_partials,
6260                o_block_cols,
6261                o_out,
6262                ..
6263            } = &mut *ws;
6264            let all_f32 = o_m.ranks[rank]
6265                .iter()
6266                .all(|block| matches!(block.weight, ResidentBf16Weight::F32(_)));
6267            if all_f32 {
6268                let mut weights = Vec::with_capacity(4);
6269                for block in 0..4 {
6270                    let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
6271                        unreachable!("all_f32 checked above");
6272                    };
6273                    weights.push(weight);
6274                }
6275                engine.matvec_f32_b4_into(
6276                    [weights[0], weights[1], weights[2], weights[3]],
6277                    &gated[rank],
6278                    &mut o_partials[rank][0],
6279                    *o_block_cols,
6280                    *o_out,
6281                )?;
6282            } else {
6283                let mut weights = Vec::with_capacity(4);
6284                for block in 0..4 {
6285                    let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
6286                        return Err("step TP decode v2 O projections mix residency classes".into());
6287                    };
6288                    weights.push(weight);
6289                }
6290                engine.matvec_bf16_b4_into(
6291                    [weights[0], weights[1], weights[2], weights[3]],
6292                    &gated[rank],
6293                    &mut o_partials[rank][0],
6294                    *o_block_cols,
6295                    *o_out,
6296                )?;
6297            }
6298        } else {
6299            for block in 0..ws.blocks_per_rank {
6300                let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
6301                    return Err("step TP decode v2 lost its F32 O residency".into());
6302                };
6303                let x =
6304                    ws.gated[rank].slice(block * ws.o_block_cols..(block + 1) * ws.o_block_cols);
6305                let w = weight.slice(0..weight.len());
6306                let mut y = ws.o_partials[rank][block].slice_mut(0..ws.o_out);
6307                engine.linear_t1_into(&x, &w, &mut y, ws.o_block_cols, ws.o_out)?;
6308            }
6309        }
6310        Ok(())
6311    }
6312
6313    /// v2 phase 2: canonical-block O reduction on the root device plus the K/V shadow gathers,
6314    /// returning a fresh model-engine output ordered behind `ev_oproj` on `e`'s stream.
6315    ///
6316    /// The caller must have queued every rank's attention work (reading `ws.gated`, `ws.k`,
6317    /// `ws.v_raw`) on the rank streams before this call. Reduction order is identical to
6318    /// `step_bf16_row_parallel_resident_native`: zeros, then rank 0's blocks, then each peer
6319    /// rank's blocks, one `add` per block.
6320    pub(crate) fn decode_v2_finish(
6321        &self,
6322        ws: &mut StepTpDecodeV2Ws,
6323        e: &Engine,
6324        o_m: &ResidentStepBf16RowParallel,
6325    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6326        let ranks = self.ranks.len();
6327        if e.ctx().ordinal() != ws.e_device {
6328            return Err("step TP decode v2 finish engine changed".into());
6329        }
6330        // MEMRA_STEP_TP_QKV_FUSED extends to the O path: one matvec_f32_b4 launch per rank
6331        // (in-order canonical block accumulation per element) and a single peer-copy + add on
6332        // the root, replacing 4 cuBLASLt launches per rank + the 4-copy/8-add chain. Same
6333        // numeric-class door and gate as the fused QKV projection.
6334        let o_fused = step_tp_qkv_fused_enabled()? && ws.blocks_per_rank == 4 && ranks == 2;
6335
6336        // Per-rank O block partials on the owning rank's stream (serial after the attention
6337        // kernels the driver queued there), then the rank-done event for root's peer reads.
6338        for rank in 0..ranks {
6339            self.decode_v2_finish_rank_partial(ws, o_m, o_fused, rank)?;
6340            if rank == 0 {
6341                // root == rank0: its own stream order covers the partial; only peers need
6342                // the record/wait pair (host-op diet, matches the routes-arm skip).
6343                continue;
6344            }
6345            let engine = &self.ranks[rank];
6346            let _main = engine.gpu.enter_main()?;
6347            ws.ev_rank[rank].record(&engine.stream())?;
6348        }
6349
6350        // Root reduce in canonical order + shadow gathers, all on the root stream.
6351        let root = &self.ranks[0];
6352        #[allow(unused_assignments)]
6353        let mut final_in_a = false;
6354        {
6355            let _main = root.gpu.enter_main()?;
6356            for ev in ws.ev_rank.iter().skip(1) {
6357                root.stream().wait(ev)?;
6358            }
6359            if o_fused && oproj_direct_on() && ranks == 2 && no_local_shadow_on() {
6360                // DIRECT JOIN: rank1's partial already sits in root memory (P2P kernel
6361                // stores; visibility guaranteed by the ev_rank[1] wait above), rank0's
6362                // partial is root-stream-ordered — record ONE event and let the model
6363                // engine do the single add itself, straight into its own output row.
6364                // Same operands, same add order as finish_root_fused: BIT-IDENTICAL.
6365                ws.ev_oproj.record(&root.stream())?;
6366                let _main = e.gpu.enter_main()?;
6367                e.stream().wait(&ws.ev_oproj)?;
6368                let mut output = e.uninit(ws.o_out)?;
6369                if oproj_tail_on() && oproj_tail_eligible() {
6370                    // M2: defer the add into the residual+norm consumer (waits stay HERE;
6371                    // only the arithmetic moves). `output` is returned unwritten.
6372                    use cudarc::driver::DevicePtr;
6373                    let stream = e.stream();
6374                    let (p0, _g0) = ws.o_partials[0][0].device_ptr(&stream);
6375                    let (p1, _g1) = ws.o_partials[1][0].device_ptr(&stream);
6376                    set_oproj_tail((p0 as u64, p1 as u64));
6377                    return Ok(output);
6378                }
6379                e.add(
6380                    &ws.o_partials[0][0],
6381                    &ws.o_partials[1][0],
6382                    &mut output,
6383                    ws.o_out,
6384                )?;
6385                return Ok(output);
6386            }
6387            if o_fused {
6388                self.decode_v2_finish_root_fused(ws)?;
6389                ws.ev_oproj.record(&root.stream())?;
6390                let _main = e.gpu.enter_main()?;
6391                e.stream().wait(&ws.ev_oproj)?;
6392                let mut output = e.uninit(ws.o_out)?;
6393                e.stream().memcpy_dtod(
6394                    &ws.reduce_a.slice(0..ws.o_out),
6395                    &mut output.slice_mut(0..ws.o_out),
6396                )?;
6397                return Ok(output);
6398            }
6399            let mut first = true;
6400            let mut current_is_a = false;
6401            for rank in 0..ranks {
6402                for block in 0..ws.blocks_per_rank {
6403                    let use_peer = rank != 0;
6404                    if use_peer {
6405                        root.stream()
6406                            .memcpy_dtod(&ws.o_partials[rank][block], &mut ws.peer_partial)?;
6407                    }
6408                    // add(prev, partial) -> the other reduce buffer, exactly one add per block
6409                    match (first, current_is_a, use_peer) {
6410                        (true, _, true) => {
6411                            root.add(&ws.zeros, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
6412                        }
6413                        (true, _, false) => root.add(
6414                            &ws.zeros,
6415                            &ws.o_partials[0][block],
6416                            &mut ws.reduce_a,
6417                            ws.o_out,
6418                        )?,
6419                        (false, true, true) => {
6420                            root.add(&ws.reduce_a, &ws.peer_partial, &mut ws.reduce_b, ws.o_out)?
6421                        }
6422                        (false, true, false) => root.add(
6423                            &ws.reduce_a,
6424                            &ws.o_partials[0][block],
6425                            &mut ws.reduce_b,
6426                            ws.o_out,
6427                        )?,
6428                        (false, false, true) => {
6429                            root.add(&ws.reduce_b, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
6430                        }
6431                        (false, false, false) => root.add(
6432                            &ws.reduce_b,
6433                            &ws.o_partials[0][block],
6434                            &mut ws.reduce_a,
6435                            ws.o_out,
6436                        )?,
6437                    }
6438                    current_is_a = first || !current_is_a;
6439                    first = false;
6440                }
6441            }
6442            final_in_a = current_is_a;
6443
6444            for rank in 0..ranks {
6445                let start = rank * ws.local_kv_dim;
6446                let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
6447                root.stream().memcpy_dtod(&ws.k[rank], &mut k_dst)?;
6448                let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
6449                root.stream().memcpy_dtod(&ws.v_raw[rank], &mut v_dst)?;
6450            }
6451            ws.ev_oproj.record(&root.stream())?;
6452        }
6453
6454        // Model-engine output: e waits the root event, then copies the reduced row into a
6455        // fresh e-context buffer (same ownership contract as v1's `e.htod`). The same wait
6456        // orders the driver's shadow append (it reads ws.k_shadow/ws.v_shadow on e's stream).
6457        let _main = e.gpu.enter_main()?;
6458        e.stream().wait(&ws.ev_oproj)?;
6459        let mut output = e.uninit(ws.o_out)?;
6460        let source = if final_in_a {
6461            &ws.reduce_a
6462        } else {
6463            &ws.reduce_b
6464        };
6465        e.stream().memcpy_dtod(
6466            &source.slice(0..ws.o_out),
6467            &mut output.slice_mut(0..ws.o_out),
6468        )?;
6469        Ok(output)
6470    }
6471
6472    pub fn run_routed_experts(
6473        &self,
6474        experts: &ResidentExpertParallel,
6475        input: &[f32],
6476        tokens: usize,
6477        selected: &[usize],
6478        route_weights: &[f32],
6479        experts_per_token: usize,
6480        activation_limit: Option<f32>,
6481    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
6482        validate_step_expert_activation_limit(activation_limit)?;
6483        validate_ep_residency(&self.ranks, experts)?;
6484        validate_activations(input, tokens, experts.input_width)?;
6485        let pairs = tokens
6486            .checked_mul(experts_per_token)
6487            .ok_or("EP route count overflow")?;
6488        if selected.len() != pairs || route_weights.len() != pairs {
6489            return Err(format!(
6490                "EP routes selected={} weights={} != tokens {tokens} x experts/token \
6491                 {experts_per_token} ({pairs})",
6492                selected.len(),
6493                route_weights.len(),
6494            )
6495            .into());
6496        }
6497        if !route_weights.iter().all(|weight| weight.is_finite()) {
6498            return Err("EP route weights contain a non-finite value".into());
6499        }
6500        if self.native_p2p {
6501            return self.run_routed_experts_native(
6502                experts,
6503                input,
6504                tokens,
6505                selected,
6506                route_weights,
6507                experts_per_token,
6508                activation_limit,
6509            );
6510        }
6511
6512        let mut output = vec![0.0f32; tokens * experts.input_width];
6513        let per_rank = experts.expert_count / experts.ranks.len();
6514        for token in 0..tokens {
6515            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
6516            for slot in 0..experts_per_token {
6517                let pair = token * experts_per_token + slot;
6518                let expert = selected[pair];
6519                if expert >= experts.expert_count {
6520                    return Err(format!(
6521                        "EP selected expert {expert} outside 0..{}",
6522                        experts.expert_count
6523                    )
6524                    .into());
6525                }
6526                let owner = expert / per_rank;
6527                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
6528                let rank = &experts.ranks[owner];
6529                let engine = &self.ranks[owner];
6530                let gate =
6531                    run_resident_bank_expert(engine, &rank.gate, local_expert, input_row, 1)?;
6532                let up = run_resident_bank_expert(engine, &rank.up, local_expert, input_row, 1)?;
6533                let activated: Vec<f32> = gate
6534                    .iter()
6535                    .zip(&up)
6536                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
6537                    .collect();
6538                debug_assert_eq!(activated.len(), experts.expert_width);
6539                let down =
6540                    run_resident_bank_expert(engine, &rank.down, local_expert, &activated, 1)?;
6541                let weight = route_weights[pair];
6542                for (sum, value) in output
6543                    [token * experts.input_width..(token + 1) * experts.input_width]
6544                    .iter_mut()
6545                    .zip(down)
6546                {
6547                    *sum += weight * value;
6548                }
6549            }
6550        }
6551        Ok(output)
6552    }
6553
6554    fn run_routed_experts_native(
6555        &self,
6556        experts: &ResidentExpertParallel,
6557        input: &[f32],
6558        tokens: usize,
6559        selected: &[usize],
6560        route_weights: &[f32],
6561        experts_per_token: usize,
6562        activation_limit: Option<f32>,
6563    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
6564        if !self.native_p2p || self.ranks.len() < 2 {
6565            return Err("native EP execution requires at least two P2P ranks".into());
6566        }
6567        if self.ep_device_arithmetic {
6568            return self.run_routed_experts_native_device(
6569                experts,
6570                input,
6571                tokens,
6572                selected,
6573                route_weights,
6574                experts_per_token,
6575                activation_limit,
6576            );
6577        }
6578        let mut output = vec![0.0f32; tokens * experts.input_width];
6579        let per_rank = experts.expert_count / experts.ranks.len();
6580        for token in 0..tokens {
6581            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
6582            let mut rank_inputs = (0..self.ranks.len())
6583                .map(|_| None)
6584                .collect::<Vec<Option<CudaSlice<f32>>>>();
6585            rank_inputs[0] = Some({
6586                let root = &self.ranks[0];
6587                let _main = root.gpu.enter_main()?;
6588                root.htod(input_row)?
6589            });
6590
6591            for slot in 0..experts_per_token {
6592                let pair = token * experts_per_token + slot;
6593                let expert = selected[pair];
6594                if expert >= experts.expert_count {
6595                    return Err(format!(
6596                        "EP selected expert {expert} outside 0..{}",
6597                        experts.expert_count
6598                    )
6599                    .into());
6600                }
6601                let owner = expert / per_rank;
6602                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
6603                if rank_inputs[owner].is_none() {
6604                    let peer_input = {
6605                        let root_input = rank_inputs[0]
6606                            .as_ref()
6607                            .ok_or("native EP lost its root input")?;
6608                        let engine = &self.ranks[owner];
6609                        let _main = engine.gpu.enter_main()?;
6610                        let mut peer_input = engine.uninit(experts.input_width)?;
6611                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
6612                        peer_input
6613                    };
6614                    rank_inputs[owner] = Some(peer_input);
6615                }
6616
6617                let rank = &experts.ranks[owner];
6618                let engine = &self.ranks[owner];
6619                let owner_input = rank_inputs[owner]
6620                    .as_ref()
6621                    .ok_or("native EP owner input is absent after dispatch")?;
6622                let gate = run_resident_bank_expert_device(
6623                    engine,
6624                    &rank.gate,
6625                    local_expert,
6626                    owner_input,
6627                    1,
6628                )?;
6629                let up = run_resident_bank_expert_device(
6630                    engine,
6631                    &rank.up,
6632                    local_expert,
6633                    owner_input,
6634                    1,
6635                )?;
6636                let (gate, up) = {
6637                    let _main = engine.gpu.enter_main()?;
6638                    (engine.dtoh(&gate)?, engine.dtoh(&up)?)
6639                };
6640                let activated = gate
6641                    .iter()
6642                    .zip(&up)
6643                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
6644                    .collect::<Vec<_>>();
6645                debug_assert_eq!(activated.len(), experts.expert_width);
6646                let activated = {
6647                    let _main = engine.gpu.enter_main()?;
6648                    engine.htod(&activated)?
6649                };
6650                let down = run_resident_bank_expert_device(
6651                    engine,
6652                    &rank.down,
6653                    local_expert,
6654                    &activated,
6655                    1,
6656                )?;
6657                let down = if owner == 0 {
6658                    let _main = engine.gpu.enter_main()?;
6659                    engine.dtoh(&down)?
6660                } else {
6661                    let root = &self.ranks[0];
6662                    let _main = root.gpu.enter_main()?;
6663                    let mut root_down = root.uninit(experts.input_width)?;
6664                    root.stream().memcpy_dtod(&down, &mut root_down)?;
6665                    root.dtoh(&root_down)?
6666                };
6667                let weight = route_weights[pair];
6668                for (sum, value) in output
6669                    [token * experts.input_width..(token + 1) * experts.input_width]
6670                    .iter_mut()
6671                    .zip(down)
6672                {
6673                    *sum += weight * value;
6674                }
6675            }
6676        }
6677        Ok(output)
6678    }
6679
6680    fn run_routed_experts_native_device(
6681        &self,
6682        experts: &ResidentExpertParallel,
6683        input: &[f32],
6684        tokens: usize,
6685        selected: &[usize],
6686        route_weights: &[f32],
6687        experts_per_token: usize,
6688        activation_limit: Option<f32>,
6689    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
6690        if !self.native_p2p || !self.ep_device_arithmetic || self.ranks.len() < 2 {
6691            return Err(
6692                "device-resident EP arithmetic requires at least two native P2P ranks".into(),
6693            );
6694        }
6695        let mut output = Vec::with_capacity(tokens * experts.input_width);
6696        let per_rank = experts.expert_count / experts.ranks.len();
6697        let root = &self.ranks[0];
6698        for token in 0..tokens {
6699            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
6700            let mut rank_inputs = (0..self.ranks.len())
6701                .map(|_| None)
6702                .collect::<Vec<Option<CudaSlice<f32>>>>();
6703            rank_inputs[0] = Some({
6704                let _main = root.gpu.enter_main()?;
6705                root.htod(input_row)?
6706            });
6707            let mut root_output = {
6708                let _main = root.gpu.enter_main()?;
6709                root.zeros(experts.input_width)?
6710            };
6711            let mut remote_down_keepalive = Vec::new();
6712
6713            for slot in 0..experts_per_token {
6714                let pair = token * experts_per_token + slot;
6715                let expert = selected[pair];
6716                if expert >= experts.expert_count {
6717                    return Err(format!(
6718                        "EP selected expert {expert} outside 0..{}",
6719                        experts.expert_count
6720                    )
6721                    .into());
6722                }
6723                let owner = expert / per_rank;
6724                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
6725                if rank_inputs[owner].is_none() {
6726                    let peer_input = {
6727                        let root_input = rank_inputs[0]
6728                            .as_ref()
6729                            .ok_or("native EP lost its root input")?;
6730                        let engine = &self.ranks[owner];
6731                        let _main = engine.gpu.enter_main()?;
6732                        let mut peer_input = engine.uninit(experts.input_width)?;
6733                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
6734                        peer_input
6735                    };
6736                    rank_inputs[owner] = Some(peer_input);
6737                }
6738
6739                let rank = &experts.ranks[owner];
6740                let engine = &self.ranks[owner];
6741                let owner_input = rank_inputs[owner]
6742                    .as_ref()
6743                    .ok_or("native EP owner input is absent after dispatch")?;
6744                let gate = run_resident_bank_expert_device(
6745                    engine,
6746                    &rank.gate,
6747                    local_expert,
6748                    owner_input,
6749                    1,
6750                )?;
6751                let up = run_resident_bank_expert_device(
6752                    engine,
6753                    &rank.up,
6754                    local_expert,
6755                    owner_input,
6756                    1,
6757                )?;
6758                let activated = {
6759                    let _main = engine.gpu.enter_main()?;
6760                    let mut activated = engine.uninit(experts.expert_width)?;
6761                    if let Some(limit) = activation_limit {
6762                        engine.silu_clamped_mul_host_expf(
6763                            &gate,
6764                            &up,
6765                            limit,
6766                            &mut activated,
6767                            experts.expert_width,
6768                        )?;
6769                    } else {
6770                        engine.silu_mul_host_expf(
6771                            &gate,
6772                            &up,
6773                            &mut activated,
6774                            experts.expert_width,
6775                        )?;
6776                    }
6777                    activated
6778                };
6779                let down = run_resident_bank_expert_device(
6780                    engine,
6781                    &rank.down,
6782                    local_expert,
6783                    &activated,
6784                    1,
6785                )?;
6786                let root_down = if owner == 0 {
6787                    down
6788                } else {
6789                    let _main = root.gpu.enter_main()?;
6790                    let mut root_down = root.uninit(experts.input_width)?;
6791                    root.stream().memcpy_dtod(&down, &mut root_down)?;
6792                    // The peer copy runs on the root stream. Keep its remote source alive until
6793                    // the final root readback synchronizes that stream; otherwise async free can
6794                    // recycle the owner's allocation while cuMemcpyPeerAsync is still reading it.
6795                    remote_down_keepalive.push(down);
6796                    root_down
6797                };
6798                let _main = root.gpu.enter_main()?;
6799                let mut destination = root_output.slice_mut(0..experts.input_width);
6800                root.axpy_host_into(
6801                    &root_down.slice(0..root_down.len()),
6802                    route_weights[pair],
6803                    &mut destination,
6804                    experts.input_width,
6805                )?;
6806            }
6807
6808            let _main = root.gpu.enter_main()?;
6809            let root_output = root.dtoh(&root_output)?;
6810            drop(remote_down_keepalive);
6811            output.extend(root_output);
6812        }
6813        Ok(output)
6814    }
6815}
6816
6817fn validate_column_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
6818    if matrix.out_features % tp != 0 {
6819        return Err(format!(
6820            "column-parallel out_features {} is not divisible by TP={tp}",
6821            matrix.out_features
6822        ));
6823    }
6824    let local_out = matrix.out_features / tp;
6825    if local_out % FP8_BLOCK != 0 {
6826        return Err(format!(
6827            "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
6828             E4M3 scale block"
6829        ));
6830    }
6831    Ok(())
6832}
6833
6834fn step_bf16_canonical_chunk_rows(out_features: usize, tp: usize) -> Result<usize, String> {
6835    if !matches!(tp, 1 | 2 | 4 | 8) {
6836        return Err(format!(
6837            "Step BF16 canonical projection requires TP1/TP2/TP4/TP8, got TP={tp}"
6838        ));
6839    }
6840    if out_features == 0 || out_features % PRODUCT_MAX_CARDS != 0 {
6841        return Err(format!(
6842            "Step BF16 output width {out_features} is not divisible by the TP8 product envelope"
6843        ));
6844    }
6845    let canonical_rows = out_features / PRODUCT_MAX_CARDS;
6846    let local_out = out_features / tp;
6847    if local_out % canonical_rows != 0 {
6848        return Err(format!(
6849            "Step BF16 TP={tp} output shard {local_out} is not divisible by canonical \
6850             {canonical_rows}-row chunks"
6851        ));
6852    }
6853    Ok(canonical_rows)
6854}
6855
6856fn step_bf16_canonical_chunk_cols(in_features: usize, tp: usize) -> Result<usize, String> {
6857    if !matches!(tp, 1 | 2 | 4 | 8) {
6858        return Err(format!(
6859            "Step BF16 canonical row projection requires TP1/TP2/TP4/TP8, got TP={tp}"
6860        ));
6861    }
6862    if in_features == 0 || in_features % PRODUCT_MAX_CARDS != 0 {
6863        return Err(format!(
6864            "Step BF16 input width {in_features} is not divisible by the TP8 product envelope"
6865        ));
6866    }
6867    let canonical_cols = in_features / PRODUCT_MAX_CARDS;
6868    let local_in = in_features / tp;
6869    if local_in % canonical_cols != 0 {
6870        return Err(format!(
6871            "Step BF16 TP={tp} input shard {local_in} is not divisible by canonical \
6872             {canonical_cols}-column chunks"
6873        ));
6874    }
6875    Ok(canonical_cols)
6876}
6877
6878fn validate_row_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
6879    if matrix.in_features % tp != 0 {
6880        return Err(format!(
6881            "row-parallel in_features {} is not divisible by TP={tp}",
6882            matrix.in_features
6883        ));
6884    }
6885    let local_in = matrix.in_features / tp;
6886    if local_in % FP8_BLOCK != 0 {
6887        return Err(format!(
6888            "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
6889             E4M3 scale block"
6890        ));
6891    }
6892    Ok(())
6893}
6894
6895fn upload_rank(
6896    engine: &Engine,
6897    matrix: E4m3BlockMatrix<'_>,
6898) -> Result<ResidentE4m3Rank, Box<dyn std::error::Error>> {
6899    let _main = engine.gpu.enter_main()?;
6900    matrix.validate()?;
6901    Ok(ResidentE4m3Rank {
6902        codes: engine.htod_bytes(matrix.codes)?,
6903        scales: engine.htod(matrix.scales)?,
6904        out_features: matrix.out_features,
6905        in_features: matrix.in_features,
6906    })
6907}
6908
6909fn upload_bf16_rank(
6910    engine: &Engine,
6911    matrix: Bf16Matrix<'_>,
6912    f32_mirror: bool,
6913) -> Result<ResidentBf16Rank, Box<dyn std::error::Error>> {
6914    let _main = engine.gpu.enter_main()?;
6915    matrix.validate()?;
6916    let bytes = engine.htod_bytes(matrix.bytes)?;
6917    let weight = if f32_mirror {
6918        let values = matrix
6919            .out_features
6920            .checked_mul(matrix.in_features)
6921            .ok_or("resident BF16 mirror element count overflow")?;
6922        ResidentBf16Weight::F32(engine.bf16_to_f32(&bytes.slice(0..bytes.len()), values)?)
6923    } else {
6924        ResidentBf16Weight::Bf16(bytes)
6925    };
6926    Ok(ResidentBf16Rank {
6927        weight,
6928        out_features: matrix.out_features,
6929        in_features: matrix.in_features,
6930    })
6931}
6932
6933fn upload_expert_bank_rank(
6934    engine: &Engine,
6935    bank: E4m3ExpertBank<'_>,
6936    expert_range: Range<usize>,
6937) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
6938    let _main = engine.gpu.enter_main()?;
6939    bank.validate()?;
6940    if expert_range.start >= expert_range.end || expert_range.end > bank.expert_count {
6941        return Err(format!(
6942            "invalid EP expert range {expert_range:?} for {} experts",
6943            bank.expert_count
6944        )
6945        .into());
6946    }
6947    let code_stride = bank.out_features * bank.in_features;
6948    let scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * bank.in_features.div_ceil(FP8_BLOCK);
6949    Ok(ResidentE4m3ExpertBankRank {
6950        codes: engine.htod_bytes(
6951            &bank.codes[expert_range.start * code_stride..expert_range.end * code_stride],
6952        )?,
6953        scales: engine.htod(
6954            &bank.scales[expert_range.start * scale_stride..expert_range.end * scale_stride],
6955        )?,
6956        expert_range,
6957        out_features: bank.out_features,
6958        in_features: bank.in_features,
6959        code_stride,
6960        scale_stride,
6961        k_blocks: None,
6962    })
6963}
6964
6965fn validate_column_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
6966    if bank.out_features % tp != 0 {
6967        return Err(format!(
6968            "TP expert output width {} is not divisible by TP={tp}",
6969            bank.out_features
6970        ));
6971    }
6972    let local_out = bank.out_features / tp;
6973    if local_out % FP8_BLOCK != 0 {
6974        return Err(format!(
6975            "TP expert output shard {local_out} cuts through a {FP8_BLOCK}-row E4M3 scale block"
6976        ));
6977    }
6978    Ok(())
6979}
6980
6981fn validate_row_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
6982    if bank.in_features % tp != 0 {
6983        return Err(format!(
6984            "TP expert input width {} is not divisible by TP={tp}",
6985            bank.in_features
6986        ));
6987    }
6988    let local_in = bank.in_features / tp;
6989    if local_in % FP8_BLOCK != 0 {
6990        return Err(format!(
6991            "TP expert input shard {local_in} cuts through a {FP8_BLOCK}-column E4M3 scale block"
6992        ));
6993    }
6994    Ok(())
6995}
6996
6997fn upload_column_bank_rank(
6998    engine: &Engine,
6999    bank: E4m3ExpertBank<'_>,
7000    tp: usize,
7001    rank: usize,
7002) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
7003    let _main = engine.gpu.enter_main()?;
7004    let packed = pack_column_bank_rank(bank, tp, rank)?;
7005    Ok(ResidentE4m3ExpertBankRank {
7006        codes: engine.htod_bytes(&packed.codes)?,
7007        scales: engine.htod(&packed.scales)?,
7008        expert_range: packed.expert_range,
7009        out_features: packed.out_features,
7010        in_features: packed.in_features,
7011        code_stride: packed.code_stride,
7012        scale_stride: packed.scale_stride,
7013        k_blocks: packed.k_blocks,
7014    })
7015}
7016
7017fn pack_column_bank_rank(
7018    bank: E4m3ExpertBank<'_>,
7019    tp: usize,
7020    rank: usize,
7021) -> Result<PackedE4m3ExpertBankRank, String> {
7022    bank.validate()?;
7023    validate_column_bank_shape(bank, tp)?;
7024    if rank >= tp {
7025        return Err(format!("TP rank {rank} outside 0..{tp}"));
7026    }
7027    let local_out = bank.out_features / tp;
7028    let full_code_stride = bank.out_features * bank.in_features;
7029    let local_code_stride = local_out * bank.in_features;
7030    let scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
7031    let full_scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * scale_cols;
7032    let local_scale_rows = local_out / FP8_BLOCK;
7033    let local_scale_stride = local_scale_rows * scale_cols;
7034    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
7035    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
7036    let row_start = rank * local_out;
7037    let scale_row_start = rank * local_scale_rows;
7038    for expert in 0..bank.expert_count {
7039        let code_start = expert * full_code_stride + row_start * bank.in_features;
7040        codes.extend_from_slice(&bank.codes[code_start..code_start + local_code_stride]);
7041        let scale_start = expert * full_scale_stride + scale_row_start * scale_cols;
7042        scales.extend_from_slice(&bank.scales[scale_start..scale_start + local_scale_stride]);
7043    }
7044    Ok(PackedE4m3ExpertBankRank {
7045        codes,
7046        scales,
7047        expert_range: 0..bank.expert_count,
7048        out_features: local_out,
7049        in_features: bank.in_features,
7050        code_stride: local_code_stride,
7051        scale_stride: local_scale_stride,
7052        k_blocks: None,
7053    })
7054}
7055
7056fn upload_row_bank_rank(
7057    engine: &Engine,
7058    bank: E4m3ExpertBank<'_>,
7059    tp: usize,
7060    rank: usize,
7061) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
7062    let _main = engine.gpu.enter_main()?;
7063    let packed = pack_row_bank_rank(bank, tp, rank)?;
7064    Ok(ResidentE4m3ExpertBankRank {
7065        codes: engine.htod_bytes(&packed.codes)?,
7066        scales: engine.htod(&packed.scales)?,
7067        expert_range: packed.expert_range,
7068        out_features: packed.out_features,
7069        in_features: packed.in_features,
7070        code_stride: packed.code_stride,
7071        scale_stride: packed.scale_stride,
7072        k_blocks: packed.k_blocks,
7073    })
7074}
7075
7076fn pack_row_bank_rank(
7077    bank: E4m3ExpertBank<'_>,
7078    tp: usize,
7079    rank: usize,
7080) -> Result<PackedE4m3ExpertBankRank, String> {
7081    bank.validate()?;
7082    validate_row_bank_shape(bank, tp)?;
7083    if rank >= tp {
7084        return Err(format!("TP rank {rank} outside 0..{tp}"));
7085    }
7086    let local_in = bank.in_features / tp;
7087    let full_code_stride = bank.out_features * bank.in_features;
7088    let local_code_stride = bank.out_features * local_in;
7089    let full_scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
7090    let local_scale_cols = local_in / FP8_BLOCK;
7091    let scale_rows = bank.out_features.div_ceil(FP8_BLOCK);
7092    let full_scale_stride = scale_rows * full_scale_cols;
7093    let local_scale_stride = scale_rows * local_scale_cols;
7094    let global_block_start = rank * local_scale_cols;
7095    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
7096    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
7097    for expert in 0..bank.expert_count {
7098        let expert_code_start = expert * full_code_stride;
7099        let expert_scale_start = expert * full_scale_stride;
7100        for local_block in 0..local_scale_cols {
7101            let global_block = global_block_start + local_block;
7102            let column_start = global_block * FP8_BLOCK;
7103            for row in 0..bank.out_features {
7104                let start = expert_code_start + row * bank.in_features + column_start;
7105                codes.extend_from_slice(&bank.codes[start..start + FP8_BLOCK]);
7106            }
7107            for row in 0..scale_rows {
7108                scales.push(bank.scales[expert_scale_start + row * full_scale_cols + global_block]);
7109            }
7110        }
7111    }
7112    Ok(PackedE4m3ExpertBankRank {
7113        codes,
7114        scales,
7115        expert_range: 0..bank.expert_count,
7116        out_features: bank.out_features,
7117        in_features: local_in,
7118        code_stride: local_code_stride,
7119        scale_stride: local_scale_stride,
7120        k_blocks: Some(local_scale_cols),
7121    })
7122}
7123
7124fn validate_resident_ranks(engines: &[Engine], ranks: &[ResidentE4m3Rank]) -> Result<(), String> {
7125    if engines.len() != ranks.len() {
7126        return Err(format!(
7127            "resident TP rank count {} != runtime rank count {}",
7128            ranks.len(),
7129            engines.len()
7130        ));
7131    }
7132    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
7133        let device = engine.ctx().ordinal();
7134        if matrix.codes.ordinal() != device || matrix.scales.ordinal() != device {
7135            return Err(format!(
7136                "resident TP rank {rank} is not owned by runtime device {device}"
7137            ));
7138        }
7139    }
7140    Ok(())
7141}
7142
7143fn validate_tp_bank_residency(
7144    engines: &[Engine],
7145    experts: &ResidentTpExpertBank,
7146) -> Result<(), String> {
7147    if engines.len() != experts.gate.len()
7148        || engines.len() != experts.up.len()
7149        || engines.len() != experts.down.len()
7150    {
7151        return Err(format!(
7152            "resident TP expert-bank rank counts gate={} up={} down={} != runtime {}",
7153            experts.gate.len(),
7154            experts.up.len(),
7155            experts.down.len(),
7156            engines.len()
7157        ));
7158    }
7159    for (rank, engine) in engines.iter().enumerate() {
7160        let device = engine.ctx().ordinal();
7161        for (projection, bank) in [
7162            ("gate", &experts.gate[rank]),
7163            ("up", &experts.up[rank]),
7164            ("down", &experts.down[rank]),
7165        ] {
7166            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
7167                return Err(format!(
7168                    "resident TP rank {rank} {projection} bank is not owned by runtime device \
7169                     {device}"
7170                ));
7171            }
7172        }
7173    }
7174    Ok(())
7175}
7176
7177fn validate_ep_residency(
7178    engines: &[Engine],
7179    experts: &ResidentExpertParallel,
7180) -> Result<(), String> {
7181    if engines.len() != experts.ranks.len() {
7182        return Err(format!(
7183            "resident EP rank count {} != runtime rank count {}",
7184            experts.ranks.len(),
7185            engines.len()
7186        ));
7187    }
7188    for (rank, (engine, resident)) in engines.iter().zip(&experts.ranks).enumerate() {
7189        let device = engine.ctx().ordinal();
7190        for (projection, bank) in [
7191            ("gate", &resident.gate),
7192            ("up", &resident.up),
7193            ("down", &resident.down),
7194        ] {
7195            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
7196                return Err(format!(
7197                    "resident EP rank {rank} {projection} bank is not owned by runtime device \
7198                     {device}"
7199                ));
7200            }
7201        }
7202    }
7203    Ok(())
7204}
7205
7206fn run_rank(
7207    engine: &Engine,
7208    matrix: E4m3BlockMatrix<'_>,
7209    activations: &[f32],
7210    tokens: usize,
7211) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7212    let _main = engine.gpu.enter_main()?;
7213    let codes = engine.htod_bytes(matrix.codes)?;
7214    let scales = engine.htod(matrix.scales)?;
7215    let activations = engine.htod(activations)?;
7216    let output = engine.qmatvec_mmq_fp8_blk(
7217        &codes,
7218        &scales,
7219        &activations,
7220        tokens,
7221        matrix.in_features,
7222        matrix.out_features,
7223    )?;
7224    engine.dtoh(&output)
7225}
7226
7227fn run_resident_rank(
7228    engine: &Engine,
7229    matrix: &ResidentE4m3Rank,
7230    activations: &[f32],
7231    tokens: usize,
7232) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7233    let _main = engine.gpu.enter_main()?;
7234    let activations = engine.htod(activations)?;
7235    let output = engine.qmatvec_mmq_fp8_blk(
7236        &matrix.codes,
7237        &matrix.scales,
7238        &activations,
7239        tokens,
7240        matrix.in_features,
7241        matrix.out_features,
7242    )?;
7243    engine.dtoh(&output)
7244}
7245
7246fn run_resident_bf16_rank(
7247    engine: &Engine,
7248    matrix: &ResidentBf16Rank,
7249    activations: &[f32],
7250    tokens: usize,
7251    canonical_chunk_rows: Option<usize>,
7252) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7253    let _main = engine.gpu.enter_main()?;
7254    let activations = engine.htod(activations)?;
7255    let output = run_resident_bf16_rank_device(
7256        engine,
7257        matrix,
7258        &activations,
7259        tokens,
7260        canonical_chunk_rows,
7261        false,
7262    )?;
7263    engine.dtoh(&output)
7264}
7265
7266fn run_resident_bf16_rank_device(
7267    engine: &Engine,
7268    matrix: &ResidentBf16Rank,
7269    activations: &CudaSlice<f32>,
7270    tokens: usize,
7271    canonical_chunk_rows: Option<usize>,
7272    strided_chunk_output: bool,
7273) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7274    let _main = engine.gpu.enter_main()?;
7275    if activations.ordinal() != engine.ctx().ordinal() {
7276        return Err(format!(
7277            "resident BF16 activation device {} != rank device {}",
7278            activations.ordinal(),
7279            engine.ctx().ordinal()
7280        )
7281        .into());
7282    }
7283    if activations.len() != tokens * matrix.in_features {
7284        return Err(format!(
7285            "resident BF16 activation count {} != {tokens}x{}",
7286            activations.len(),
7287            matrix.in_features
7288        )
7289        .into());
7290    }
7291    match (&matrix.weight, canonical_chunk_rows) {
7292        (ResidentBf16Weight::Bf16(bytes), Some(rows)) => engine
7293            .linear_bf16_resident_canonical_rows(
7294                activations,
7295                bytes,
7296                tokens,
7297                matrix.in_features,
7298                matrix.out_features,
7299                rows,
7300            ),
7301        (ResidentBf16Weight::Bf16(bytes), None) => engine.linear_bf16_resident(
7302            activations,
7303            bytes,
7304            tokens,
7305            matrix.in_features,
7306            matrix.out_features,
7307        ),
7308        (ResidentBf16Weight::F32(values), Some(rows)) if strided_chunk_output => engine
7309            .linear_f32_resident_canonical_rows_strided(
7310                activations,
7311                values,
7312                tokens,
7313                matrix.in_features,
7314                matrix.out_features,
7315                rows,
7316            ),
7317        (ResidentBf16Weight::F32(values), Some(rows)) => engine.linear_f32_resident_canonical_rows(
7318            activations,
7319            values,
7320            tokens,
7321            matrix.in_features,
7322            matrix.out_features,
7323            rows,
7324        ),
7325        (ResidentBf16Weight::F32(values), None) => engine.linear(
7326            activations,
7327            values,
7328            tokens,
7329            matrix.in_features,
7330            matrix.out_features,
7331        ),
7332    }
7333}
7334
7335fn validate_resident_bf16_ranks(
7336    engines: &[Engine],
7337    ranks: &[ResidentBf16Rank],
7338) -> Result<(), String> {
7339    if engines.len() != ranks.len() {
7340        return Err(format!(
7341            "resident BF16 TP rank count {} != runtime rank count {}",
7342            ranks.len(),
7343            engines.len(),
7344        ));
7345    }
7346    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
7347        let device = engine.ctx().ordinal();
7348        if matrix.weight.ordinal() != device {
7349            return Err(format!(
7350                "resident BF16 TP rank {rank} is not owned by runtime device {device}"
7351            ));
7352        }
7353    }
7354    Ok(())
7355}
7356
7357fn validate_step_bf16_row_residency(
7358    engines: &[Engine],
7359    matrix: &ResidentStepBf16RowParallel,
7360) -> Result<(), String> {
7361    if engines.len() != matrix.ranks.len() {
7362        return Err(format!(
7363            "resident Step BF16 row rank count {} != runtime rank count {}",
7364            matrix.ranks.len(),
7365            engines.len(),
7366        ));
7367    }
7368    let canonical_cols = step_bf16_canonical_chunk_cols(matrix.in_features, engines.len())?;
7369    if matrix.canonical_chunk_cols != canonical_cols {
7370        return Err(format!(
7371            "resident Step BF16 row canonical columns {} != registered {canonical_cols}",
7372            matrix.canonical_chunk_cols
7373        ));
7374    }
7375    let blocks_per_rank = PRODUCT_MAX_CARDS / engines.len();
7376    for (rank, (engine, blocks)) in engines.iter().zip(&matrix.ranks).enumerate() {
7377        if blocks.len() != blocks_per_rank {
7378            return Err(format!(
7379                "resident Step BF16 row rank {rank} has {} blocks, expected {blocks_per_rank}",
7380                blocks.len()
7381            ));
7382        }
7383        let device = engine.ctx().ordinal();
7384        for (block, resident) in blocks.iter().enumerate() {
7385            if resident.weight.ordinal() != device
7386                || resident.in_features != canonical_cols
7387                || resident.out_features != matrix.out_features
7388            {
7389                return Err(format!(
7390                    "resident Step BF16 row rank {rank} block {block} has inconsistent \
7391                     device or geometry"
7392                ));
7393            }
7394        }
7395    }
7396    Ok(())
7397}
7398
7399fn validate_replicated_device_rows(
7400    engines: &[Engine],
7401    rows: &ResidentReplicatedDeviceRows,
7402) -> Result<(), String> {
7403    let rank_lengths = rows
7404        .ranks
7405        .iter()
7406        .map(|rank_rows| rank_rows.len())
7407        .collect::<Vec<_>>();
7408    replicated_device_row_values(rows.tokens, rows.width, engines.len(), &rank_lengths)?;
7409    if rows
7410        .ranks
7411        .iter()
7412        .zip(engines)
7413        .any(|(rank_rows, engine)| rank_rows.ordinal() != engine.ctx().ordinal())
7414    {
7415        return Err("replicated device rows are owned by the wrong CUDA contexts".into());
7416    }
7417    Ok(())
7418}
7419
7420fn replicated_device_row_values(
7421    tokens: usize,
7422    width: usize,
7423    expected_ranks: usize,
7424    rank_lengths: &[usize],
7425) -> Result<usize, String> {
7426    let values = tokens
7427        .checked_mul(width)
7428        .ok_or("replicated device row size overflow")?;
7429    if tokens == 0
7430        || width == 0
7431        || expected_ranks == 0
7432        || rank_lengths.len() != expected_ranks
7433        || rank_lengths.iter().any(|&rank_len| rank_len != values)
7434    {
7435        return Err(format!(
7436            "replicated device rows have inconsistent geometry tokens={} width={} ranks={}/{}",
7437            tokens,
7438            width,
7439            rank_lengths.len(),
7440            expected_ranks
7441        ));
7442    }
7443    Ok(values)
7444}
7445
7446fn replicated_device_row_source_values(
7447    tokens: usize,
7448    width: usize,
7449    source_len: usize,
7450    source_device: usize,
7451    root_device: usize,
7452) -> Result<usize, String> {
7453    let values = tokens
7454        .checked_mul(width)
7455        .ok_or("replicated device row size overflow")?;
7456    if tokens == 0 || width == 0 || source_len != values || source_device != root_device {
7457        return Err(format!(
7458            "replicated device row source has inconsistent geometry/device \
7459             tokens={tokens} width={width} source={source_len}@{source_device} root={root_device}"
7460        ));
7461    }
7462    Ok(values)
7463}
7464
7465fn bf16_column_shard(
7466    matrix: Bf16Matrix<'_>,
7467    tp: usize,
7468    rank: usize,
7469) -> Result<Bf16Matrix<'_>, String> {
7470    matrix.validate()?;
7471    if tp == 0 || rank >= tp || matrix.out_features % tp != 0 {
7472        return Err(format!(
7473            "invalid BF16 column shard out={} TP={tp} rank={rank}",
7474            matrix.out_features
7475        ));
7476    }
7477    let local_out = matrix.out_features / tp;
7478    let row_bytes = matrix.in_features * 2;
7479    let start = rank * local_out * row_bytes;
7480    Ok(Bf16Matrix {
7481        bytes: &matrix.bytes[start..start + local_out * row_bytes],
7482        out_features: local_out,
7483        in_features: matrix.in_features,
7484    })
7485}
7486
7487fn bf16_row_shard(matrix: Bf16Matrix<'_>, tp: usize, rank: usize) -> Result<Vec<u8>, String> {
7488    matrix.validate()?;
7489    if tp == 0 || rank >= tp || matrix.in_features % tp != 0 {
7490        return Err(format!(
7491            "invalid BF16 row shard in={} TP={tp} rank={rank}",
7492            matrix.in_features
7493        ));
7494    }
7495    let local_in = matrix.in_features / tp;
7496    let mut bytes = Vec::with_capacity(matrix.out_features * local_in * 2);
7497    for row in 0..matrix.out_features {
7498        let start = (row * matrix.in_features + rank * local_in) * 2;
7499        bytes.extend_from_slice(&matrix.bytes[start..start + local_in * 2]);
7500    }
7501    Ok(bytes)
7502}
7503
7504fn bf16_row_block(
7505    matrix: Bf16Matrix<'_>,
7506    col_start: usize,
7507    block_cols: usize,
7508) -> Result<Vec<u8>, String> {
7509    matrix.validate()?;
7510    let col_end = col_start
7511        .checked_add(block_cols)
7512        .ok_or("BF16 row block column overflow")?;
7513    if block_cols == 0 || col_end > matrix.in_features {
7514        return Err(format!(
7515            "invalid BF16 row block columns {col_start}..{col_end} for input width {}",
7516            matrix.in_features
7517        ));
7518    }
7519    let mut bytes = Vec::with_capacity(matrix.out_features * block_cols * 2);
7520    for row in 0..matrix.out_features {
7521        let start = (row * matrix.in_features + col_start) * 2;
7522        bytes.extend_from_slice(&matrix.bytes[start..start + block_cols * 2]);
7523    }
7524    Ok(bytes)
7525}
7526
7527fn run_resident_bank_expert(
7528    engine: &Engine,
7529    bank: &ResidentE4m3ExpertBankRank,
7530    local_expert: usize,
7531    activations: &[f32],
7532    tokens: usize,
7533) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7534    let _main = engine.gpu.enter_main()?;
7535    if bank.k_blocks.is_some() {
7536        return Err("block-major TP row bank requires canonical block execution".into());
7537    }
7538    let local_count = bank.expert_range.end - bank.expert_range.start;
7539    if local_expert >= local_count {
7540        return Err(format!(
7541            "local EP expert {local_expert} outside 0..{local_count} for range {:?}",
7542            bank.expert_range
7543        )
7544        .into());
7545    }
7546    validate_activations(activations, tokens, bank.in_features)?;
7547    let activations = engine.htod(activations)?;
7548    let weight = bank
7549        .codes
7550        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
7551    let scales = bank
7552        .scales
7553        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
7554    let input = activations.slice(0..activations.len());
7555    let output = engine.qmatvec_mmq_fp8_blk_view(
7556        &weight,
7557        &scales,
7558        &input,
7559        tokens,
7560        bank.in_features,
7561        bank.out_features,
7562    )?;
7563    engine.dtoh(&output)
7564}
7565
7566fn run_resident_bank_expert_block(
7567    engine: &Engine,
7568    bank: &ResidentE4m3ExpertBankRank,
7569    local_expert: usize,
7570    block: usize,
7571    activations: &[f32],
7572) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7573    let _main = engine.gpu.enter_main()?;
7574    let local_count = bank.expert_range.end - bank.expert_range.start;
7575    if local_expert >= local_count {
7576        return Err(format!(
7577            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
7578            bank.expert_range
7579        )
7580        .into());
7581    }
7582    let blocks = bank
7583        .k_blocks
7584        .ok_or("TP row bank is not packed in native K-block order")?;
7585    if block >= blocks {
7586        return Err(format!("TP row block {block} outside 0..{blocks}").into());
7587    }
7588    validate_activations(activations, 1, FP8_BLOCK)?;
7589    let block_code_stride = bank.out_features * FP8_BLOCK;
7590    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
7591    if bank.in_features != blocks * FP8_BLOCK
7592        || bank.code_stride != blocks * block_code_stride
7593        || bank.scale_stride != blocks * block_scale_stride
7594    {
7595        return Err("TP row bank block-major geometry is inconsistent".into());
7596    }
7597
7598    let expert_code_start = local_expert * bank.code_stride;
7599    let expert_scale_start = local_expert * bank.scale_stride;
7600    let weight = bank.codes.slice(
7601        expert_code_start + block * block_code_stride
7602            ..expert_code_start + (block + 1) * block_code_stride,
7603    );
7604    let scales = bank.scales.slice(
7605        expert_scale_start + block * block_scale_stride
7606            ..expert_scale_start + (block + 1) * block_scale_stride,
7607    );
7608    let activations = engine.htod(activations)?;
7609    let input = activations.slice(0..activations.len());
7610    let output = engine.qmatvec_mmq_fp8_blk_view(
7611        &weight,
7612        &scales,
7613        &input,
7614        1,
7615        FP8_BLOCK,
7616        bank.out_features,
7617    )?;
7618    engine.dtoh(&output)
7619}
7620
7621fn run_resident_bank_expert_device(
7622    engine: &Engine,
7623    bank: &ResidentE4m3ExpertBankRank,
7624    local_expert: usize,
7625    activations: &CudaSlice<f32>,
7626    tokens: usize,
7627) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7628    let _main = engine.gpu.enter_main()?;
7629    if bank.k_blocks.is_some() {
7630        return Err("block-major TP row bank requires canonical block execution".into());
7631    }
7632    let local_count = bank.expert_range.end - bank.expert_range.start;
7633    if local_expert >= local_count {
7634        return Err(format!(
7635            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
7636            bank.expert_range
7637        )
7638        .into());
7639    }
7640    let expected = tokens
7641        .checked_mul(bank.in_features)
7642        .ok_or("native TP activation size overflow")?;
7643    if activations.len() != expected || activations.ordinal() != engine.ctx().ordinal() {
7644        return Err(format!(
7645            "native TP activation len/device {}/{} != expected {expected}/{}",
7646            activations.len(),
7647            activations.ordinal(),
7648            engine.ctx().ordinal()
7649        )
7650        .into());
7651    }
7652    let weight = bank
7653        .codes
7654        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
7655    let scales = bank
7656        .scales
7657        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
7658    let input = activations.slice(0..activations.len());
7659    engine.qmatvec_mmq_fp8_blk_view(
7660        &weight,
7661        &scales,
7662        &input,
7663        tokens,
7664        bank.in_features,
7665        bank.out_features,
7666    )
7667}
7668
7669fn run_resident_bank_expert_block_device(
7670    engine: &Engine,
7671    bank: &ResidentE4m3ExpertBankRank,
7672    local_expert: usize,
7673    block: usize,
7674    activations: &cudarc::driver::CudaView<'_, f32>,
7675) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7676    let _main = engine.gpu.enter_main()?;
7677    let local_count = bank.expert_range.end - bank.expert_range.start;
7678    if local_expert >= local_count {
7679        return Err(format!(
7680            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
7681            bank.expert_range
7682        )
7683        .into());
7684    }
7685    let blocks = bank
7686        .k_blocks
7687        .ok_or("native TP row bank is not packed in checkpoint-block order")?;
7688    if block >= blocks {
7689        return Err(format!("native TP row block {block} outside 0..{blocks}").into());
7690    }
7691    let activation_device = activations.stream().context().ordinal();
7692    if activations.len() != FP8_BLOCK || activation_device != engine.ctx().ordinal() {
7693        return Err(format!(
7694            "native TP block activation len/device {}/{} != expected {FP8_BLOCK}/{}",
7695            activations.len(),
7696            activation_device,
7697            engine.ctx().ordinal()
7698        )
7699        .into());
7700    }
7701    let block_code_stride = bank.out_features * FP8_BLOCK;
7702    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
7703    if bank.in_features != blocks * FP8_BLOCK
7704        || bank.code_stride != blocks * block_code_stride
7705        || bank.scale_stride != blocks * block_scale_stride
7706    {
7707        return Err("native TP row bank block-major geometry is inconsistent".into());
7708    }
7709    let expert_code_start = local_expert * bank.code_stride;
7710    let expert_scale_start = local_expert * bank.scale_stride;
7711    let weight = bank.codes.slice(
7712        expert_code_start + block * block_code_stride
7713            ..expert_code_start + (block + 1) * block_code_stride,
7714    );
7715    let scales = bank.scales.slice(
7716        expert_scale_start + block * block_scale_stride
7717            ..expert_scale_start + (block + 1) * block_scale_stride,
7718    );
7719    engine.qmatvec_mmq_fp8_blk_view(
7720        &weight,
7721        &scales,
7722        activations,
7723        1,
7724        FP8_BLOCK,
7725        bank.out_features,
7726    )
7727}
7728
7729fn configure_native_p2p(
7730    ranks: &[Engine],
7731    devices: &[usize],
7732) -> Result<(), Box<dyn std::error::Error>> {
7733    if ranks.len() != devices.len() || ranks.len() < 2 {
7734        return Err("native TP P2P setup requires matching multi-rank devices".into());
7735    }
7736    for (rank, (&device, engine)) in devices.iter().zip(ranks).enumerate() {
7737        if engine.ctx().ordinal() != device {
7738            return Err(format!(
7739                "native TP rank {rank} context device {} != requested device {device}",
7740                engine.ctx().ordinal()
7741            )
7742            .into());
7743        }
7744    }
7745
7746    for src in 0..ranks.len() {
7747        for dst in 0..ranks.len() {
7748            if src == dst {
7749                continue;
7750            }
7751            let mut can_access = 0;
7752            unsafe {
7753                cudarc::driver::sys::cuDeviceCanAccessPeer(
7754                    &mut can_access,
7755                    ranks[src].ctx().cu_device(),
7756                    ranks[dst].ctx().cu_device(),
7757                )
7758                .result()?;
7759            }
7760            if can_access == 0 {
7761                return Err(format!(
7762                    "native TP requires P2P, but dev{} cannot access dev{}",
7763                    devices[src], devices[dst]
7764                )
7765                .into());
7766            }
7767            ranks[src].ctx().bind_to_thread()?;
7768            let rc =
7769                unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(ranks[dst].ctx().cu_ctx(), 0) };
7770            use cudarc::driver::sys::cudaError_enum as E;
7771            if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
7772                return Err(format!(
7773                    "native TP cuCtxEnablePeerAccess(dev{} -> dev{}) failed: {rc:?}",
7774                    devices[src], devices[dst]
7775                )
7776                .into());
7777            }
7778        }
7779    }
7780
7781    for &owner in devices {
7782        for &accessor in devices {
7783            if owner == accessor {
7784                continue;
7785            }
7786            let device = cudarc::driver::result::device::get(owner as i32)?;
7787            let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
7788            unsafe {
7789                cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
7790            }
7791            let desc = cudarc::driver::sys::CUmemAccessDesc {
7792                location: cudarc::driver::sys::CUmemLocation {
7793                    type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
7794                    id: accessor as i32,
7795                },
7796                flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
7797            };
7798            let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
7799            if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
7800                return Err(format!(
7801                    "native TP cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: \
7802                     {rc:?}"
7803                )
7804                .into());
7805            }
7806        }
7807    }
7808
7809    for src in 0..ranks.len() {
7810        for dst in 0..ranks.len() {
7811            if src == dst {
7812                continue;
7813            }
7814            let expected = (0..NATIVE_P2P_PROBE_WORDS)
7815                .map(|index| {
7816                    (index as u32)
7817                        .wrapping_mul(0x9e37_79b9)
7818                        .wrapping_add(((src as u32) << 16) | dst as u32)
7819                })
7820                .collect::<Vec<_>>();
7821            let poison = expected.iter().map(|value| !value).collect::<Vec<_>>();
7822            let source = ranks[src].htod_u32_v(&expected)?;
7823            let mut destination = ranks[dst].htod_u32_v(&poison)?;
7824            ranks[dst].stream().memcpy_dtod(&source, &mut destination)?;
7825            let actual = ranks[dst].dtoh_u32(&destination)?;
7826            if actual != expected {
7827                let mismatches = actual
7828                    .iter()
7829                    .zip(&expected)
7830                    .filter(|(actual, expected)| actual != expected)
7831                    .count();
7832                return Err(format!(
7833                    "native TP peer probe dev{}->dev{} failed: {mismatches}/{} words differ",
7834                    devices[src],
7835                    devices[dst],
7836                    expected.len()
7837                )
7838                .into());
7839            }
7840        }
7841    }
7842    ranks[0].ctx().bind_to_thread()?;
7843    eprintln!(
7844        "[tp] native peer byte-integrity probe PASS: devices={devices:?} \
7845         directions={} bytes={} mismatches=0",
7846        ranks.len() * (ranks.len() - 1),
7847        NATIVE_P2P_PROBE_WORDS * std::mem::size_of::<u32>(),
7848    );
7849    Ok(())
7850}
7851
7852fn validate_activations(
7853    activations: &[f32],
7854    tokens: usize,
7855    in_features: usize,
7856) -> Result<(), String> {
7857    let expected = tokens
7858        .checked_mul(in_features)
7859        .ok_or_else(|| "activation size overflow".to_string())?;
7860    if activations.len() != expected {
7861        return Err(format!(
7862            "activation count {} != {tokens}x{in_features} ({expected})",
7863            activations.len()
7864        ));
7865    }
7866    if !activations.iter().all(|value| value.is_finite()) {
7867        return Err("activations contain a non-finite value".to_string());
7868    }
7869    Ok(())
7870}
7871
7872fn column_shard(
7873    matrix: E4m3BlockMatrix<'_>,
7874    tp: usize,
7875    rank: usize,
7876) -> Result<E4m3BlockMatrix<'_>, String> {
7877    let local_out = matrix.out_features / tp;
7878    let row_start = rank * local_out;
7879    let code_start = row_start * matrix.in_features;
7880    let code_end = code_start + local_out * matrix.in_features;
7881    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
7882    let local_scale_rows = local_out / FP8_BLOCK;
7883    let scale_start = rank * local_scale_rows * scale_cols;
7884    let scale_end = scale_start + local_scale_rows * scale_cols;
7885    Ok(E4m3BlockMatrix {
7886        codes: &matrix.codes[code_start..code_end],
7887        scales: &matrix.scales[scale_start..scale_end],
7888        out_features: local_out,
7889        in_features: matrix.in_features,
7890    })
7891}
7892
7893fn row_shard(
7894    matrix: E4m3BlockMatrix<'_>,
7895    tp: usize,
7896    rank: usize,
7897) -> Result<(Vec<u8>, Vec<f32>), String> {
7898    let local_in = matrix.in_features / tp;
7899    let col_start = rank * local_in;
7900    let mut codes = Vec::with_capacity(matrix.out_features * local_in);
7901    for row in 0..matrix.out_features {
7902        let start = row * matrix.in_features + col_start;
7903        codes.extend_from_slice(&matrix.codes[start..start + local_in]);
7904    }
7905
7906    let scale_rows = matrix.out_features.div_ceil(FP8_BLOCK);
7907    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
7908    let local_scale_cols = local_in / FP8_BLOCK;
7909    let scale_col_start = rank * local_scale_cols;
7910    let mut scales = Vec::with_capacity(scale_rows * local_scale_cols);
7911    for row in 0..scale_rows {
7912        let start = row * scale_cols + scale_col_start;
7913        scales.extend_from_slice(&matrix.scales[start..start + local_scale_cols]);
7914    }
7915    Ok((codes, scales))
7916}
7917
7918fn activation_shard(
7919    activations: &[f32],
7920    tokens: usize,
7921    in_features: usize,
7922    tp: usize,
7923    rank: usize,
7924) -> Vec<f32> {
7925    let local_in = in_features / tp;
7926    let col_start = rank * local_in;
7927    let mut shard = Vec::with_capacity(tokens * local_in);
7928    for token in 0..tokens {
7929        let start = token * in_features + col_start;
7930        shard.extend_from_slice(&activations[start..start + local_in]);
7931    }
7932    shard
7933}
7934
7935// ─── Step NVFP4 expert TP program (official Step-3.7-Flash-NVFP4 checkpoint class) ─────────────
7936//
7937// The routed experts of the NVFP4 checkpoint are modelopt-packed: e2m1 codes (2/byte), per-16
7938// UE4M3 sub-scales, and a per-EXPERT `weight_scale_2` f32 macro (~1e-5..1e-4, LOAD-BEARING).
7939// Rank compute repacks each shard host-side into memra block_nvfp4 rows (nibble reorder only —
7940// value-exact, see nvfp4_repack.rs) and runs the proven `qmatvec_nvfp4_fast` dp4a kernel; the
7941// activation q8_1 quantization uses per-32 blocks, and every shard cut here is 64-aligned, so a
7942// rank-local partial is bit-identical to the corresponding slice of the unsharded kernel.
7943//
7944// MACRO CANONICAL ORDER: the macro multiplies each assembled f32 output exactly ONCE — after the
7945// column gather (gate/up) and after the FULL row-parallel reduce (down), never per-partial.
7946// `(a + b) * m` and `a * m + b * m` differ in f32, so applying it per-rank would break the
7947// TP1-vs-TP2 bit gate. Every entry point below follows this order.
7948//
7949// TP2 shard legality is NVFP4-native: column parallelism splits whole output rows (scale rows
7950// ride along, nothing cuts), row parallelism splits input columns at 64-element superblock
7951// boundaries (16-element scale groups nest inside). The 128-block E4M3 constraint does not apply.
7952
7953/// One expert's modelopt NVFP4 projection: packed codes + per-16 UE4M3 scale bytes + macro.
7954#[derive(Clone, Copy)]
7955pub struct Nvfp4BlockMatrix<'a> {
7956    pub codes: &'a [u8],  // [out_features, in_features/2] packed e2m1, row-major
7957    pub scales: &'a [u8], // [out_features, in_features/16] UE4M3 bytes, row-major
7958    pub macro_scale: f32, // per-expert weight_scale_2 dequant multiplier
7959    pub out_features: usize,
7960    pub in_features: usize,
7961}
7962
7963impl Nvfp4BlockMatrix<'_> {
7964    pub fn validate(&self) -> Result<(), String> {
7965        if self.in_features == 0 || self.out_features == 0 {
7966            return Err("NVFP4 matrix has a zero dimension".to_string());
7967        }
7968        if self.in_features % 64 != 0 {
7969            return Err(format!(
7970                "NVFP4 in_features {} is not 64-aligned (memra block_nvfp4 superblock)",
7971                self.in_features
7972            ));
7973        }
7974        if self.codes.len() != self.out_features * self.in_features / 2 {
7975            return Err(format!(
7976                "NVFP4 code bytes {} != {}x{}/2",
7977                self.codes.len(),
7978                self.out_features,
7979                self.in_features
7980            ));
7981        }
7982        if self.scales.len() != self.out_features * self.in_features / 16 {
7983            return Err(format!(
7984                "NVFP4 scale bytes {} != {}x{}/16",
7985                self.scales.len(),
7986                self.out_features,
7987                self.in_features
7988            ));
7989        }
7990        if !self.macro_scale.is_finite() || self.macro_scale <= 0.0 {
7991            return Err(format!(
7992                "NVFP4 macro scale {} is not finite-positive",
7993                self.macro_scale
7994            ));
7995        }
7996        Ok(())
7997    }
7998}
7999
8000/// Stacked modelopt NVFP4 expert bank (host view over the checkpoint bytes).
8001#[derive(Clone, Copy)]
8002pub struct Nvfp4ExpertBank<'a> {
8003    pub codes: &'a [u8],   // [expert_count, out_features, in_features/2]
8004    pub scales: &'a [u8],  // [expert_count, out_features, in_features/16]
8005    pub macros: &'a [f32], // [expert_count] weight_scale_2
8006    pub expert_count: usize,
8007    pub out_features: usize,
8008    pub in_features: usize,
8009}
8010
8011impl Nvfp4ExpertBank<'_> {
8012    pub fn validate(&self) -> Result<(), String> {
8013        if self.expert_count == 0 {
8014            return Err("NVFP4 expert bank is empty".to_string());
8015        }
8016        if self.macros.len() != self.expert_count {
8017            return Err(format!(
8018                "NVFP4 bank macros {} != expert count {}",
8019                self.macros.len(),
8020                self.expert_count
8021            ));
8022        }
8023        self.expert(0).map(|_| ())
8024    }
8025
8026    pub fn expert(&self, expert: usize) -> Result<Nvfp4BlockMatrix<'_>, String> {
8027        if expert >= self.expert_count {
8028            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
8029        }
8030        let code_stride = self.out_features * self.in_features / 2;
8031        let scale_stride = self.out_features * self.in_features / 16;
8032        if self.codes.len() != self.expert_count * code_stride
8033            || self.scales.len() != self.expert_count * scale_stride
8034        {
8035            return Err("NVFP4 bank byte extents do not match the declared geometry".to_string());
8036        }
8037        let matrix = Nvfp4BlockMatrix {
8038            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
8039            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
8040            macro_scale: self.macros[expert],
8041            out_features: self.out_features,
8042            in_features: self.in_features,
8043        };
8044        matrix.validate()?;
8045        Ok(matrix)
8046    }
8047}
8048
8049/// One rank's resident repacked NVFP4 shard: memra block_nvfp4 rows on device.
8050pub struct ResidentNvfp4Rank {
8051    blocks: crate::CudaSlice<u8>,
8052    macro_scale: f32,
8053    out_features: usize,
8054    in_features: usize,
8055    row_bytes: usize,
8056}
8057
8058pub struct ResidentNvfp4ColumnParallel {
8059    ranks: Vec<ResidentNvfp4Rank>,
8060    pub out_features: usize,
8061    pub in_features: usize,
8062}
8063
8064pub struct ResidentNvfp4RowParallel {
8065    ranks: Vec<ResidentNvfp4Rank>,
8066    pub out_features: usize,
8067    pub in_features: usize,
8068}
8069
8070pub struct ResidentTpNvfp4Expert {
8071    gate: ResidentNvfp4ColumnParallel,
8072    up: ResidentNvfp4ColumnParallel,
8073    down: ResidentNvfp4RowParallel,
8074    pub input_width: usize,
8075    pub expert_width: usize,
8076}
8077
8078/// One rank's resident NVFP4 expert bank shard: one repacked block buffer PER expert (per-expert
8079/// device allocations keep this increment off any new strided-kernel API; the strided twin is a
8080/// later perf rung, mirroring the FP8 bank's history).
8081pub struct ResidentNvfp4ColumnBankRank {
8082    /// Contiguous per-rank expert bank: `expert_count` repacked shards of `expert_bytes` each.
8083    /// Contiguity is what lets the device-routes program cover every selected expert with ONE
8084    /// launch (`qmatvec_nvfp4_dp4a_sel` indexes `sel[t] * expert_bytes`).
8085    bank: crate::CudaSlice<u8>,
8086    expert_bytes: usize,
8087    local_out: usize,
8088    in_features: usize,
8089    row_bytes: usize,
8090}
8091
8092impl ResidentNvfp4ColumnBankRank {
8093    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
8094        self.bank
8095            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
8096    }
8097}
8098
8099/// Canonical row-shard count for the NVFP4 down projection. The down reduction ALWAYS executes
8100/// as exactly this many input-column windows summed in shard order, at every world size: a
8101/// single full-width dot and a two-half-dots-plus-add differ in f32 parenthesization, so pinning
8102/// the shard grid (not the world size) is what makes the TP1-oracle-vs-TP2 bit gate meaningful.
8103/// This is the NVFP4 twin of the FP8 bank's canonical checkpoint-block reduction.
8104pub const NVFP4_CANONICAL_ROW_SHARDS: usize = 2;
8105
8106pub struct ResidentNvfp4RowBankRank {
8107    /// Contiguous per-shard expert bank (see `ResidentNvfp4ColumnBankRank::bank`).
8108    bank: crate::CudaSlice<u8>,
8109    expert_bytes: usize,
8110    device_rank: usize, // index into the runtime's rank engines this canonical shard lives on
8111    out_features: usize,
8112    local_in: usize,
8113    row_bytes: usize,
8114}
8115
8116impl ResidentNvfp4RowBankRank {
8117    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
8118        self.bank
8119            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
8120    }
8121}
8122
8123impl ResidentNvfp4TensorParallel {
8124    pub(crate) fn device_workspace_handle(
8125        &self,
8126    ) -> &std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>> {
8127        &self.device_workspace
8128    }
8129}
8130
8131pub struct ResidentNvfp4TensorParallel {
8132    gate: Vec<ResidentNvfp4ColumnBankRank>,
8133    up: Vec<ResidentNvfp4ColumnBankRank>,
8134    down: Vec<ResidentNvfp4RowBankRank>,
8135    macros_gate: Vec<f32>,
8136    macros_up: Vec<f32>,
8137    macros_down: Vec<f32>,
8138    /// Per-rank device copies of the gate/up macro-scales (E f32 each), indexed by the
8139    /// batched SwiGLU kernel via the selection array. Down macros stay host-side — they fold
8140    /// into the route-weight axpy scalar.
8141    macros_gate_dev: Vec<crate::CudaSlice<f32>>,
8142    macros_up_dev: Vec<crate::CudaSlice<f32>>,
8143    macros_down_dev: Vec<crate::CudaSlice<f32>>,
8144    pub expert_count: usize,
8145    pub input_width: usize,
8146    pub expert_width: usize,
8147    /// Lazily-built persistent decode workspace (device routes program). Interior mutability
8148    /// mirrors StepEpGroupedDecode: the forward holds the bank behind a shared reference.
8149    device_workspace: std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>>,
8150    /// Lazily-built spec-verify t=2 workspace (MEMRA_TCOL_FFN): the two-column routed
8151    /// sweep's slabs and events, kept apart from the serving workspace so the verify walk
8152    /// never perturbs serving state.
8153    t2_workspace: std::sync::Mutex<Option<Nvfp4T2Workspace>>,
8154}
8155
8156/// Persistent buffers for the two-column (spec verify) NVFP4 device-routed program: every
8157/// slab is the t=1 workspace shape doubled along the pair axis, plus per-column
8158/// accumulators. One per expert bank, reused every (round, layer) call.
8159pub struct Nvfp4T2Workspace {
8160    input2: Vec<crate::CudaSlice<f32>>,
8161    in_q2: Vec<crate::CudaSlice<i8>>,
8162    in_d2: Vec<crate::CudaSlice<f32>>,
8163    sel2: Vec<crate::CudaSlice<i32>>,
8164    route_w2: Vec<crate::CudaSlice<f32>>,
8165    gate_out2: Vec<crate::CudaSlice<f32>>,
8166    up_out2: Vec<crate::CudaSlice<f32>>,
8167    act_q2: Vec<crate::CudaSlice<i8>>,
8168    act_d2: Vec<crate::CudaSlice<f32>>,
8169    partial2: Vec<crate::CudaSlice<f32>>,
8170    /// Per-rank per-column combine accumulators ([width] each).
8171    acc_a: Vec<crate::CudaSlice<f32>>,
8172    acc_b: Vec<crate::CudaSlice<f32>>,
8173    /// Root-side pulls of rank1's accumulators and the joined columns.
8174    peer_a: crate::CudaSlice<f32>,
8175    peer_b: crate::CudaSlice<f32>,
8176    omix_a: crate::CudaSlice<f32>,
8177    omix_b: crate::CudaSlice<f32>,
8178    ev_entry: CudaEvent,
8179    ev_rank: Vec<CudaEvent>,
8180    ev_root: CudaEvent,
8181    n_sel: usize,
8182    e_device: usize,
8183}
8184
8185/// Persistent per-call device buffers for the NVFP4 device routes program: one gate/up output,
8186/// one down partial, and one shard accumulator per rank, plus root combine staging. Reused every
8187/// (token, layer) call so the decode loop performs zero output allocations.
8188/// A stitched multi-device parent graph for one layer's device-routed expert program, plus
8189/// the children it was built from (retained: AddChildGraphNode clones, but the probe retains
8190/// conservatively) and the persistent e-context input staging its copies read.
8191struct RoutesGraph {
8192    exec: cudarc::driver::sys::CUgraphExec,
8193    parent: cudarc::driver::sys::CUgraph,
8194    _children: Vec<cudarc::driver::CudaGraph>,
8195}
8196// SAFETY: the raw handles are only used from the single decode thread; CUDA graph handles are
8197// context-agnostic process handles.
8198unsafe impl Send for RoutesGraph {}
8199
8200impl Drop for RoutesGraph {
8201    fn drop(&mut self) {
8202        unsafe {
8203            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
8204            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
8205        }
8206    }
8207}
8208
8209impl Nvfp4DeviceRoutesWorkspace {
8210    pub(crate) fn in_stage_handle(&self) -> Option<&crate::CudaSlice<f32>> {
8211        self.in_stage_e.as_ref()
8212    }
8213    pub(crate) fn in_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
8214        self.in_stage_e.as_mut()
8215    }
8216    pub(crate) fn out_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
8217        self.out_stage_e.as_mut()
8218    }
8219    /// Arm the e-context stages + router staging pair when absent (token-graph entry).
8220    pub(crate) fn arm_stages(
8221        &mut self,
8222        e: &Engine,
8223        width: usize,
8224        n_sel: usize,
8225    ) -> Result<(), Box<dyn std::error::Error>> {
8226        let _main = e.gpu.enter_main()?;
8227        if self.in_stage_e.is_none() {
8228            self.in_stage_e = Some(e.htod(&vec![0.0f32; width])?);
8229            self.out_stage_e = Some(e.htod(&vec![0.0f32; width])?);
8230        }
8231        if self.dev_route_e.is_none() {
8232            self.dev_route_e = Some((
8233                e.htod_i32(&vec![0i32; n_sel])?,
8234                e.htod(&vec![0.0f32; n_sel])?,
8235            ));
8236        }
8237        Ok(())
8238    }
8239
8240    /// Split-borrow: the routes input (shared) + output (mut) stages together.
8241    pub(crate) fn in_and_out_stages_mut(
8242        &mut self,
8243    ) -> Option<(&crate::CudaSlice<f32>, &mut crate::CudaSlice<f32>)> {
8244        match (self.in_stage_e.as_ref(), self.out_stage_e.as_mut()) {
8245            (Some(input), Some(output)) => Some((input, output)),
8246            _ => None,
8247        }
8248    }
8249    pub(crate) fn dev_route_e_mut(
8250        &mut self,
8251    ) -> Option<(&mut crate::CudaSlice<i32>, &mut crate::CudaSlice<f32>)> {
8252        self.dev_route_e.as_mut().map(|(a, b)| (a, b))
8253    }
8254}
8255
8256pub struct Nvfp4DeviceRoutesWorkspace {
8257    /// [n_sel, local_out] batched gate/up outputs and the SwiGLU q8_1 pair; [n_sel, width]
8258    /// down partials. Sized for `n_sel` selected experts per token (pinned at first call).
8259    gate_out: Vec<crate::CudaSlice<f32>>,
8260    up_out: Vec<crate::CudaSlice<f32>>,
8261    act_q: Vec<crate::CudaSlice<i8>>,
8262    act_d: Vec<crate::CudaSlice<f32>>,
8263    sel: Vec<crate::CudaSlice<i32>>,
8264    partial: Vec<crate::CudaSlice<f32>>,
8265    accumulator: Vec<crate::CudaSlice<f32>>,
8266    /// Per-rank folded combine weights (route_weight x down macro), one htod per call.
8267    combine_w: Vec<crate::CudaSlice<f32>>,
8268    /// Device-routed extension: per-rank raw route weights (the down-macro fold happens
8269    /// in-kernel via sel + macros_down_dev).
8270    route_w: Vec<crate::CudaSlice<f32>>,
8271    /// Persistent q8_1 pair of the shared layer input (one quantize per rank per call, no
8272    /// per-call allocation).
8273    in_q: Vec<crate::CudaSlice<i8>>,
8274    in_d: Vec<crate::CudaSlice<f32>>,
8275    /// e-context staging for the device router outputs (persistent — rank streams peer-read
8276    /// them, so the router's fresh outputs are copied here on e's stream first; the pp.rs
8277    /// never-free discipline).
8278    dev_route_e: Option<(crate::CudaSlice<i32>, crate::CudaSlice<f32>)>,
8279    /// Prestage door state: input pull + quantize already issued for this layer's call
8280    /// (nvfp4_routes_prestage), so the routed run skips them. Reset per call.
8281    prestaged: bool,
8282    /// Peer-router door state: rank1's sel/route_w were computed locally in prestage;
8283    /// the routed run skips rank1's sel pull. Reset per call.
8284    rank1_routed: bool,
8285    /// Doorbell fences (MEMRA_FENCE_MEMOPS): raw cuMemAlloc'd [rank1_flag, root_flag]
8286    /// u32 pair in ROOT memory (async-pool memory is memop-INELIGIBLE — receipted
8287    /// CUDA_ERROR_INVALID_VALUE) + the host-side monotonic ticket. 0 = unarmed.
8288    fence_flags_raw: u64,
8289    fence_ticket: u32,
8290    /// Prestage input fence, recorded on e after the input's producer.
8291    ev_input: Option<(CudaEvent, usize)>,
8292    /// Graph-door staging: persistent e-context input row + output row (fixed addresses the
8293    /// captured copies read/write), and the per-layer stitched parent.
8294    in_stage_e: Option<crate::CudaSlice<f32>>,
8295    out_stage_e: Option<crate::CudaSlice<f32>>,
8296    routes_graph: Option<RoutesGraph>,
8297    /// Token-graph raw pointer sets (armed once by routes_arm_raw).
8298    raw_dev_route_e: Option<(u64, u64)>,
8299    raw_combine: Option<(u64, u64, u64, u64)>,
8300    raw_input: Vec<u64>,
8301    raw_sel: Vec<u64>,
8302    raw_route_w: Vec<u64>,
8303    remote: crate::CudaSlice<f32>,
8304    combined: crate::CudaSlice<f32>,
8305    n_sel: usize,
8306    /// Device-IO extension (lazily built by `run_tensor_parallel_routes_nvfp4_device_io`):
8307    /// persistent per-rank input rows plus the evented ordering pair — the pp.rs
8308    /// BoundarySlot discipline, same as the v2 attention workspace.
8309    input: Vec<crate::CudaSlice<f32>>,
8310    ev_rank: Vec<CudaEvent>,
8311    ev_done: Option<CudaEvent>,
8312    ev_entry: Option<(CudaEvent, usize)>,
8313}
8314
8315/// One rank's whole-expert NVFP4 residency (expert-parallel ownership).
8316struct ResidentNvfp4EpRank {
8317    gate: Vec<crate::CudaSlice<u8>>,
8318    up: Vec<crate::CudaSlice<u8>>,
8319    down: Vec<crate::CudaSlice<u8>>,
8320    #[allow(dead_code)]
8321    expert_range: Range<usize>,
8322}
8323
8324pub struct ResidentNvfp4ExpertParallel {
8325    ranks: Vec<ResidentNvfp4EpRank>,
8326    macros_gate: Vec<f32>,
8327    macros_up: Vec<f32>,
8328    macros_down: Vec<f32>,
8329    pub expert_count: usize,
8330    pub input_width: usize,
8331    pub expert_width: usize,
8332    gate_row_bytes: usize,
8333    down_row_bytes: usize,
8334}
8335
8336fn nvfp4_repack_matrix(matrix: Nvfp4BlockMatrix<'_>) -> Vec<u8> {
8337    memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
8338        matrix.codes,
8339        matrix.scales,
8340        matrix.out_features,
8341        matrix.in_features,
8342    )
8343}
8344
8345fn nvfp4_row_bytes(in_features: usize) -> usize {
8346    in_features / 64 * 36 // memra block_nvfp4: 64 elems -> 36 bytes (4 UE4M3 + 32 packed e2m1)
8347}
8348
8349/// MEMRA_NVFP4_BANK_V2=1: store the contiguous expert banks in the slot-major layout the
8350/// coalesced `*_v2` kernels read (see qmatvec.cu). Pure byte permutation — value-exact.
8351/// MEMRA_NO_LOCAL_SHADOW=1: skip the per-layer local-KV shadow gathers and appends in the
8352/// eager v2 decode (lengths still advance) — the graph door proved contents-stale local KV
8353/// is decode-identical (12/12). The local contents feed spec/MTP scratch only.
8354/// MEMRA_FUSE_ROPE_APPEND=1: fuse qk norms + rope + dcw KV append + len inc into one
8355/// launch per rank per layer (bit-identical; identity-gated). dcw path only.
8356pub(crate) fn fuse_rope_append_on() -> bool {
8357    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
8358    *ON.get_or_init(|| std::env::var("MEMRA_FUSE_ROPE_APPEND").as_deref() == Ok("1"))
8359}
8360
8361pub(crate) fn no_local_shadow_on() -> bool {
8362    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
8363    *ON.get_or_init(|| std::env::var("MEMRA_NO_LOCAL_SHADOW").as_deref() == Ok("1"))
8364}
8365
8366pub(crate) fn nvfp4_bank_v2_on() -> bool {
8367    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
8368    *ON.get_or_init(|| std::env::var("MEMRA_NVFP4_BANK_V2").as_deref() == Ok("1"))
8369}
8370
8371/// Permute one repacked block_nvfp4 matrix (out_features rows of `nvfp4_row_bytes(in_f)`)
8372/// into the slot-major v2 row layout: per row, slot g's 16 qs bytes at g*16, then the two
8373/// UE4M3 scale bytes per slot at nslots*16 + g*2. Row byte count unchanged.
8374fn nvfp4_matrix_v2_permute(v1: &[u8], out_features: usize, in_features: usize) -> Vec<u8> {
8375    let row_bytes = nvfp4_row_bytes(in_features);
8376    assert_eq!(v1.len(), out_features * row_bytes, "v2 permute geometry");
8377    let n_slots = in_features / 32;
8378    let mut out = Vec::with_capacity(v1.len());
8379    for row in 0..out_features {
8380        let r = &v1[row * row_bytes..(row + 1) * row_bytes];
8381        for g in 0..n_slots {
8382            let (sblk, h) = (g / 2, g % 2);
8383            let b = &r[sblk * 36..sblk * 36 + 36];
8384            out.extend_from_slice(&b[4 + 16 * h..4 + 16 * h + 16]);
8385        }
8386        for g in 0..n_slots {
8387            let (sblk, h) = (g / 2, g % 2);
8388            let b = &r[sblk * 36..sblk * 36 + 36];
8389            out.push(b[2 * h]);
8390            out.push(b[2 * h + 1]);
8391        }
8392    }
8393    out
8394}
8395
8396/// Repack + (optionally) v2-permute one expert shard for the contiguous banks.
8397fn nvfp4_repack_bank_matrix(matrix: Nvfp4BlockMatrix<'_>) -> Vec<u8> {
8398    let (out_features, in_features) = (matrix.out_features, matrix.in_features);
8399    let v1 = nvfp4_repack_matrix(matrix);
8400    if nvfp4_bank_v2_on() {
8401        nvfp4_matrix_v2_permute(&v1, out_features, in_features)
8402    } else {
8403        v1
8404    }
8405}
8406
8407/// Column shard: whole output rows per rank (codes and scales are row-major, so both slices are
8408/// contiguous borrows). The macro rides unchanged — it is applied post-gather by the caller.
8409fn nvfp4_column_shard<'a>(
8410    matrix: Nvfp4BlockMatrix<'a>,
8411    tp: usize,
8412    rank: usize,
8413) -> Result<Nvfp4BlockMatrix<'a>, String> {
8414    if matrix.out_features % tp != 0 {
8415        return Err(format!(
8416            "NVFP4 column-parallel out_features {} is not divisible by TP={tp}",
8417            matrix.out_features
8418        ));
8419    }
8420    let local_out = matrix.out_features / tp;
8421    let code_row = matrix.in_features / 2;
8422    let scale_row = matrix.in_features / 16;
8423    Ok(Nvfp4BlockMatrix {
8424        codes: &matrix.codes[rank * local_out * code_row..(rank + 1) * local_out * code_row],
8425        scales: &matrix.scales[rank * local_out * scale_row..(rank + 1) * local_out * scale_row],
8426        macro_scale: matrix.macro_scale,
8427        out_features: local_out,
8428        in_features: matrix.in_features,
8429    })
8430}
8431
8432/// Row shard: input-column windows per rank, 64-superblock aligned. Owned buffers: each output
8433/// row contributes one contiguous byte window, gathered across rows.
8434fn nvfp4_row_shard(
8435    matrix: Nvfp4BlockMatrix<'_>,
8436    tp: usize,
8437    rank: usize,
8438) -> Result<(Vec<u8>, Vec<u8>, usize), String> {
8439    if matrix.in_features % tp != 0 {
8440        return Err(format!(
8441            "NVFP4 row-parallel in_features {} is not divisible by TP={tp}",
8442            matrix.in_features
8443        ));
8444    }
8445    let local_in = matrix.in_features / tp;
8446    if local_in % 64 != 0 {
8447        return Err(format!(
8448            "NVFP4 row-parallel input shard {local_in} cuts through a 64-element superblock"
8449        ));
8450    }
8451    let code_row = matrix.in_features / 2;
8452    let scale_row = matrix.in_features / 16;
8453    let local_code = local_in / 2;
8454    let local_scale = local_in / 16;
8455    let mut codes = Vec::with_capacity(matrix.out_features * local_code);
8456    let mut scales = Vec::with_capacity(matrix.out_features * local_scale);
8457    for row in 0..matrix.out_features {
8458        let code_start = row * code_row + rank * local_code;
8459        codes.extend_from_slice(&matrix.codes[code_start..code_start + local_code]);
8460        let scale_start = row * scale_row + rank * local_scale;
8461        scales.extend_from_slice(&matrix.scales[scale_start..scale_start + local_scale]);
8462    }
8463    Ok((codes, scales, local_in))
8464}
8465
8466/// Rank compute leaf: repack modelopt -> block_nvfp4, upload, run the proven dp4a kernel. The
8467/// macro is NOT applied here — callers apply it once at the canonical post-gather/post-reduce
8468/// point (see the section header).
8469fn run_rank_nvfp4(
8470    engine: &Engine,
8471    matrix: Nvfp4BlockMatrix<'_>,
8472    activations: &[f32],
8473    tokens: usize,
8474) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8475    matrix.validate()?;
8476    validate_activations(activations, tokens, matrix.in_features)?;
8477    let _main = engine.gpu.enter_main()?;
8478    let blocks = engine.htod_bytes(&nvfp4_repack_matrix(matrix))?;
8479    let activations = engine.htod(activations)?;
8480    let output = engine.qmatvec_nvfp4_fast(
8481        &blocks.slice(0..blocks.len()),
8482        &activations,
8483        tokens,
8484        matrix.in_features,
8485        matrix.out_features,
8486        nvfp4_row_bytes(matrix.in_features),
8487    )?;
8488    engine.dtoh(&output)
8489}
8490
8491fn upload_rank_nvfp4(
8492    engine: &Engine,
8493    matrix: Nvfp4BlockMatrix<'_>,
8494) -> Result<ResidentNvfp4Rank, Box<dyn std::error::Error>> {
8495    matrix.validate()?;
8496    let _main = engine.gpu.enter_main()?;
8497    Ok(ResidentNvfp4Rank {
8498        blocks: engine.htod_bytes(&nvfp4_repack_matrix(matrix))?,
8499        macro_scale: matrix.macro_scale,
8500        out_features: matrix.out_features,
8501        in_features: matrix.in_features,
8502        row_bytes: nvfp4_row_bytes(matrix.in_features),
8503    })
8504}
8505
8506fn run_resident_rank_nvfp4(
8507    engine: &Engine,
8508    rank: &ResidentNvfp4Rank,
8509    activations: &[f32],
8510    tokens: usize,
8511) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8512    validate_activations(activations, tokens, rank.in_features)?;
8513    let _main = engine.gpu.enter_main()?;
8514    let activations = engine.htod(activations)?;
8515    let output = engine.qmatvec_nvfp4_fast(
8516        &rank.blocks.slice(0..rank.blocks.len()),
8517        &activations,
8518        tokens,
8519        rank.in_features,
8520        rank.out_features,
8521        rank.row_bytes,
8522    )?;
8523    engine.dtoh(&output)
8524}
8525
8526fn apply_macro(values: &mut [f32], macro_scale: f32) {
8527    for value in values.iter_mut() {
8528        *value *= macro_scale;
8529    }
8530}
8531
8532impl TpE4m3HostBounce {
8533    /// Unsharded NVFP4 projection on rank 0 (compatibility oracle). Macro applied post-kernel.
8534    pub fn full_nvfp4(
8535        &self,
8536        matrix: Nvfp4BlockMatrix<'_>,
8537        activations: &[f32],
8538        tokens: usize,
8539    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8540        let mut output = run_rank_nvfp4(&self.ranks[0], matrix, activations, tokens)?;
8541        apply_macro(&mut output, matrix.macro_scale);
8542        Ok(output)
8543    }
8544
8545    /// Column-parallel NVFP4 projection: output rows partition across ranks, host gather in rank
8546    /// order, macro applied ONCE post-gather.
8547    pub fn column_parallel_nvfp4(
8548        &self,
8549        matrix: Nvfp4BlockMatrix<'_>,
8550        activations: &[f32],
8551        tokens: usize,
8552    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
8553        matrix.validate()?;
8554        validate_activations(activations, tokens, matrix.in_features)?;
8555        let tp = self.ranks.len();
8556        let local_out = matrix.out_features / tp;
8557        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
8558        let mut rank_outputs = Vec::with_capacity(tp);
8559        for (rank_index, rank) in self.ranks.iter().enumerate() {
8560            let shard = nvfp4_column_shard(matrix, tp, rank_index)?;
8561            let output = run_rank_nvfp4(rank, shard, activations, tokens)?;
8562            let row_start = rank_index * local_out;
8563            for token in 0..tokens {
8564                gathered[token * matrix.out_features + row_start
8565                    ..token * matrix.out_features + row_start + local_out]
8566                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
8567            }
8568            rank_outputs.push(output);
8569        }
8570        apply_macro(&mut gathered, matrix.macro_scale);
8571        Ok(ColumnParallelResult {
8572            gathered,
8573            rank_outputs,
8574        })
8575    }
8576
8577    /// Row-parallel NVFP4 projection: input columns partition at 64-superblock boundaries,
8578    /// rank-local partials reduce in stable rank order, macro applied ONCE post-reduce.
8579    pub fn row_parallel_nvfp4(
8580        &self,
8581        matrix: Nvfp4BlockMatrix<'_>,
8582        activations: &[f32],
8583        tokens: usize,
8584    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
8585        matrix.validate()?;
8586        validate_activations(activations, tokens, matrix.in_features)?;
8587        let tp = self.ranks.len();
8588        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
8589        let mut rank_partials = Vec::with_capacity(tp);
8590        for (rank_index, rank) in self.ranks.iter().enumerate() {
8591            let (codes, scales, local_in) = nvfp4_row_shard(matrix, tp, rank_index)?;
8592            let local_activations =
8593                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
8594            let shard = Nvfp4BlockMatrix {
8595                codes: &codes,
8596                scales: &scales,
8597                macro_scale: matrix.macro_scale,
8598                out_features: matrix.out_features,
8599                in_features: local_in,
8600            };
8601            let partial = run_rank_nvfp4(rank, shard, &local_activations, tokens)?;
8602            for (sum, value) in reduced.iter_mut().zip(&partial) {
8603                *sum += *value;
8604            }
8605            rank_partials.push(partial);
8606        }
8607        apply_macro(&mut reduced, matrix.macro_scale);
8608        Ok(RowParallelResult {
8609            reduced,
8610            rank_partials,
8611        })
8612    }
8613
8614    pub fn upload_expert_nvfp4(
8615        &self,
8616        gate: Nvfp4BlockMatrix<'_>,
8617        up: Nvfp4BlockMatrix<'_>,
8618        down: Nvfp4BlockMatrix<'_>,
8619    ) -> Result<ResidentTpNvfp4Expert, Box<dyn std::error::Error>> {
8620        if gate.in_features != up.in_features || gate.out_features != up.out_features {
8621            return Err("NVFP4 TP expert gate/up dimensions differ".into());
8622        }
8623        if down.in_features != gate.out_features || down.out_features != gate.in_features {
8624            return Err(format!(
8625                "NVFP4 TP expert down {}x{} does not invert gate/up {}x{}",
8626                down.out_features, down.in_features, gate.out_features, gate.in_features
8627            )
8628            .into());
8629        }
8630        let tp = self.ranks.len();
8631        let mut gate_ranks = Vec::with_capacity(tp);
8632        let mut up_ranks = Vec::with_capacity(tp);
8633        let mut down_ranks = Vec::with_capacity(tp);
8634        for (rank_index, engine) in self.ranks.iter().enumerate() {
8635            gate_ranks.push(upload_rank_nvfp4(
8636                engine,
8637                nvfp4_column_shard(gate, tp, rank_index)?,
8638            )?);
8639            up_ranks.push(upload_rank_nvfp4(
8640                engine,
8641                nvfp4_column_shard(up, tp, rank_index)?,
8642            )?);
8643            let (codes, scales, local_in) = nvfp4_row_shard(down, tp, rank_index)?;
8644            down_ranks.push(upload_rank_nvfp4(
8645                engine,
8646                Nvfp4BlockMatrix {
8647                    codes: &codes,
8648                    scales: &scales,
8649                    macro_scale: down.macro_scale,
8650                    out_features: down.out_features,
8651                    in_features: local_in,
8652                },
8653            )?);
8654        }
8655        Ok(ResidentTpNvfp4Expert {
8656            gate: ResidentNvfp4ColumnParallel {
8657                ranks: gate_ranks,
8658                out_features: gate.out_features,
8659                in_features: gate.in_features,
8660            },
8661            up: ResidentNvfp4ColumnParallel {
8662                ranks: up_ranks,
8663                out_features: up.out_features,
8664                in_features: up.in_features,
8665            },
8666            down: ResidentNvfp4RowParallel {
8667                ranks: down_ranks,
8668                out_features: down.out_features,
8669                in_features: down.in_features,
8670            },
8671            input_width: gate.in_features,
8672            expert_width: gate.out_features,
8673        })
8674    }
8675
8676    fn column_parallel_resident_nvfp4(
8677        &self,
8678        matrix: &ResidentNvfp4ColumnParallel,
8679        activations: &[f32],
8680        tokens: usize,
8681    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8682        validate_activations(activations, tokens, matrix.in_features)?;
8683        let local_out = matrix.out_features / self.ranks.len();
8684        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
8685        let mut macro_scale = None;
8686        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
8687            let output = run_resident_rank_nvfp4(engine, shard, activations, tokens)?;
8688            let row_start = rank_index * local_out;
8689            for token in 0..tokens {
8690                gathered[token * matrix.out_features + row_start
8691                    ..token * matrix.out_features + row_start + local_out]
8692                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
8693            }
8694            macro_scale = Some(shard.macro_scale);
8695        }
8696        apply_macro(
8697            &mut gathered,
8698            macro_scale.ok_or("NVFP4 column-parallel matrix has no ranks")?,
8699        );
8700        Ok(gathered)
8701    }
8702
8703    fn row_parallel_resident_nvfp4(
8704        &self,
8705        matrix: &ResidentNvfp4RowParallel,
8706        activations: &[f32],
8707        tokens: usize,
8708    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8709        validate_activations(activations, tokens, matrix.in_features)?;
8710        let tp = self.ranks.len();
8711        let local_in = matrix.in_features / tp;
8712        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
8713        let mut macro_scale = None;
8714        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
8715            if shard.in_features != local_in {
8716                return Err(format!(
8717                    "NVFP4 resident row shard in_features {} != expected {local_in}",
8718                    shard.in_features
8719                )
8720                .into());
8721            }
8722            let local_activations =
8723                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
8724            let partial = run_resident_rank_nvfp4(engine, shard, &local_activations, tokens)?;
8725            for (sum, value) in reduced.iter_mut().zip(&partial) {
8726                *sum += *value;
8727            }
8728            macro_scale = Some(shard.macro_scale);
8729        }
8730        apply_macro(
8731            &mut reduced,
8732            macro_scale.ok_or("NVFP4 row-parallel matrix has no ranks")?,
8733        );
8734        Ok(reduced)
8735    }
8736
8737    pub fn run_expert_nvfp4(
8738        &self,
8739        expert: &ResidentTpNvfp4Expert,
8740        input: &[f32],
8741        tokens: usize,
8742    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8743        validate_activations(input, tokens, expert.input_width)?;
8744        let gate = self.column_parallel_resident_nvfp4(&expert.gate, input, tokens)?;
8745        let up = self.column_parallel_resident_nvfp4(&expert.up, input, tokens)?;
8746        let activated: Vec<f32> = gate
8747            .iter()
8748            .zip(&up)
8749            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
8750            .collect();
8751        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
8752        self.row_parallel_resident_nvfp4(&expert.down, &activated, tokens)
8753    }
8754
8755    /// Upload every expert's TP shards resident (one repacked block buffer per expert per rank).
8756    pub fn upload_tensor_parallel_nvfp4(
8757        &self,
8758        gate: Nvfp4ExpertBank<'_>,
8759        up: Nvfp4ExpertBank<'_>,
8760        down: Nvfp4ExpertBank<'_>,
8761    ) -> Result<ResidentNvfp4TensorParallel, Box<dyn std::error::Error>> {
8762        gate.validate()?;
8763        up.validate()?;
8764        down.validate()?;
8765        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
8766            return Err("NVFP4 TP gate/up/down expert counts differ".into());
8767        }
8768        if gate.in_features != up.in_features || gate.out_features != up.out_features {
8769            return Err("NVFP4 TP gate/up dimensions differ".into());
8770        }
8771        if down.in_features != gate.out_features || down.out_features != gate.in_features {
8772            return Err(format!(
8773                "NVFP4 TP down {}x{} does not invert gate/up {}x{}",
8774                down.out_features, down.in_features, gate.out_features, gate.in_features
8775            )
8776            .into());
8777        }
8778        let tp = self.ranks.len();
8779        if gate.out_features % tp != 0 {
8780            return Err(format!(
8781                "NVFP4 TP expert output width {} is not divisible by TP={tp}",
8782                gate.out_features
8783            )
8784            .into());
8785        }
8786        if down.in_features % NVFP4_CANONICAL_ROW_SHARDS != 0
8787            || (down.in_features / NVFP4_CANONICAL_ROW_SHARDS) % 64 != 0
8788        {
8789            return Err(format!(
8790                "NVFP4 TP expert input width {} does not split into 64-aligned canonical \
8791                 shards ({NVFP4_CANONICAL_ROW_SHARDS})",
8792                down.in_features
8793            )
8794            .into());
8795        }
8796        if tp > NVFP4_CANONICAL_ROW_SHARDS {
8797            return Err(format!(
8798                "NVFP4 TP world {tp} exceeds the canonical row-shard grid \
8799                 ({NVFP4_CANONICAL_ROW_SHARDS})"
8800            )
8801            .into());
8802        }
8803
8804        let mut gate_ranks = Vec::with_capacity(tp);
8805        let mut up_ranks = Vec::with_capacity(tp);
8806        let mut macros_gate_dev = Vec::with_capacity(tp);
8807        let mut macros_up_dev = Vec::with_capacity(tp);
8808        let mut macros_down_dev = Vec::with_capacity(tp);
8809        for (rank_index, engine) in self.ranks.iter().enumerate() {
8810            let _main = engine.gpu.enter_main()?;
8811            // Contiguous per-rank banks: repack every expert shard into one host buffer, one
8812            // upload. Contiguity feeds the batched selected-experts launch; per-expert bytes
8813            // are unchanged (same repack).
8814            let mut gate_host: Vec<u8> = Vec::new();
8815            let mut up_host: Vec<u8> = Vec::new();
8816            for expert in 0..gate.expert_count {
8817                let gate_shard = nvfp4_column_shard(gate.expert(expert)?, tp, rank_index)?;
8818                gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(gate_shard));
8819                let up_shard = nvfp4_column_shard(up.expert(expert)?, tp, rank_index)?;
8820                up_host.extend_from_slice(&nvfp4_repack_bank_matrix(up_shard));
8821            }
8822            let gate_expert_bytes = gate_host.len() / gate.expert_count;
8823            let up_expert_bytes = up_host.len() / up.expert_count;
8824            gate_ranks.push(ResidentNvfp4ColumnBankRank {
8825                bank: engine.htod_bytes(&gate_host)?,
8826                expert_bytes: gate_expert_bytes,
8827                local_out: gate.out_features / tp,
8828                in_features: gate.in_features,
8829                row_bytes: nvfp4_row_bytes(gate.in_features),
8830            });
8831            up_ranks.push(ResidentNvfp4ColumnBankRank {
8832                bank: engine.htod_bytes(&up_host)?,
8833                expert_bytes: up_expert_bytes,
8834                local_out: up.out_features / tp,
8835                in_features: up.in_features,
8836                row_bytes: nvfp4_row_bytes(up.in_features),
8837            });
8838            macros_gate_dev.push(engine.htod(gate.macros)?);
8839            macros_up_dev.push(engine.htod(up.macros)?);
8840            macros_down_dev.push(engine.htod(down.macros)?);
8841        }
8842        // Down: canonical shard grid, NOT the world size (see NVFP4_CANONICAL_ROW_SHARDS).
8843        // Shard s lives on rank s % world, so TP1 holds both shards and TP2 one each, while the
8844        // execution and reduction order stay identical.
8845        let mut down_ranks = Vec::with_capacity(NVFP4_CANONICAL_ROW_SHARDS);
8846        for shard_index in 0..NVFP4_CANONICAL_ROW_SHARDS {
8847            let device_rank = shard_index % tp;
8848            let engine = &self.ranks[device_rank];
8849            let _main = engine.gpu.enter_main()?;
8850            let mut down_host: Vec<u8> = Vec::new();
8851            for expert in 0..down.expert_count {
8852                let down_matrix = down.expert(expert)?;
8853                let (codes, scales, local_in) =
8854                    nvfp4_row_shard(down_matrix, NVFP4_CANONICAL_ROW_SHARDS, shard_index)?;
8855                down_host.extend_from_slice(&nvfp4_repack_bank_matrix(Nvfp4BlockMatrix {
8856                    codes: &codes,
8857                    scales: &scales,
8858                    macro_scale: down_matrix.macro_scale,
8859                    out_features: down_matrix.out_features,
8860                    in_features: local_in,
8861                }));
8862            }
8863            let down_expert_bytes = down_host.len() / down.expert_count;
8864            down_ranks.push(ResidentNvfp4RowBankRank {
8865                bank: engine.htod_bytes(&down_host)?,
8866                expert_bytes: down_expert_bytes,
8867                device_rank,
8868                out_features: down.out_features,
8869                local_in: down.in_features / NVFP4_CANONICAL_ROW_SHARDS,
8870                row_bytes: nvfp4_row_bytes(down.in_features / NVFP4_CANONICAL_ROW_SHARDS),
8871            });
8872        }
8873        Ok(ResidentNvfp4TensorParallel {
8874            gate: gate_ranks,
8875            up: up_ranks,
8876            down: down_ranks,
8877            macros_gate: gate.macros.to_vec(),
8878            macros_up: up.macros.to_vec(),
8879            macros_down: down.macros.to_vec(),
8880            macros_gate_dev,
8881            macros_up_dev,
8882            macros_down_dev,
8883            expert_count: gate.expert_count,
8884            input_width: gate.in_features,
8885            expert_width: gate.out_features,
8886            device_workspace: std::sync::Mutex::new(None),
8887            t2_workspace: std::sync::Mutex::new(None),
8888        })
8889    }
8890
8891    fn run_column_bank_expert_nvfp4(
8892        &self,
8893        ranks: &[ResidentNvfp4ColumnBankRank],
8894        macros: &[f32],
8895        expert: usize,
8896        input: &[f32],
8897    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8898        let local_out = ranks
8899            .first()
8900            .ok_or("NVFP4 TP column bank has no ranks")?
8901            .local_out;
8902        let mut gathered = vec![0.0f32; local_out * ranks.len()];
8903        for (rank_index, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
8904            let _main = engine.gpu.enter_main()?;
8905            let activations = engine.htod(input)?;
8906            let output = if nvfp4_bank_v2_on() {
8907                engine.qmatvec_nvfp4_fast_v2(
8908                    &bank.expert(expert),
8909                    &activations,
8910                    1,
8911                    bank.in_features,
8912                    bank.local_out,
8913                    bank.row_bytes,
8914                )?
8915            } else {
8916                engine.qmatvec_nvfp4_fast(
8917                    &bank.expert(expert),
8918                    &activations,
8919                    1,
8920                    bank.in_features,
8921                    bank.local_out,
8922                    bank.row_bytes,
8923                )?
8924            };
8925            let output = engine.dtoh(&output)?;
8926            gathered[rank_index * local_out..(rank_index + 1) * local_out].copy_from_slice(&output);
8927        }
8928        apply_macro(&mut gathered, macros[expert]);
8929        Ok(gathered)
8930    }
8931
8932    /// Canonical-shard row reduction: iterate the FIXED shard grid in shard order (each shard
8933    /// executes on its owning rank engine), so the reduction parenthesization is identical at
8934    /// every world size — that identity is what the TP1-oracle-vs-TP2 bit gate proves.
8935    fn run_row_bank_expert_nvfp4(
8936        &self,
8937        shards: &[ResidentNvfp4RowBankRank],
8938        macros: &[f32],
8939        expert: usize,
8940        input: &[f32],
8941    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8942        let out_features = shards
8943            .first()
8944            .ok_or("NVFP4 TP row bank has no canonical shards")?
8945            .out_features;
8946        let in_features = shards.iter().map(|shard| shard.local_in).sum::<usize>();
8947        let mut reduced = vec![0.0f32; out_features];
8948        for (shard_index, shard) in shards.iter().enumerate() {
8949            let engine = self
8950                .ranks
8951                .get(shard.device_rank)
8952                .ok_or("NVFP4 canonical shard names a rank outside this runtime")?;
8953            let _main = engine.gpu.enter_main()?;
8954            let local_activations =
8955                activation_shard(input, 1, in_features, shards.len(), shard_index);
8956            let activations = engine.htod(&local_activations)?;
8957            let output = if nvfp4_bank_v2_on() {
8958                engine.qmatvec_nvfp4_fast_v2(
8959                    &shard.expert(expert),
8960                    &activations,
8961                    1,
8962                    shard.local_in,
8963                    shard.out_features,
8964                    shard.row_bytes,
8965                )?
8966            } else {
8967                engine.qmatvec_nvfp4_fast(
8968                    &shard.expert(expert),
8969                    &activations,
8970                    1,
8971                    shard.local_in,
8972                    shard.out_features,
8973                    shard.row_bytes,
8974                )?
8975            };
8976            let partial = engine.dtoh(&output)?;
8977            for (sum, value) in reduced.iter_mut().zip(&partial) {
8978                *sum += *value;
8979            }
8980        }
8981        apply_macro(&mut reduced, macros[expert]);
8982        Ok(reduced)
8983    }
8984
8985    /// Upload whole experts per owning rank (NVFP4 expert-parallel: the layout the clamped tail
8986    /// layers require — clamp semantics do not distribute across a tensor shard). Each owned
8987    /// expert keeps its full gate/up/down as one repacked block buffer on its owner.
8988    pub fn upload_expert_parallel_nvfp4(
8989        &self,
8990        gate: Nvfp4ExpertBank<'_>,
8991        up: Nvfp4ExpertBank<'_>,
8992        down: Nvfp4ExpertBank<'_>,
8993    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
8994        gate.validate()?;
8995        up.validate()?;
8996        down.validate()?;
8997        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
8998            return Err("NVFP4 EP gate/up/down expert counts differ".into());
8999        }
9000        if gate.in_features != up.in_features || gate.out_features != up.out_features {
9001            return Err("NVFP4 EP gate/up dimensions differ".into());
9002        }
9003        if down.in_features != gate.out_features || down.out_features != gate.in_features {
9004            return Err(format!(
9005                "NVFP4 EP down {}x{} does not invert gate/up {}x{}",
9006                down.out_features, down.in_features, gate.out_features, gate.in_features
9007            )
9008            .into());
9009        }
9010        let world = self.ranks.len();
9011        if gate.expert_count % world != 0 {
9012            return Err(format!(
9013                "NVFP4 EP expert count {} is not divisible by {world} ranks",
9014                gate.expert_count
9015            )
9016            .into());
9017        }
9018        let experts_per_rank = gate.expert_count / world;
9019        let mut ranks = Vec::with_capacity(world);
9020        for (rank_index, engine) in self.ranks.iter().enumerate() {
9021            let _main = engine.gpu.enter_main()?;
9022            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
9023            let mut gate_experts = Vec::with_capacity(experts_per_rank);
9024            let mut up_experts = Vec::with_capacity(experts_per_rank);
9025            let mut down_experts = Vec::with_capacity(experts_per_rank);
9026            for expert in expert_range.clone() {
9027                gate_experts.push(engine.htod_bytes(&nvfp4_repack_matrix(gate.expert(expert)?))?);
9028                up_experts.push(engine.htod_bytes(&nvfp4_repack_matrix(up.expert(expert)?))?);
9029                down_experts.push(engine.htod_bytes(&nvfp4_repack_matrix(down.expert(expert)?))?);
9030            }
9031            ranks.push(ResidentNvfp4EpRank {
9032                gate: gate_experts,
9033                up: up_experts,
9034                down: down_experts,
9035                expert_range,
9036            });
9037        }
9038        Ok(ResidentNvfp4ExpertParallel {
9039            ranks,
9040            macros_gate: gate.macros.to_vec(),
9041            macros_up: up.macros.to_vec(),
9042            macros_down: down.macros.to_vec(),
9043            expert_count: gate.expert_count,
9044            input_width: gate.in_features,
9045            expert_width: gate.out_features,
9046            gate_row_bytes: nvfp4_row_bytes(gate.in_features),
9047            down_row_bytes: nvfp4_row_bytes(down.in_features),
9048        })
9049    }
9050
9051    /// Routed NVFP4 expert-parallel program, host-canonical: every selected expert executes WHOLE
9052    /// on its owning rank (gate -> up -> clamped-or-plain SwiGLU on host -> down), each projection
9053    /// macro applied once post-kernel, route-weighted accumulate on the host in slot order. The
9054    /// activation uses `step_expert_activation_host`, so the clamped tail layers keep the official
9055    /// contract. Exactness-first; no throughput claim.
9056    #[allow(clippy::too_many_arguments)]
9057    pub fn run_routed_experts_nvfp4(
9058        &self,
9059        experts: &ResidentNvfp4ExpertParallel,
9060        input: &[f32],
9061        tokens: usize,
9062        selected: &[usize],
9063        route_weights: &[f32],
9064        experts_per_token: usize,
9065        activation_limit: Option<f32>,
9066    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9067        validate_activations(input, tokens, experts.input_width)?;
9068        let pairs = tokens
9069            .checked_mul(experts_per_token)
9070            .ok_or("NVFP4 EP route count overflow")?;
9071        if selected.len() != pairs || route_weights.len() != pairs {
9072            return Err(format!(
9073                "NVFP4 EP routes selected={} weights={} != tokens {tokens} x experts/token \
9074                 {experts_per_token} ({pairs})",
9075                selected.len(),
9076                route_weights.len(),
9077            )
9078            .into());
9079        }
9080        if !route_weights.iter().all(|weight| weight.is_finite()) {
9081            return Err("NVFP4 EP route weights contain a non-finite value".into());
9082        }
9083        let experts_per_rank = experts.expert_count / experts.ranks.len();
9084        let mut output = vec![0.0f32; tokens * experts.input_width];
9085        for token in 0..tokens {
9086            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
9087            for slot in 0..experts_per_token {
9088                let pair = token * experts_per_token + slot;
9089                let expert = selected[pair];
9090                if expert >= experts.expert_count {
9091                    return Err(format!(
9092                        "NVFP4 EP selected expert {expert} outside 0..{}",
9093                        experts.expert_count
9094                    )
9095                    .into());
9096                }
9097                let owner = expert / experts_per_rank;
9098                let local = expert - owner * experts_per_rank;
9099                let rank = &experts.ranks[owner];
9100                let engine = &self.ranks[owner];
9101                let _main = engine.gpu.enter_main()?;
9102                let device_input = engine.htod(input_row)?;
9103                let gate_out = engine.qmatvec_nvfp4_fast(
9104                    &rank.gate[local].slice(0..rank.gate[local].len()),
9105                    &device_input,
9106                    1,
9107                    experts.input_width,
9108                    experts.expert_width,
9109                    experts.gate_row_bytes,
9110                )?;
9111                let up_out = engine.qmatvec_nvfp4_fast(
9112                    &rank.up[local].slice(0..rank.up[local].len()),
9113                    &device_input,
9114                    1,
9115                    experts.input_width,
9116                    experts.expert_width,
9117                    experts.gate_row_bytes,
9118                )?;
9119                let mut gate_host = engine.dtoh(&gate_out)?;
9120                let mut up_host = engine.dtoh(&up_out)?;
9121                apply_macro(&mut gate_host, experts.macros_gate[expert]);
9122                apply_macro(&mut up_host, experts.macros_up[expert]);
9123                let activated: Vec<f32> = gate_host
9124                    .iter()
9125                    .zip(&up_host)
9126                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
9127                    .collect();
9128                let device_activated = engine.htod(&activated)?;
9129                let down_out = engine.qmatvec_nvfp4_fast(
9130                    &rank.down[local].slice(0..rank.down[local].len()),
9131                    &device_activated,
9132                    1,
9133                    experts.expert_width,
9134                    experts.input_width,
9135                    experts.down_row_bytes,
9136                )?;
9137                let mut down_host = engine.dtoh(&down_out)?;
9138                apply_macro(&mut down_host, experts.macros_down[expert]);
9139                let weight = route_weights[pair];
9140                for (sum, value) in output
9141                    [token * experts.input_width..(token + 1) * experts.input_width]
9142                    .iter_mut()
9143                    .zip(down_host)
9144                {
9145                    *sum += weight * value;
9146                }
9147            }
9148        }
9149        Ok(output)
9150    }
9151
9152    /// Device-resident routed NVFP4 expert program (decode shape, t=1 rows). The geometry gift
9153    /// this exploits: gate/up column halves land on the SAME rank that owns the matching down
9154    /// canonical shard (act[rank r] is exactly down-shard r's input-column window), so the whole
9155    /// expert interior — gate, up, macro-scaled SwiGLU, down partial, route-weighted accumulate —
9156    /// runs rank-local with ZERO cross-rank transfer. Per (token, layer): one input upload per
9157    /// rank, one fenced peer copy of the remote accumulator, one root add, one readback.
9158    ///
9159    /// Numeric class: device silu (silu_mul_scaled) with gate/up macros folded as gs/us and the
9160    /// down macro folded into the accumulate scalar (weight * macro_down — exact, both are
9161    /// per-expert constants). This matches the owning-stage MoE dev-path semantics, NOT the
9162    /// host-canonical program bit-for-bit; gate it with argmax + relative bounds against the
9163    /// host-canonical oracle, and with repeat determinism against itself.
9164    /// Clamped layers refuse (they stay on the EP program).
9165    pub fn run_tensor_parallel_routes_nvfp4_device(
9166        &self,
9167        experts: &ResidentNvfp4TensorParallel,
9168        input: &[f32],
9169        selected: &[usize],
9170        route_weights: &[f32],
9171        experts_per_token: usize,
9172        activation_limit: Option<f32>,
9173    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9174        validate_activations(input, 1, experts.input_width)?;
9175        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
9176            return Err(format!(
9177                "NVFP4 device routes selected={} weights={} != experts/token {experts_per_token}",
9178                selected.len(),
9179                route_weights.len(),
9180            )
9181            .into());
9182        }
9183        if !route_weights.iter().all(|weight| weight.is_finite()) {
9184            return Err("NVFP4 device route weights contain a non-finite value".into());
9185        }
9186        let world = self.ranks.len();
9187        if world != NVFP4_CANONICAL_ROW_SHARDS {
9188            return Err(format!(
9189                "NVFP4 device routes require world == canonical shard grid \
9190                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
9191            )
9192            .into());
9193        }
9194        let local_out = experts.expert_width / world;
9195
9196        // MEMRA_STEP_TP_TIMING=1: cumulative wall-clock of this program, printed every 430 calls
9197        // (~one 43-layer decode step's worth) so a bench run decomposes expert-program time vs
9198        // everything else without Nsight.
9199        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
9200        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
9201        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
9202        let started = timing.then(std::time::Instant::now);
9203
9204        let n_sel = experts_per_token;
9205        let mut workspace_guard = experts
9206            .device_workspace
9207            .lock()
9208            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
9209        if workspace_guard.is_none() {
9210            let mut gate_out = Vec::with_capacity(world);
9211            let mut up_out = Vec::with_capacity(world);
9212            let mut act_q = Vec::with_capacity(world);
9213            let mut act_d = Vec::with_capacity(world);
9214            let mut sel = Vec::with_capacity(world);
9215            let mut partial = Vec::with_capacity(world);
9216            let mut accumulator = Vec::with_capacity(world);
9217            let mut combine_w = Vec::with_capacity(world);
9218            let mut route_w = Vec::with_capacity(world);
9219            let mut in_q = Vec::with_capacity(world);
9220            let mut in_d = Vec::with_capacity(world);
9221            let mut input = Vec::with_capacity(world);
9222            let mut ev_rank = Vec::with_capacity(world);
9223            let moe_direct = moe_direct_on();
9224            for (rank, engine) in self.ranks.iter().enumerate() {
9225                let _main = engine.gpu.enter_main()?;
9226                gate_out.push(engine.uninit(n_sel * local_out)?);
9227                up_out.push(engine.uninit(n_sel * local_out)?);
9228                act_q.push(engine.uninit_i8(n_sel * local_out)?);
9229                act_d.push(engine.uninit(n_sel * local_out / 32)?);
9230                sel.push(engine.htod_i32(&vec![0i32; n_sel])?);
9231                partial.push(engine.uninit(n_sel * experts.input_width)?);
9232                // Direct join: peer accumulators live on ROOT (single P2P store pass).
9233                if moe_direct && rank != 0 {
9234                    let root = &self.ranks[0];
9235                    let _root_main = root.gpu.enter_main()?;
9236                    accumulator.push(root.zeros(experts.input_width)?);
9237                } else {
9238                    accumulator.push(engine.zeros(experts.input_width)?);
9239                }
9240                combine_w.push(engine.htod(&vec![0.0f32; n_sel])?);
9241                route_w.push(engine.htod(&vec![0.0f32; n_sel])?);
9242                in_q.push(engine.uninit_i8(experts.input_width)?);
9243                in_d.push(engine.uninit(experts.input_width / 32)?);
9244                input.push(engine.uninit(experts.input_width)?);
9245                ev_rank.push(engine.ctx().new_event(None)?);
9246            }
9247            let root = &self.ranks[0];
9248            let _main = root.gpu.enter_main()?;
9249            *workspace_guard = Some(Nvfp4DeviceRoutesWorkspace {
9250                prestaged: false,
9251                rank1_routed: false,
9252                ev_input: None,
9253                fence_flags_raw: 0,
9254                fence_ticket: 0,
9255                gate_out,
9256                up_out,
9257                act_q,
9258                act_d,
9259                sel,
9260                partial,
9261                accumulator,
9262                combine_w,
9263                route_w,
9264                in_q,
9265                in_d,
9266                dev_route_e: None,
9267                in_stage_e: None,
9268                out_stage_e: None,
9269                routes_graph: None,
9270                raw_dev_route_e: None,
9271                raw_combine: None,
9272                raw_input: Vec::new(),
9273                raw_sel: Vec::new(),
9274                raw_route_w: Vec::new(),
9275                remote: root.uninit(experts.input_width)?,
9276                combined: root.uninit(experts.input_width)?,
9277                n_sel,
9278                input,
9279                ev_rank,
9280                ev_done: Some(root.ctx().new_event(None)?),
9281                ev_entry: None,
9282            });
9283        }
9284        let workspace = workspace_guard
9285            .as_mut()
9286            .expect("NVFP4 device routes workspace initialized above");
9287        if workspace.n_sel != n_sel {
9288            return Err(format!(
9289                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
9290                workspace.n_sel
9291            )
9292            .into());
9293        }
9294        for &expert in selected {
9295            if expert >= experts.expert_count {
9296                return Err(format!(
9297                    "NVFP4 device selected expert {expert} outside 0..{}",
9298                    experts.expert_count
9299                )
9300                .into());
9301            }
9302        }
9303        let sel_i32 = selected
9304            .iter()
9305            .map(|&expert| expert as i32)
9306            .collect::<Vec<_>>();
9307
9308        // BATCHED program (2026-08-20): per rank, ONE launch per sweep (gate, up, SwiGLU,
9309        // down) covers every selected expert via the selection array and the contiguous bank —
9310        // the per-expert launch loop was pure host latency (~100 sequential launches/layer,
9311        // 291us wall for ~35us of arithmetic). Per (expert, row) the kernels are bit-identical
9312        // to the per-expert forms, and the route-weight axpy chain keeps its exact sequential
9313        // accumulation order — the program's values are unchanged.
9314        for (rank_index, engine) in self.ranks.iter().enumerate() {
9315            let _main = engine.gpu.enter_main()?;
9316            let device_input = engine.htod(input)?;
9317            let Nvfp4DeviceRoutesWorkspace { in_q, in_d, .. } = &mut *workspace;
9318            engine.quantize_q8_1_into(
9319                &device_input,
9320                1,
9321                experts.input_width,
9322                &mut in_q[rank_index],
9323                &mut in_d[rank_index],
9324            )?;
9325            // device_input frees on this rank's stream after the quantize — same-stream order.
9326        }
9327        self.nvfp4_routes_batched_sweeps(
9328            experts,
9329            workspace,
9330            selected,
9331            route_weights,
9332            &sel_i32,
9333            local_out,
9334            n_sel,
9335            activation_limit,
9336            false,
9337        )?;
9338
9339        // Combine: fence the remote shard's producer stream, peer-copy its accumulator to root,
9340        // reduce in canonical shard order, read back once.
9341        let root = &self.ranks[0];
9342        for engine in &self.ranks[1..] {
9343            let _main = engine.gpu.enter_main()?;
9344            engine.stream().synchronize()?;
9345        }
9346        let _main = root.gpu.enter_main()?;
9347        root.stream()
9348            .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
9349        root.add(
9350            &workspace.accumulator[0],
9351            &workspace.remote,
9352            &mut workspace.combined,
9353            experts.input_width,
9354        )?;
9355        let output = root.dtoh(&workspace.combined)?;
9356        if let Some(started) = started {
9357            use std::sync::atomic::Ordering;
9358            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
9359                + started.elapsed().as_nanos() as u64;
9360            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
9361            if calls % 430 == 0 {
9362                eprintln!(
9363                    "[nvfp4-dev-routes-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
9364                    ns as f64 / 1.0e6,
9365                    ns as f64 / calls as f64 / 1.0e3,
9366                );
9367            }
9368        }
9369        Ok(output)
9370    }
9371
9372    /// The shared batched sweeps of the device routes program: per rank, upload the selection,
9373    /// reset the accumulator, run the gate/up/SwiGLU/down batched launches, then the
9374    /// route-weight axpy chain in exact sequential per-pair order. Every op queues on the
9375    /// owning rank's stream; callers own input acquisition and the combine.
9376    #[allow(clippy::too_many_arguments)]
9377    fn nvfp4_routes_batched_sweeps(
9378        &self,
9379        experts: &ResidentNvfp4TensorParallel,
9380        workspace: &mut Nvfp4DeviceRoutesWorkspace,
9381        selected: &[usize],
9382        route_weights: &[f32],
9383        sel_i32: &[i32],
9384        local_out: usize,
9385        n_sel: usize,
9386        activation_limit: Option<f32>,
9387        device_routed: bool,
9388    ) -> Result<(), Box<dyn std::error::Error>> {
9389        for rank_index in 0..self.ranks.len() {
9390            self.nvfp4_routes_batched_sweeps_rank(
9391                experts,
9392                workspace,
9393                selected,
9394                route_weights,
9395                sel_i32,
9396                local_out,
9397                n_sel,
9398                activation_limit,
9399                device_routed,
9400                rank_index,
9401            )?;
9402        }
9403        Ok(())
9404    }
9405
9406    /// One rank's sweeps (the per-rank body of `nvfp4_routes_batched_sweeps`) — separated so
9407    /// the graph door can capture each rank's segment on its own stream.
9408    #[allow(clippy::too_many_arguments)]
9409    fn nvfp4_routes_batched_sweeps_rank(
9410        &self,
9411        experts: &ResidentNvfp4TensorParallel,
9412        workspace: &mut Nvfp4DeviceRoutesWorkspace,
9413        selected: &[usize],
9414        route_weights: &[f32],
9415        sel_i32: &[i32],
9416        local_out: usize,
9417        n_sel: usize,
9418        activation_limit: Option<f32>,
9419        device_routed: bool,
9420        rank_index: usize,
9421    ) -> Result<(), Box<dyn std::error::Error>> {
9422        {
9423            let engine = &self.ranks[rank_index];
9424            let _main = engine.gpu.enter_main()?;
9425            if !device_routed {
9426                engine.htod_i32_into(&mut workspace.sel[rank_index], sel_i32)?;
9427                // Folded combine weights (route_weight x down macro) — one 40-byte upload
9428                // replaces the accumulator reset + n_sel sequential axpy launches below.
9429                let folded = (0..n_sel)
9430                    .map(|pair| route_weights[pair] * experts.macros_down[selected[pair]])
9431                    .collect::<Vec<_>>();
9432                let mut view = workspace.combine_w[rank_index].slice_mut(0..n_sel);
9433                engine.stream().memcpy_htod(&folded, &mut view)?;
9434            }
9435            let gate_bank = &experts.gate[rank_index];
9436            let up_bank = &experts.up[rank_index];
9437            let (aq, ad) = (&workspace.in_q[rank_index], &workspace.in_d[rank_index]);
9438            // FUSION #2a (v2 banks): the two sweeps share sel/aq/ad and identical geometry
9439            // — one launch, per-row bit-identical, double the grid fill.
9440            let gu_fused = nvfp4_bank_v2_on()
9441                && gate_bank.in_features == up_bank.in_features
9442                && gate_bank.local_out == up_bank.local_out
9443                && gate_bank.row_bytes == up_bank.row_bytes
9444                && gate_bank.expert_bytes == up_bank.expert_bytes;
9445            if gu_fused {
9446                let Nvfp4DeviceRoutesWorkspace {
9447                    sel,
9448                    gate_out,
9449                    up_out,
9450                    in_q,
9451                    in_d,
9452                    ..
9453                } = &mut *workspace;
9454                engine.qmatvec_nvfp4_sel_gu_into(
9455                    &gate_bank.bank,
9456                    &up_bank.bank,
9457                    &sel[rank_index],
9458                    &in_q[rank_index],
9459                    &in_d[rank_index],
9460                    &mut gate_out[rank_index],
9461                    &mut up_out[rank_index],
9462                    n_sel,
9463                    gate_bank.in_features,
9464                    gate_bank.local_out,
9465                    gate_bank.row_bytes,
9466                    gate_bank.expert_bytes,
9467                )?;
9468            } else {
9469                engine.qmatvec_nvfp4_sel_into(
9470                    &gate_bank.bank,
9471                    &workspace.sel[rank_index],
9472                    aq,
9473                    ad,
9474                    &mut workspace.gate_out[rank_index],
9475                    n_sel,
9476                    gate_bank.in_features,
9477                    gate_bank.local_out,
9478                    gate_bank.row_bytes,
9479                    gate_bank.expert_bytes,
9480                    0,
9481                    0,
9482                )?;
9483                engine.qmatvec_nvfp4_sel_into(
9484                    &up_bank.bank,
9485                    &workspace.sel[rank_index],
9486                    aq,
9487                    ad,
9488                    &mut workspace.up_out[rank_index],
9489                    n_sel,
9490                    up_bank.in_features,
9491                    up_bank.local_out,
9492                    up_bank.row_bytes,
9493                    up_bank.expert_bytes,
9494                    0,
9495                    0,
9496                )?;
9497            }
9498            // Fused macro-scaled SwiGLU that EMITS q8_1 directly — down consumes it with no
9499            // separate quantize launch. act[rank] IS down canonical shard `rank_index`'s
9500            // input-column window (the geometry gift; see the method doc).
9501            {
9502                let Nvfp4DeviceRoutesWorkspace {
9503                    gate_out,
9504                    up_out,
9505                    sel,
9506                    act_q,
9507                    act_d,
9508                    ..
9509                } = &mut *workspace;
9510                engine.silu_mul_scaled_q8_1_sel_into(
9511                    &gate_out[rank_index],
9512                    &up_out[rank_index],
9513                    &experts.macros_gate_dev[rank_index],
9514                    &experts.macros_up_dev[rank_index],
9515                    &sel[rank_index],
9516                    activation_limit,
9517                    &mut act_q[rank_index],
9518                    &mut act_d[rank_index],
9519                    local_out,
9520                    n_sel,
9521                )?;
9522            }
9523            let shard = &experts.down[rank_index];
9524            if shard.device_rank != rank_index || shard.local_in != local_out {
9525                return Err(
9526                    "NVFP4 device routes: down canonical shard placement drifted from \
9527                     the gate/up column split"
9528                        .into(),
9529                );
9530            }
9531            // MEMRA_SEL_DOWN8=1: down sweep + route-weight combine in ONE launch, one warp
9532            // per SLOT instead of one warp per (row, slot) — the q8 `down8 w8` occupancy arm
9533            // (cx-downkernel: waves/SM 0.91 -> 4.36) ported to the NVFP4 banks. Bit-identical
9534            // (same dot program, same reduce tree, same slot-ordered chain), and the
9535            // n_sel x out_f partial buffer round trip disappears. Device-routed only: the
9536            // host-routed arm folds the macro into combine_w instead of reading md on device.
9537            let down8 = device_routed && sel_down8_on() && (shard.local_in >> 5) <= 32;
9538            if down8 {
9539                let Nvfp4DeviceRoutesWorkspace {
9540                    sel,
9541                    act_q,
9542                    act_d,
9543                    route_w,
9544                    accumulator,
9545                    ..
9546                } = &mut *workspace;
9547                engine.qmatvec_nvfp4_sel_down8_into(
9548                    &shard.bank,
9549                    &sel[rank_index],
9550                    &act_q[rank_index],
9551                    &act_d[rank_index],
9552                    &route_w[rank_index],
9553                    &experts.macros_down_dev[rank_index],
9554                    &mut accumulator[rank_index],
9555                    n_sel,
9556                    shard.local_in,
9557                    shard.out_features,
9558                    shard.row_bytes,
9559                    shard.expert_bytes,
9560                    local_out,
9561                    local_out / 32,
9562                )?;
9563            } else {
9564                let Nvfp4DeviceRoutesWorkspace {
9565                    sel,
9566                    act_q,
9567                    act_d,
9568                    partial,
9569                    ..
9570                } = &mut *workspace;
9571                engine.qmatvec_nvfp4_sel_into(
9572                    &shard.bank,
9573                    &sel[rank_index],
9574                    &act_q[rank_index],
9575                    &act_d[rank_index],
9576                    &mut partial[rank_index],
9577                    n_sel,
9578                    shard.local_in,
9579                    shard.out_features,
9580                    shard.row_bytes,
9581                    shard.expert_bytes,
9582                    local_out,
9583                    local_out / 32,
9584                )?;
9585            }
9586            // Route-weight accumulation: axpy_rows_seq keeps the exact sequential per-pair
9587            // FP chain of the reset + n_sel axpy launches in ONE launch. Device-routed calls
9588            // fold the down macro in-kernel from the device selection. (down8 already
9589            // produced the accumulator inside the sweep.)
9590            if !down8 {
9591                let Nvfp4DeviceRoutesWorkspace {
9592                    partial,
9593                    combine_w,
9594                    route_w,
9595                    sel,
9596                    accumulator,
9597                    ..
9598                } = &mut *workspace;
9599                if device_routed {
9600                    engine.axpy_rows_seq_md_into(
9601                        &partial[rank_index],
9602                        &route_w[rank_index],
9603                        &experts.macros_down_dev[rank_index],
9604                        &sel[rank_index],
9605                        &mut accumulator[rank_index],
9606                        experts.input_width,
9607                        n_sel,
9608                    )?;
9609                } else {
9610                    engine.axpy_rows_seq_into(
9611                        &partial[rank_index],
9612                        &combine_w[rank_index],
9613                        &mut accumulator[rank_index],
9614                        experts.input_width,
9615                        n_sel,
9616                    )?;
9617                }
9618            }
9619        }
9620        Ok(())
9621    }
9622
9623    /// Device-IO twin of `run_tensor_parallel_routes_nvfp4_device`: the layer input arrives as
9624    /// a device row on the model engine `e` and the combined output returns as a fresh
9625    /// `e`-context row — no host round-trip, no host stream sync. Ordering is evented (the v2
9626    /// attention discipline): `ev_entry` is recorded on `e`'s stream AFTER the caller queued
9627    /// the input's producer; each rank waits it before its peer read; the root reduce waits
9628    /// every rank's done event; `e` waits the root's done event before copying out. The
9629    /// program bytes are identical to the host-IO twin — dtoh/htod and dtod preserve f32 bits.
9630    pub fn run_tensor_parallel_routes_nvfp4_device_io(
9631        &self,
9632        experts: &ResidentNvfp4TensorParallel,
9633        e: &Engine,
9634        input_dev: &crate::CudaSlice<f32>,
9635        selected: &[usize],
9636        route_weights: &[f32],
9637        experts_per_token: usize,
9638        activation_limit: Option<f32>,
9639    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
9640        if input_dev.len() != experts.input_width {
9641            return Err(format!(
9642                "NVFP4 device-io routes input {} != width {}",
9643                input_dev.len(),
9644                experts.input_width
9645            )
9646            .into());
9647        }
9648        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
9649            return Err(format!(
9650                "NVFP4 device-io routes selected={} weights={} != experts/token {experts_per_token}",
9651                selected.len(),
9652                route_weights.len(),
9653            )
9654            .into());
9655        }
9656        if !route_weights.iter().all(|weight| weight.is_finite()) {
9657            return Err("NVFP4 device route weights contain a non-finite value".into());
9658        }
9659        let world = self.ranks.len();
9660        if world != NVFP4_CANONICAL_ROW_SHARDS {
9661            return Err(format!(
9662                "NVFP4 device routes require world == canonical shard grid \
9663                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
9664            )
9665            .into());
9666        }
9667        let local_out = experts.expert_width / world;
9668        let n_sel = experts_per_token;
9669
9670        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
9671        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
9672        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
9673        let started = timing.then(std::time::Instant::now);
9674
9675        let mut workspace_guard = experts
9676            .device_workspace
9677            .lock()
9678            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
9679        if workspace_guard.is_none() {
9680            drop(workspace_guard);
9681            // Build through the host-IO ensure path exactly once: run it with a zero input.
9682            // Cheaper than duplicating the init; the first real call overwrites everything.
9683            let zero = vec![0.0f32; experts.input_width];
9684            let zero_sel = vec![0usize; n_sel];
9685            let zero_w = vec![0.0f32; n_sel];
9686            let _ = self.run_tensor_parallel_routes_nvfp4_device(
9687                experts,
9688                &zero,
9689                &zero_sel,
9690                &zero_w,
9691                n_sel,
9692                activation_limit,
9693            )?;
9694            workspace_guard = experts
9695                .device_workspace
9696                .lock()
9697                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
9698        }
9699        let workspace = workspace_guard
9700            .as_mut()
9701            .expect("NVFP4 device routes workspace initialized above");
9702        if workspace.n_sel != n_sel {
9703            return Err(format!(
9704                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
9705                workspace.n_sel
9706            )
9707            .into());
9708        }
9709        for &expert in selected {
9710            if expert >= experts.expert_count {
9711                return Err(format!(
9712                    "NVFP4 device selected expert {expert} outside 0..{}",
9713                    experts.expert_count
9714                )
9715                .into());
9716            }
9717        }
9718        let sel_i32 = selected
9719            .iter()
9720            .map(|&expert| expert as i32)
9721            .collect::<Vec<_>>();
9722
9723        // Entry fence: e's stream position covers the input's producer AND every consumer of
9724        // the previous layer's output (queued on e's stream before this call), guarding the
9725        // workspace reuse exactly like the v2 attention driver.
9726        if let Some((_, device)) = workspace.ev_entry.as_ref() {
9727            if *device != e.ctx().ordinal() {
9728                return Err("NVFP4 device-io routes engine changed".into());
9729            }
9730        } else {
9731            let _main = e.gpu.enter_main()?;
9732            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
9733        }
9734        {
9735            let _main = e.gpu.enter_main()?;
9736            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
9737            ev_entry.record(&e.stream())?;
9738        }
9739        for (rank_index, engine) in self.ranks.iter().enumerate() {
9740            let _main = engine.gpu.enter_main()?;
9741            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
9742            engine.stream().wait(ev_entry)?;
9743            {
9744                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
9745                engine
9746                    .stream()
9747                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
9748            }
9749            {
9750                let Nvfp4DeviceRoutesWorkspace {
9751                    input, in_q, in_d, ..
9752                } = &mut *workspace;
9753                engine.quantize_q8_1_into(
9754                    &input[rank_index],
9755                    1,
9756                    experts.input_width,
9757                    &mut in_q[rank_index],
9758                    &mut in_d[rank_index],
9759                )?;
9760            }
9761        }
9762        self.nvfp4_routes_batched_sweeps(
9763            experts,
9764            workspace,
9765            selected,
9766            route_weights,
9767            &sel_i32,
9768            local_out,
9769            n_sel,
9770            activation_limit,
9771            false,
9772        )?;
9773
9774        // Evented combine: rank done events replace the host stream syncs, the reduce runs on
9775        // the root stream in canonical shard order, and e copies the combined row out behind
9776        // the root's done event.
9777        // rank0 == root: its own stream order already covers its sweep; only the PEER
9778        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
9779        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
9780            let _main = engine.gpu.enter_main()?;
9781            workspace.ev_rank[rank_index].record(&engine.stream())?;
9782        }
9783        if moe_direct_on() && self.ranks.len() == 2 {
9784            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
9785            // rank0's is root-stream-ordered. One root event + rank1's own event order
9786            // the model engine's single add — same operand order as root's add
9787            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
9788            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
9789            // hazard class does not apply).
9790            {
9791                let root = &self.ranks[0];
9792                let _main = root.gpu.enter_main()?;
9793                workspace
9794                    .ev_done
9795                    .as_ref()
9796                    .expect("device routes done event")
9797                    .record(&root.stream())?;
9798            }
9799            let _main = e.gpu.enter_main()?;
9800            e.stream().wait(
9801                workspace
9802                    .ev_done
9803                    .as_ref()
9804                    .expect("device routes done event"),
9805            )?;
9806            for ev in workspace.ev_rank.iter().skip(1) {
9807                e.stream().wait(ev)?;
9808            }
9809            let mut output = e.uninit(experts.input_width)?;
9810            e.add(
9811                &workspace.accumulator[0],
9812                &workspace.accumulator[1],
9813                &mut output,
9814                experts.input_width,
9815            )?;
9816            let output = output;
9817            if let Some(started) = started {
9818                use std::sync::atomic::Ordering;
9819                let ns = TIMING_NS
9820                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
9821                    + started.elapsed().as_nanos() as u64;
9822                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
9823                if calls % 430 == 0 {
9824                    eprintln!(
9825                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
9826                        ns as f64 / 1.0e6,
9827                        ns as f64 / calls as f64 / 1.0e3,
9828                    );
9829                }
9830            }
9831            return Ok(output);
9832        }
9833        {
9834            let root = &self.ranks[0];
9835            let _main = root.gpu.enter_main()?;
9836            for ev in workspace.ev_rank.iter().skip(1) {
9837                root.stream().wait(ev)?;
9838            }
9839            root.stream()
9840                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
9841            {
9842                let Nvfp4DeviceRoutesWorkspace {
9843                    accumulator,
9844                    remote,
9845                    combined,
9846                    ..
9847                } = &mut *workspace;
9848                root.add(&accumulator[0], remote, combined, experts.input_width)?;
9849            }
9850            workspace
9851                .ev_done
9852                .as_ref()
9853                .expect("device routes done event")
9854                .record(&root.stream())?;
9855        }
9856        let output = {
9857            let _main = e.gpu.enter_main()?;
9858            e.stream().wait(
9859                workspace
9860                    .ev_done
9861                    .as_ref()
9862                    .expect("device routes done event"),
9863            )?;
9864            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
9865            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
9866            let mut output = e.uninit(experts.input_width)?;
9867            e.stream().memcpy_dtod(
9868                &workspace.combined.slice(0..experts.input_width),
9869                &mut output.slice_mut(0..experts.input_width),
9870            )?;
9871            output
9872        };
9873        if let Some(started) = started {
9874            use std::sync::atomic::Ordering;
9875            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
9876                + started.elapsed().as_nanos() as u64;
9877            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
9878            if calls % 430 == 0 {
9879                eprintln!(
9880                    "[nvfp4-dev-routes-io-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
9881                    ns as f64 / 1.0e6,
9882                    ns as f64 / calls as f64 / 1.0e3,
9883                );
9884            }
9885        }
9886        Ok(output)
9887    }
9888
9889    /// Device-routed twin of `run_tensor_parallel_routes_nvfp4_device_io`: the selection and
9890    /// route weights arrive as the device router's e-context outputs — the per-layer host
9891    /// logits readback disappears. The fresh router outputs are staged into persistent
9892    /// e-context buffers on e's stream (never-free discipline) before the entry event; each
9893    /// rank peer-reads them behind it. The down-macro fold happens in-kernel.
9894    #[allow(clippy::too_many_arguments)]
9895    /// Prestage the routed-expert input: pull the shared row to every rank and quantize it
9896    /// there, WITHOUT the selection — callable before the router so the rank chains overlap
9897    /// it. No-op (returns false) when the workspace is not built yet or the door is off;
9898    /// the routed run then does its own staging as before.
9899    pub fn nvfp4_routes_prestage(
9900        &self,
9901        experts: &ResidentNvfp4TensorParallel,
9902        e: &Engine,
9903        input_dev: &crate::CudaSlice<f32>,
9904    ) -> Result<bool, Box<dyn std::error::Error>> {
9905        self.nvfp4_routes_prestage_with(experts, e, input_dev, |_, _, _, _| Ok(false))
9906    }
9907
9908    /// `nvfp4_routes_prestage` with a PEER-ROUTER hook: after rank1's input pull +
9909    /// quantize, the hook may compute rank1's route selection LOCALLY (replicated router —
9910    /// deterministic kernels on identical input bits produce identical sel/w, so the
9911    /// selection is bit-equal to the root's). Returns true when it wrote sel/route_w; the
9912    /// routed run then skips rank1's sel pull.
9913    pub fn nvfp4_routes_prestage_with(
9914        &self,
9915        experts: &ResidentNvfp4TensorParallel,
9916        e: &Engine,
9917        input_dev: &crate::CudaSlice<f32>,
9918        rank1_router: impl FnOnce(
9919            &Engine,
9920            &crate::CudaSlice<f32>,
9921            &mut crate::CudaSlice<i32>,
9922            &mut crate::CudaSlice<f32>,
9923        ) -> Result<bool, Box<dyn std::error::Error>>,
9924    ) -> Result<bool, Box<dyn std::error::Error>> {
9925        if !routes_prestage_on() || step_tp_graph_enabled()? {
9926            return Ok(false);
9927        }
9928        if input_dev.len() != experts.input_width {
9929            return Err("NVFP4 prestage input width mismatch".into());
9930        }
9931        let mut workspace_guard = experts
9932            .device_workspace
9933            .lock()
9934            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
9935        let Some(workspace) = workspace_guard.as_mut() else {
9936            return Ok(false);
9937        };
9938        if workspace.ev_input.is_none() {
9939            let _main = e.gpu.enter_main()?;
9940            workspace.ev_input = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
9941        } else if workspace.ev_input.as_ref().map(|(_, d)| *d) != Some(e.ctx().ordinal()) {
9942            return Err("NVFP4 prestage engine changed".into());
9943        }
9944        {
9945            let _main = e.gpu.enter_main()?;
9946            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
9947            ev.record(&e.stream())?;
9948        }
9949        for (rank_index, engine) in self.ranks.iter().enumerate() {
9950            let _main = engine.gpu.enter_main()?;
9951            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
9952            engine.stream().wait(ev)?;
9953            {
9954                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
9955                engine
9956                    .stream()
9957                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
9958            }
9959            {
9960                let Nvfp4DeviceRoutesWorkspace {
9961                    input, in_q, in_d, ..
9962                } = &mut *workspace;
9963                engine.quantize_q8_1_into(
9964                    &input[rank_index],
9965                    1,
9966                    experts.input_width,
9967                    &mut in_q[rank_index],
9968                    &mut in_d[rank_index],
9969                )?;
9970            }
9971        }
9972        if self.ranks.len() == 2 {
9973            let rank1 = &self.ranks[1];
9974            let _r1 = rank1.gpu.enter_main()?;
9975            let Nvfp4DeviceRoutesWorkspace {
9976                input,
9977                sel,
9978                route_w,
9979                ..
9980            } = &mut *workspace;
9981            let (in1, rest_sel) = (&input[1], &mut sel[1]);
9982            if rank1_router(rank1, in1, rest_sel, &mut route_w[1])? {
9983                workspace.rank1_routed = true;
9984            }
9985        }
9986        workspace.prestaged = true;
9987        Ok(true)
9988    }
9989
9990    /// TWO-COLUMN device-routed expert program (spec verify, MEMRA_TCOL_FFN): one gu_tcol
9991    /// sweep over 2*n_sel_col pairs (pair t reads activation row t/n_sel_col — weights the
9992    /// two columns share dedup through L2), the UNCHANGED silu/down kernels at n_sel=16
9993    /// (both already index per pair), and one offset-axpy combine per column (the exact
9994    /// t=1 sequential chain over that column's 8 pairs). No serving doors: no graph, no
9995    /// prestage, no shexp folding — plain evented ordering. Returns [2, input_width] on e.
9996    ///
9997    /// EXACTNESS: every kernel body is the t=1 program per (pair,row) or per element; the
9998    /// per-column combine order equals the t=1 combine; the cross-rank join adds the same
9999    /// operand values elementwise. Gated by the greedy tape like every verify arm.
10000    #[allow(clippy::too_many_arguments)]
10001    pub fn run_tensor_parallel_routes_nvfp4_device_routed_t2(
10002        &self,
10003        experts: &ResidentNvfp4TensorParallel,
10004        e: &Engine,
10005        z2: &crate::CudaSlice<f32>,
10006        sel_d: &crate::CudaSlice<i32>,
10007        w_d: &crate::CudaSlice<f32>,
10008        n_sel_col: usize,
10009        activation_limit: Option<f32>,
10010    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10011        let world = self.ranks.len();
10012        if world != NVFP4_CANONICAL_ROW_SHARDS {
10013            return Err("NVFP4 t2 routes require the canonical 2-shard grid".into());
10014        }
10015        let width = experts.input_width;
10016        let n_sel = 2 * n_sel_col;
10017        if z2.len() < 2 * width || sel_d.len() < n_sel || w_d.len() < n_sel {
10018            return Err("NVFP4 t2 routes geometry".into());
10019        }
10020        if !nvfp4_bank_v2_on() {
10021            return Err("NVFP4 t2 routes require the v2 banks (MEMRA_NVFP4_BANK_V2=1)".into());
10022        }
10023        let local_out = experts.expert_width / world;
10024        let mut guard = experts
10025            .t2_workspace
10026            .lock()
10027            .map_err(|_| "NVFP4 t2 workspace lock is poisoned")?;
10028        if guard.as_ref().is_none_or(|ws| ws.n_sel != n_sel) {
10029            let mut input2 = Vec::new();
10030            let mut in_q2 = Vec::new();
10031            let mut in_d2 = Vec::new();
10032            let mut sel2 = Vec::new();
10033            let mut route_w2 = Vec::new();
10034            let mut gate_out2 = Vec::new();
10035            let mut up_out2 = Vec::new();
10036            let mut act_q2 = Vec::new();
10037            let mut act_d2 = Vec::new();
10038            let mut partial2 = Vec::new();
10039            let mut acc_a = Vec::new();
10040            let mut acc_b = Vec::new();
10041            let mut ev_rank = Vec::new();
10042            for engine in &self.ranks {
10043                let _m = engine.gpu.enter_main()?;
10044                input2.push(engine.uninit(2 * width)?);
10045                in_q2.push(engine.alloc_i8_uninit(2 * width)?);
10046                in_d2.push(engine.uninit(2 * (width / 32))?);
10047                sel2.push(engine.htod_i32(&vec![0i32; n_sel])?);
10048                route_w2.push(engine.uninit(n_sel)?);
10049                gate_out2.push(engine.uninit(n_sel * local_out)?);
10050                up_out2.push(engine.uninit(n_sel * local_out)?);
10051                act_q2.push(engine.alloc_i8_uninit(n_sel * local_out)?);
10052                act_d2.push(engine.uninit(n_sel * (local_out / 32))?);
10053                partial2.push(engine.uninit(n_sel * width)?);
10054                acc_a.push(engine.uninit(width)?);
10055                acc_b.push(engine.uninit(width)?);
10056                ev_rank.push(engine.ctx().new_event(None)?);
10057            }
10058            let root = &self.ranks[0];
10059            let (peer_a, peer_b, omix_a, omix_b, ev_root) = {
10060                let _m = root.gpu.enter_main()?;
10061                (
10062                    root.uninit(width)?,
10063                    root.uninit(width)?,
10064                    root.uninit(width)?,
10065                    root.uninit(width)?,
10066                    root.ctx().new_event(None)?,
10067                )
10068            };
10069            let ev_entry = {
10070                let _m = e.gpu.enter_main()?;
10071                e.ctx().new_event(None)?
10072            };
10073            *guard = Some(Nvfp4T2Workspace {
10074                input2,
10075                in_q2,
10076                in_d2,
10077                sel2,
10078                route_w2,
10079                gate_out2,
10080                up_out2,
10081                act_q2,
10082                act_d2,
10083                partial2,
10084                acc_a,
10085                acc_b,
10086                peer_a,
10087                peer_b,
10088                omix_a,
10089                omix_b,
10090                ev_entry,
10091                ev_rank,
10092                ev_root,
10093                n_sel,
10094                e_device: e.ctx().ordinal(),
10095            });
10096        }
10097        let ws = guard.as_mut().expect("armed above");
10098        if ws.e_device != e.ctx().ordinal() {
10099            return Err("NVFP4 t2 routes engine changed".into());
10100        }
10101        {
10102            let _main = e.gpu.enter_main()?;
10103            ws.ev_entry.record(&e.stream())?;
10104        }
10105        for rank in 0..world {
10106            let engine = &self.ranks[rank];
10107            let _main = engine.gpu.enter_main()?;
10108            engine.stream().wait(&ws.ev_entry)?;
10109            {
10110                let mut dst = ws.input2[rank].slice_mut(0..2 * width);
10111                engine
10112                    .stream()
10113                    .memcpy_dtod(&z2.slice(0..2 * width), &mut dst)?;
10114            }
10115            {
10116                let mut dst = ws.sel2[rank].slice_mut(0..n_sel);
10117                engine
10118                    .stream()
10119                    .memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
10120            }
10121            {
10122                let mut dst = ws.route_w2[rank].slice_mut(0..n_sel);
10123                engine
10124                    .stream()
10125                    .memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
10126            }
10127            {
10128                let Nvfp4T2Workspace {
10129                    input2,
10130                    in_q2,
10131                    in_d2,
10132                    ..
10133                } = &mut *ws;
10134                engine.quantize_q8_1_into(
10135                    &input2[rank],
10136                    2,
10137                    width,
10138                    &mut in_q2[rank],
10139                    &mut in_d2[rank],
10140                )?;
10141            }
10142            let gate_bank = &experts.gate[rank];
10143            let up_bank = &experts.up[rank];
10144            if gate_bank.in_features != up_bank.in_features
10145                || gate_bank.local_out != up_bank.local_out
10146                || gate_bank.row_bytes != up_bank.row_bytes
10147                || gate_bank.expert_bytes != up_bank.expert_bytes
10148            {
10149                return Err("NVFP4 t2 routes need matched gate/up bank geometry".into());
10150            }
10151            {
10152                let Nvfp4T2Workspace {
10153                    sel2,
10154                    in_q2,
10155                    in_d2,
10156                    gate_out2,
10157                    up_out2,
10158                    ..
10159                } = &mut *ws;
10160                engine.qmatvec_nvfp4_sel_gu_tcol_into(
10161                    &gate_bank.bank,
10162                    &up_bank.bank,
10163                    &sel2[rank],
10164                    &in_q2[rank],
10165                    &in_d2[rank],
10166                    &mut gate_out2[rank],
10167                    &mut up_out2[rank],
10168                    n_sel,
10169                    n_sel_col,
10170                    gate_bank.in_features,
10171                    gate_bank.local_out,
10172                    gate_bank.row_bytes,
10173                    gate_bank.expert_bytes,
10174                    width,
10175                    width / 32,
10176                )?;
10177            }
10178            {
10179                let Nvfp4T2Workspace {
10180                    gate_out2,
10181                    up_out2,
10182                    sel2,
10183                    act_q2,
10184                    act_d2,
10185                    ..
10186                } = &mut *ws;
10187                engine.silu_mul_scaled_q8_1_sel_into(
10188                    &gate_out2[rank],
10189                    &up_out2[rank],
10190                    &experts.macros_gate_dev[rank],
10191                    &experts.macros_up_dev[rank],
10192                    &sel2[rank],
10193                    activation_limit,
10194                    &mut act_q2[rank],
10195                    &mut act_d2[rank],
10196                    local_out,
10197                    n_sel,
10198                )?;
10199            }
10200            let shard = &experts.down[rank];
10201            if shard.device_rank != rank || shard.local_in != local_out {
10202                return Err("NVFP4 t2 routes: down shard placement drifted".into());
10203            }
10204            {
10205                let Nvfp4T2Workspace {
10206                    sel2,
10207                    act_q2,
10208                    act_d2,
10209                    partial2,
10210                    ..
10211                } = &mut *ws;
10212                engine.qmatvec_nvfp4_sel_into(
10213                    &shard.bank,
10214                    &sel2[rank],
10215                    &act_q2[rank],
10216                    &act_d2[rank],
10217                    &mut partial2[rank],
10218                    n_sel,
10219                    shard.local_in,
10220                    shard.out_features,
10221                    shard.row_bytes,
10222                    shard.expert_bytes,
10223                    local_out,
10224                    local_out / 32,
10225                )?;
10226            }
10227            {
10228                let Nvfp4T2Workspace {
10229                    partial2,
10230                    route_w2,
10231                    sel2,
10232                    acc_a,
10233                    acc_b,
10234                    ..
10235                } = &mut *ws;
10236                engine.axpy_rows_seq_md_off_into(
10237                    &partial2[rank],
10238                    &route_w2[rank],
10239                    &experts.macros_down_dev[rank],
10240                    &sel2[rank],
10241                    &mut acc_a[rank],
10242                    width,
10243                    n_sel_col,
10244                    0,
10245                )?;
10246                engine.axpy_rows_seq_md_off_into(
10247                    &partial2[rank],
10248                    &route_w2[rank],
10249                    &experts.macros_down_dev[rank],
10250                    &sel2[rank],
10251                    &mut acc_b[rank],
10252                    width,
10253                    n_sel_col,
10254                    n_sel_col,
10255                )?;
10256            }
10257            if rank != 0 {
10258                ws.ev_rank[rank].record(&engine.stream())?;
10259            }
10260        }
10261        let root = &self.ranks[0];
10262        {
10263            let _main = root.gpu.enter_main()?;
10264            for ev in ws.ev_rank.iter().skip(1) {
10265                root.stream().wait(ev)?;
10266            }
10267            {
10268                let Nvfp4T2Workspace {
10269                    acc_a,
10270                    acc_b,
10271                    peer_a,
10272                    peer_b,
10273                    omix_a,
10274                    omix_b,
10275                    ..
10276                } = &mut *ws;
10277                {
10278                    let mut dst = peer_a.slice_mut(0..width);
10279                    root.stream()
10280                        .memcpy_dtod(&acc_a[1].slice(0..width), &mut dst)?;
10281                }
10282                {
10283                    let mut dst = peer_b.slice_mut(0..width);
10284                    root.stream()
10285                        .memcpy_dtod(&acc_b[1].slice(0..width), &mut dst)?;
10286                }
10287                root.add(&acc_a[0], peer_a, omix_a, width)?;
10288                root.add(&acc_b[0], peer_b, omix_b, width)?;
10289            }
10290            ws.ev_root.record(&root.stream())?;
10291        }
10292        let _main = e.gpu.enter_main()?;
10293        e.stream().wait(&ws.ev_root)?;
10294        let mut out = e.uninit(2 * width)?;
10295        e.stream()
10296            .memcpy_dtod(&ws.omix_a.slice(0..width), &mut out.slice_mut(0..width))?;
10297        e.stream().memcpy_dtod(
10298            &ws.omix_b.slice(0..width),
10299            &mut out.slice_mut(width..2 * width),
10300        )?;
10301        Ok(out)
10302    }
10303
10304    pub fn run_tensor_parallel_routes_nvfp4_device_routed(
10305        &self,
10306        experts: &ResidentNvfp4TensorParallel,
10307        e: &Engine,
10308        input_dev: &crate::CudaSlice<f32>,
10309        sel_d: &crate::CudaSlice<i32>,
10310        w_d: &crate::CudaSlice<f32>,
10311        experts_per_token: usize,
10312        activation_limit: Option<f32>,
10313    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10314        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
10315            experts,
10316            e,
10317            input_dev,
10318            sel_d,
10319            w_d,
10320            experts_per_token,
10321            activation_limit,
10322            || Ok(()),
10323        )
10324    }
10325
10326    /// `run_tensor_parallel_routes_nvfp4_device_routed` with a PREJOIN hook: `pre_join`
10327    /// runs on the host right before the join wait is enqueued on e's stream — work it
10328    /// issues there (e.g. the shexp overlap) executes WHILE the peer rank finishes its
10329    /// sweep, instead of after the join. Value-neutral by construction (the hook only
10330    /// reorders independent host issue).
10331    #[allow(clippy::too_many_arguments)]
10332    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
10333        &self,
10334        experts: &ResidentNvfp4TensorParallel,
10335        e: &Engine,
10336        input_dev: &crate::CudaSlice<f32>,
10337        sel_d: &crate::CudaSlice<i32>,
10338        w_d: &crate::CudaSlice<f32>,
10339        experts_per_token: usize,
10340        activation_limit: Option<f32>,
10341        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
10342    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10343        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
10344            experts,
10345            e,
10346            input_dev,
10347            sel_d,
10348            w_d,
10349            experts_per_token,
10350            activation_limit,
10351            pre_join,
10352            None,
10353        )
10354    }
10355
10356    /// The prejoin variant with MOE TAIL FUSION M1: when `post_add = Some((sh_raw,
10357    /// scale_raw))`, the direct-join arm folds the shexp apply into the join add
10358    /// (`dst = (acc0+acc1) + sh*scale[0]`, exact split-pair sequence) — the caller skips
10359    /// its apply launch. Raw UVA pointers so no lock is held across the call.
10360    #[allow(clippy::too_many_arguments)]
10361    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
10362        &self,
10363        experts: &ResidentNvfp4TensorParallel,
10364        e: &Engine,
10365        input_dev: &crate::CudaSlice<f32>,
10366        sel_d: &crate::CudaSlice<i32>,
10367        w_d: &crate::CudaSlice<f32>,
10368        experts_per_token: usize,
10369        activation_limit: Option<f32>,
10370        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
10371        post_add: Option<(u64, u64)>,
10372    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10373        if input_dev.len() != experts.input_width {
10374            return Err(format!(
10375                "NVFP4 device-routed input {} != width {}",
10376                input_dev.len(),
10377                experts.input_width
10378            )
10379            .into());
10380        }
10381        let n_sel = experts_per_token;
10382        if sel_d.len() < n_sel || w_d.len() < n_sel {
10383            return Err(format!(
10384                "NVFP4 device-routed routes sel={} w={} < experts/token {n_sel}",
10385                sel_d.len(),
10386                w_d.len()
10387            )
10388            .into());
10389        }
10390        let world = self.ranks.len();
10391        if world != NVFP4_CANONICAL_ROW_SHARDS {
10392            return Err(format!(
10393                "NVFP4 device routes require world == canonical shard grid \
10394                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
10395            )
10396            .into());
10397        }
10398        let local_out = experts.expert_width / world;
10399
10400        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10401        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10402        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
10403        let started = timing.then(std::time::Instant::now);
10404
10405        let mut workspace_guard = experts
10406            .device_workspace
10407            .lock()
10408            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
10409        if workspace_guard.is_none() {
10410            drop(workspace_guard);
10411            let zero = vec![0.0f32; experts.input_width];
10412            let zero_sel = vec![0usize; n_sel];
10413            let zero_w = vec![0.0f32; n_sel];
10414            let _ = self.run_tensor_parallel_routes_nvfp4_device(
10415                experts,
10416                &zero,
10417                &zero_sel,
10418                &zero_w,
10419                n_sel,
10420                activation_limit,
10421            )?;
10422            workspace_guard = experts
10423                .device_workspace
10424                .lock()
10425                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
10426        }
10427        let workspace = workspace_guard
10428            .as_mut()
10429            .expect("NVFP4 device routes workspace initialized above");
10430        if workspace.n_sel != n_sel {
10431            return Err(format!(
10432                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
10433                workspace.n_sel
10434            )
10435            .into());
10436        }
10437
10438        // GRAPH DOOR (MEMRA_STEP_TP_GRAPH=1): the whole rank+root segment replays as one
10439        // stitched multi-device parent launched on e's stream — no events, no per-token node
10440        // updates (every address is persistent staging). VALUE-IDENTICAL to the eager path:
10441        // the children replay exactly the same kernel/copy sequence.
10442        if step_tp_graph_enabled()? {
10443            if workspace.dev_route_e.is_none() {
10444                let _main = e.gpu.enter_main()?;
10445                workspace.dev_route_e = Some((
10446                    e.htod_i32(&vec![0i32; n_sel])?,
10447                    e.htod(&vec![0.0f32; n_sel])?,
10448                ));
10449            }
10450            if workspace.in_stage_e.is_none() {
10451                let _main = e.gpu.enter_main()?;
10452                workspace.in_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
10453                workspace.out_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
10454            }
10455            if workspace.routes_graph.is_none() {
10456                let graph = self.nvfp4_routes_build_graph(
10457                    experts,
10458                    workspace,
10459                    local_out,
10460                    n_sel,
10461                    activation_limit,
10462                )?;
10463                workspace.routes_graph = Some(graph);
10464                eprintln!(
10465                    "[step-tp-graph] routes segment captured: ranks={world} n_sel={n_sel} \
10466                     children=3 updates=none performance_claim=false"
10467                );
10468            }
10469            let output = {
10470                let _main = e.gpu.enter_main()?;
10471                {
10472                    let (sel_e, w_e) = workspace
10473                        .dev_route_e
10474                        .as_mut()
10475                        .expect("device route staging set above");
10476                    {
10477                        let mut dst = sel_e.slice_mut(0..n_sel);
10478                        e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
10479                    }
10480                    {
10481                        let mut dst = w_e.slice_mut(0..n_sel);
10482                        e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
10483                    }
10484                }
10485                {
10486                    let in_stage = workspace
10487                        .in_stage_e
10488                        .as_mut()
10489                        .expect("graph staging set above");
10490                    let mut dst = in_stage.slice_mut(0..experts.input_width);
10491                    e.stream()
10492                        .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut dst)?;
10493                }
10494                unsafe {
10495                    let r = cudarc::driver::sys::cuGraphLaunch(
10496                        workspace
10497                            .routes_graph
10498                            .as_ref()
10499                            .expect("routes graph built above")
10500                            .exec,
10501                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
10502                    );
10503                    if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
10504                        return Err(format!("routes graph launch: {r:?}").into());
10505                    }
10506                }
10507                let mut output = e.uninit(experts.input_width)?;
10508                {
10509                    let out_stage = workspace
10510                        .out_stage_e
10511                        .as_ref()
10512                        .expect("graph staging set above");
10513                    e.stream().memcpy_dtod(
10514                        &out_stage.slice(0..experts.input_width),
10515                        &mut output.slice_mut(0..experts.input_width),
10516                    )?;
10517                }
10518                output
10519            };
10520            if let Some(started) = started {
10521                use std::sync::atomic::Ordering;
10522                let ns = TIMING_NS
10523                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
10524                    + started.elapsed().as_nanos() as u64;
10525                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
10526                if calls % 430 == 0 {
10527                    eprintln!(
10528                        "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
10529                        ns as f64 / 1.0e6,
10530                        ns as f64 / calls as f64 / 1.0e3,
10531                    );
10532                }
10533            }
10534            return Ok(output);
10535        }
10536
10537        // Entry fence + router-output staging, all on e's stream: the fresh sel/w slices are
10538        // copied into the persistent e-context pair, then the event is recorded — the caller's
10539        // sel_d/w_d can free on e's stream with no cross-stream reader.
10540        if let Some((_, device)) = workspace.ev_entry.as_ref() {
10541            if *device != e.ctx().ordinal() {
10542                return Err("NVFP4 device-routed routes engine changed".into());
10543            }
10544        } else {
10545            let _main = e.gpu.enter_main()?;
10546            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
10547        }
10548        if workspace.dev_route_e.is_none() {
10549            let _main = e.gpu.enter_main()?;
10550            workspace.dev_route_e = Some((
10551                e.htod_i32(&vec![0i32; n_sel])?,
10552                e.htod(&vec![0.0f32; n_sel])?,
10553            ));
10554        }
10555        // MEMRA_SEL_MIRROR: the staging pair exists so the rank streams read a persistent
10556        // e-context address. The caller's sel_d/w_d ARE persistent (the process-static
10557        // selection rows), so when every consuming rank shares e's device the ranks can read
10558        // them directly and this hop disappears. The graph door keeps the staging (its
10559        // captured copies read the fixed addresses).
10560        let mirror = sel_mirror_on() && !step_tp_graph_enabled()?;
10561        let e_device = e.ctx().ordinal();
10562        // rank1_routed is consumed (taken) below; peek it here for the staging decision.
10563        let rank1_routed_peek = workspace.rank1_routed;
10564        let stage_needed = !mirror
10565            || self.ranks.iter().enumerate().any(|(rank_index, engine)| {
10566                !(rank1_routed_peek && rank_index == 1) && engine.ctx().ordinal() != e_device
10567            });
10568        {
10569            let _main = e.gpu.enter_main()?;
10570            if stage_needed {
10571                let (sel_e, w_e) = workspace
10572                    .dev_route_e
10573                    .as_mut()
10574                    .expect("device route staging set above");
10575                {
10576                    let mut dst = sel_e.slice_mut(0..n_sel);
10577                    e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
10578                }
10579                {
10580                    let mut dst = w_e.slice_mut(0..n_sel);
10581                    e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
10582                }
10583            }
10584            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
10585            ev_entry.record(&e.stream())?;
10586        }
10587        // Prestage door: input pull + quantize were already issued on the rank streams
10588        // (before the router) — the rank stream order suffices, skip them here.
10589        let prestaged = std::mem::take(&mut workspace.prestaged);
10590        let rank1_routed = std::mem::take(&mut workspace.rank1_routed);
10591        for (rank_index, engine) in self.ranks.iter().enumerate() {
10592            let _main = engine.gpu.enter_main()?;
10593            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
10594            engine.stream().wait(ev_entry)?;
10595            if !prestaged {
10596                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
10597                engine
10598                    .stream()
10599                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
10600            }
10601            if !(rank1_routed && rank_index == 1) {
10602                // ONE mirror launch instead of two 32-byte copy-engine dispatches; source is
10603                // the caller's persistent rows when this rank shares e's device (UVA, ordered
10604                // by ev_entry), else the staged e-context pair.
10605                let same_dev = engine.ctx().ordinal() == e_device;
10606                if mirror {
10607                    // Split the workspace borrow so the source (the staged pair, when this
10608                    // rank is off-device) and the destination rows coexist.
10609                    let Nvfp4DeviceRoutesWorkspace {
10610                        sel,
10611                        route_w,
10612                        dev_route_e,
10613                        ..
10614                    } = &mut *workspace;
10615                    let (src_sel, src_w): (&crate::CudaSlice<i32>, &crate::CudaSlice<f32>) =
10616                        if same_dev {
10617                            (sel_d, w_d)
10618                        } else {
10619                            let (sel_e, w_e) = dev_route_e
10620                                .as_ref()
10621                                .expect("device route staging set above");
10622                            (sel_e, w_e)
10623                        };
10624                    engine.moe_sel_w_mirror(
10625                        src_sel,
10626                        src_w,
10627                        &mut sel[rank_index],
10628                        &mut route_w[rank_index],
10629                        n_sel,
10630                    )?;
10631                } else {
10632                    let (sel_e, w_e) = workspace
10633                        .dev_route_e
10634                        .as_ref()
10635                        .expect("device route staging set above");
10636                    {
10637                        let mut dst = workspace.sel[rank_index].slice_mut(0..n_sel);
10638                        engine
10639                            .stream()
10640                            .memcpy_dtod(&sel_e.slice(0..n_sel), &mut dst)?;
10641                    }
10642                    {
10643                        let mut dst = workspace.route_w[rank_index].slice_mut(0..n_sel);
10644                        engine
10645                            .stream()
10646                            .memcpy_dtod(&w_e.slice(0..n_sel), &mut dst)?;
10647                    }
10648                }
10649            }
10650            if !prestaged {
10651                let Nvfp4DeviceRoutesWorkspace {
10652                    input, in_q, in_d, ..
10653                } = &mut *workspace;
10654                engine.quantize_q8_1_into(
10655                    &input[rank_index],
10656                    1,
10657                    experts.input_width,
10658                    &mut in_q[rank_index],
10659                    &mut in_d[rank_index],
10660                )?;
10661            }
10662        }
10663        self.nvfp4_routes_batched_sweeps(
10664            experts,
10665            workspace,
10666            &[],
10667            &[],
10668            &[],
10669            local_out,
10670            n_sel,
10671            activation_limit,
10672            true,
10673        )?;
10674
10675        // rank0 == root: its own stream order already covers its sweep; only the PEER
10676        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
10677        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
10678            let _main = engine.gpu.enter_main()?;
10679            workspace.ev_rank[rank_index].record(&engine.stream())?;
10680        }
10681        // Doorbell fences (MEMRA_FENCE_MEMOPS=1): rank1 + root ring their flags; e waits
10682        // the tickets instead of the two events. Arm lazily; 0-len = unsupported.
10683        let memops = fence_memops_on() && moe_direct_on() && self.ranks.len() == 2;
10684        let mut ticket = 0u32;
10685        if memops {
10686            use cudarc::driver::sys;
10687            if workspace.fence_flags_raw == 0 {
10688                let root = &self.ranks[0];
10689                let _main = root.gpu.enter_main()?;
10690                let mut ptr: sys::CUdeviceptr = 0;
10691                let r = unsafe { sys::cuMemAlloc_v2(&mut ptr, 8) };
10692                if r != sys::CUresult::CUDA_SUCCESS {
10693                    return Err(format!("fence flag alloc: {r:?}").into());
10694                }
10695                let r = unsafe { sys::cuMemsetD8_v2(ptr, 0, 8) };
10696                if r != sys::CUresult::CUDA_SUCCESS {
10697                    return Err(format!("fence flag memset: {r:?}").into());
10698                }
10699                workspace.fence_flags_raw = ptr as u64;
10700            }
10701            workspace.fence_ticket = workspace.fence_ticket.wrapping_add(1).max(1);
10702            ticket = workspace.fence_ticket;
10703            let base = workspace.fence_flags_raw;
10704            // rank1's fence: a peer stream MEMOP is rejected over PCIe P2P
10705            // (CUDA_ERROR_INVALID_VALUE, receipted 2026-08-23), but a peer KERNEL STORE into
10706            // root memory is legal — the direct join already relies on it. Under
10707            // MEMRA_FENCE_RANK1 rank1 rings flag[0] that way and e waits it same-device,
10708            // replacing the cross-device event wait below.
10709            if fence_rank1_on() {
10710                let peer = &self.ranks[1];
10711                let _pmain = peer.gpu.enter_main()?;
10712                peer.ring_flag_raw(base, ticket)?;
10713            }
10714            {
10715                let root = &self.ranks[0];
10716                let _main = root.gpu.enter_main()?;
10717                let r = unsafe {
10718                    sys::cuStreamWriteValue32_v2(
10719                        root.stream().cu_stream() as sys::CUstream,
10720                        (base + 4) as sys::CUdeviceptr,
10721                        ticket,
10722                        0,
10723                    )
10724                };
10725                if r != sys::CUresult::CUDA_SUCCESS {
10726                    return Err(format!("fence write root: {r:?}").into());
10727                }
10728            }
10729        }
10730        // PREJOIN hook: rank work is fully issued (dev1 running); independent e-stream
10731        // kernels queued here execute while the peer rank drains its sweep.
10732        pre_join()?;
10733
10734        if moe_direct_on() && self.ranks.len() == 2 {
10735            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
10736            // rank0's is root-stream-ordered. One root event + rank1's own event order
10737            // the model engine's single add — same operand order as root's add
10738            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
10739            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
10740            // hazard class does not apply).
10741            let _main = e.gpu.enter_main()?;
10742            if memops {
10743                use cudarc::driver::sys;
10744                let base = workspace.fence_flags_raw;
10745                let r = unsafe {
10746                    sys::cuStreamWaitValue32_v2(
10747                        e.stream().cu_stream() as sys::CUstream,
10748                        (base + 4) as sys::CUdeviceptr,
10749                        ticket,
10750                        sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
10751                    )
10752                };
10753                if r != sys::CUresult::CUDA_SUCCESS {
10754                    return Err(format!("fence wait: {r:?}").into());
10755                }
10756                if fence_rank1_on() {
10757                    // Same-device wait on the flag rank1 rang over P2P.
10758                    let r = unsafe {
10759                        sys::cuStreamWaitValue32_v2(
10760                            e.stream().cu_stream() as sys::CUstream,
10761                            base as sys::CUdeviceptr,
10762                            ticket,
10763                            sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
10764                        )
10765                    };
10766                    if r != sys::CUresult::CUDA_SUCCESS {
10767                        return Err(format!("fence wait rank1: {r:?}").into());
10768                    }
10769                } else {
10770                    for ev in workspace.ev_rank.iter().skip(1) {
10771                        e.stream().wait(ev)?;
10772                    }
10773                }
10774            } else {
10775                {
10776                    let root = &self.ranks[0];
10777                    let _rmain = root.gpu.enter_main()?;
10778                    workspace
10779                        .ev_done
10780                        .as_ref()
10781                        .expect("device routes done event")
10782                        .record(&root.stream())?;
10783                }
10784                e.stream().wait(
10785                    workspace
10786                        .ev_done
10787                        .as_ref()
10788                        .expect("device routes done event"),
10789                )?;
10790                for ev in workspace.ev_rank.iter().skip(1) {
10791                    e.stream().wait(ev)?;
10792                }
10793            }
10794            let mut output = e.uninit(experts.input_width)?;
10795            if let Some((sh_raw, scale_raw)) = post_add {
10796                // MOE TAIL FUSION M1: fold the shexp apply into the join add —
10797                // dst = (acc0 + acc1) + sh*scale[0], the exact split-pair sequence.
10798                e.add3_raw(
10799                    &workspace.accumulator[0],
10800                    &workspace.accumulator[1],
10801                    sh_raw,
10802                    scale_raw,
10803                    &mut output,
10804                    experts.input_width,
10805                )?;
10806            } else {
10807                e.add(
10808                    &workspace.accumulator[0],
10809                    &workspace.accumulator[1],
10810                    &mut output,
10811                    experts.input_width,
10812                )?;
10813            }
10814            let output = output;
10815            if let Some(started) = started {
10816                use std::sync::atomic::Ordering;
10817                let ns = TIMING_NS
10818                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
10819                    + started.elapsed().as_nanos() as u64;
10820                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
10821                if calls % 430 == 0 {
10822                    eprintln!(
10823                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
10824                        ns as f64 / 1.0e6,
10825                        ns as f64 / calls as f64 / 1.0e3,
10826                    );
10827                }
10828            }
10829            return Ok(output);
10830        }
10831        {
10832            let root = &self.ranks[0];
10833            let _main = root.gpu.enter_main()?;
10834            for ev in workspace.ev_rank.iter().skip(1) {
10835                root.stream().wait(ev)?;
10836            }
10837            root.stream()
10838                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
10839            {
10840                let Nvfp4DeviceRoutesWorkspace {
10841                    accumulator,
10842                    remote,
10843                    combined,
10844                    ..
10845                } = &mut *workspace;
10846                root.add(&accumulator[0], remote, combined, experts.input_width)?;
10847            }
10848            workspace
10849                .ev_done
10850                .as_ref()
10851                .expect("device routes done event")
10852                .record(&root.stream())?;
10853        }
10854        let output = {
10855            let _main = e.gpu.enter_main()?;
10856            e.stream().wait(
10857                workspace
10858                    .ev_done
10859                    .as_ref()
10860                    .expect("device routes done event"),
10861            )?;
10862            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
10863            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
10864            let mut output = e.uninit(experts.input_width)?;
10865            e.stream().memcpy_dtod(
10866                &workspace.combined.slice(0..experts.input_width),
10867                &mut output.slice_mut(0..experts.input_width),
10868            )?;
10869            output
10870        };
10871        if let Some(started) = started {
10872            use std::sync::atomic::Ordering;
10873            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
10874                + started.elapsed().as_nanos() as u64;
10875            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
10876            if calls % 430 == 0 {
10877                eprintln!(
10878                    "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
10879                    ns as f64 / 1.0e6,
10880                    ns as f64 / calls as f64 / 1.0e3,
10881                );
10882            }
10883        }
10884        Ok(output)
10885    }
10886
10887    /// The fused finish's ROOT section (combine + shadow gathers), event-free: the eager
10888    /// caller wraps it with rank-event waits + the done record; the token graph captures it
10889    /// verbatim (parent edges provide the ordering).
10890    pub(crate) fn decode_v2_finish_root_fused(
10891        &self,
10892        ws: &mut StepTpDecodeV2Ws,
10893    ) -> Result<(), Box<dyn std::error::Error>> {
10894        let root = &self.ranks[0];
10895        let _main = root.gpu.enter_main()?;
10896        if ws.raw_peer_partial != 0 {
10897            // Capture-safe raw seams (arming happened in the stage flow).
10898            raw_copy_bytes(ws.raw_peer_partial, ws.raw_o_partial1, ws.o_out * 4, root)?;
10899        } else {
10900            root.stream()
10901                .memcpy_dtod(&ws.o_partials[1][0], &mut ws.peer_partial)?;
10902        }
10903        {
10904            let StepTpDecodeV2Ws {
10905                o_partials,
10906                peer_partial,
10907                reduce_a,
10908                o_out,
10909                ..
10910            } = &mut *ws;
10911            root.add(&o_partials[0][0], peer_partial, reduce_a, *o_out)?;
10912        }
10913        let shadows = !no_local_shadow_on() || ws.raw_mixed_stage_e != 0;
10914        if shadows {
10915            // rank0's shadows are same-context (root) copies; rank1's cross-context reads go
10916            // raw when armed.
10917            let mut k_dst = ws.k_shadow.slice_mut(0..ws.local_kv_dim);
10918            root.stream().memcpy_dtod(&ws.k[0], &mut k_dst)?;
10919            let mut v_dst = ws.v_shadow.slice_mut(0..ws.local_kv_dim);
10920            root.stream().memcpy_dtod(&ws.v_raw[0], &mut v_dst)?;
10921        }
10922        if shadows && ws.raw_peer_partial != 0 {
10923            raw_copy_bytes(
10924                ws.raw_k_shadow + (ws.local_kv_dim * 4) as u64,
10925                ws.raw_k1,
10926                ws.local_kv_dim * 4,
10927                root,
10928            )?;
10929            raw_copy_bytes(
10930                ws.raw_v_shadow + (ws.local_kv_dim * 4) as u64,
10931                ws.raw_v1,
10932                ws.local_kv_dim * 4,
10933                root,
10934            )?;
10935        } else if shadows {
10936            let start = ws.local_kv_dim;
10937            let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
10938            root.stream().memcpy_dtod(&ws.k[1], &mut k_dst)?;
10939            let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
10940            root.stream().memcpy_dtod(&ws.v_raw[1], &mut v_dst)?;
10941        }
10942        if ws.raw_mixed_stage_e != 0 {
10943            // Token-graph mirrors: the e-glue children read same-context copies of the
10944            // root-produced rows.
10945            raw_copy_bytes(ws.raw_mixed_stage_e, ws.raw_reduce_a, ws.o_out * 4, root)?;
10946            let (k_stage, v_stage) = ws.raw_shadow_stage_e;
10947            raw_copy_bytes(k_stage, ws.raw_k_shadow, 2 * ws.local_kv_dim * 4, root)?;
10948            raw_copy_bytes(v_stage, ws.raw_v_shadow, 2 * ws.local_kv_dim * 4, root)?;
10949        }
10950        Ok(())
10951    }
10952
10953    /// Arm the token-graph e-context mirrors (orchestrator-supplied fixed addresses) plus
10954    /// reduce_a's own pointer.
10955    pub(crate) fn decode_v2_arm_token_mirrors(
10956        &self,
10957        ws: &mut StepTpDecodeV2Ws,
10958        mixed_stage_e: u64,
10959        shadow_stage_e: (u64, u64),
10960    ) -> Result<(), Box<dyn std::error::Error>> {
10961        use cudarc::driver::DevicePtr;
10962        let root = &self.ranks[0];
10963        let _main = root.gpu.enter_main()?;
10964        let stream = root.stream();
10965        let (a, _g) = ws.reduce_a.device_ptr(&stream);
10966        ws.raw_reduce_a = a as u64;
10967        ws.raw_mixed_stage_e = mixed_stage_e;
10968        ws.raw_shadow_stage_e = shadow_stage_e;
10969        Ok(())
10970    }
10971
10972    /// Build one layer's stitched routes graph: per-rank children captured on their own
10973    /// streams (raw cuMemcpyAsync at every cross-context seam — cudarc's slice tracking is
10974    /// capture-illegal there), a root combine child, and a multi-device parent with
10975    /// {rank0, rank1} -> root dependency edges. Zero per-token updates: every address the
10976    /// nodes touch is persistent workspace/staging.
10977    fn nvfp4_routes_build_graph(
10978        &self,
10979        experts: &ResidentNvfp4TensorParallel,
10980        workspace: &mut Nvfp4DeviceRoutesWorkspace,
10981        local_out: usize,
10982        n_sel: usize,
10983        activation_limit: Option<f32>,
10984    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
10985        use cudarc::driver::DevicePtr;
10986        use cudarc::driver::sys;
10987        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
10988            if r == sys::CUresult::CUDA_SUCCESS {
10989                Ok(())
10990            } else {
10991                Err(format!("{what}: {r:?}").into())
10992            }
10993        }
10994        let world = self.ranks.len();
10995        if world != 2 {
10996            return Err("routes graph door is built for the TP2 pair".into());
10997        }
10998        let width = experts.input_width;
10999
11000        // Raw pointers cached before capture (each read with its owner's stream).
11001        let ptr_f32 = |buf: &crate::CudaSlice<f32>, engine: &Engine| -> u64 {
11002            let stream = engine.stream();
11003            let (ptr, _g) = buf.device_ptr(&stream);
11004            ptr as u64
11005        };
11006        let ptr_i32 = |buf: &crate::CudaSlice<i32>, engine: &Engine| -> u64 {
11007            let stream = engine.stream();
11008            let (ptr, _g) = buf.device_ptr(&stream);
11009            ptr as u64
11010        };
11011        let (sel_e, w_e) = workspace
11012            .dev_route_e
11013            .as_ref()
11014            .expect("device route staging set before graph build");
11015        let root_engine = &self.ranks[0];
11016        let p_in_stage = ptr_f32(
11017            workspace.in_stage_e.as_ref().expect("graph staging"),
11018            root_engine,
11019        );
11020        let p_out_stage = ptr_f32(
11021            workspace.out_stage_e.as_ref().expect("graph staging"),
11022            root_engine,
11023        );
11024        let p_sel_e = ptr_i32(sel_e, root_engine);
11025        let p_w_e = ptr_f32(w_e, root_engine);
11026        let p_input: Vec<u64> = (0..world)
11027            .map(|r| ptr_f32(&workspace.input[r], &self.ranks[r]))
11028            .collect();
11029        let p_sel: Vec<u64> = (0..world)
11030            .map(|r| ptr_i32(&workspace.sel[r], &self.ranks[r]))
11031            .collect();
11032        let p_route_w: Vec<u64> = (0..world)
11033            .map(|r| ptr_f32(&workspace.route_w[r], &self.ranks[r]))
11034            .collect();
11035        let p_acc1 = ptr_f32(&workspace.accumulator[1], &self.ranks[1]);
11036        let p_remote = ptr_f32(&workspace.remote, root_engine);
11037        let p_combined = ptr_f32(&workspace.combined, root_engine);
11038
11039        let raw_copy = |dst: u64,
11040                        src: u64,
11041                        bytes: usize,
11042                        engine: &Engine|
11043         -> Result<(), Box<dyn std::error::Error>> {
11044            unsafe {
11045                cu_try(
11046                    sys::cuMemcpyAsync(
11047                        dst as sys::CUdeviceptr,
11048                        src as sys::CUdeviceptr,
11049                        bytes,
11050                        engine.stream().cu_stream() as sys::CUstream,
11051                    ),
11052                    "routes graph cuMemcpyAsync",
11053                )
11054            }
11055        };
11056
11057        let mut children = Vec::with_capacity(3);
11058        for rank in 0..world {
11059            let engine = &self.ranks[rank];
11060            let _main = engine.gpu.enter_main()?;
11061            let (child, _retained) = engine.capture_graph_retained(|_| {
11062                raw_copy(p_input[rank], p_in_stage, width * 4, engine)?;
11063                raw_copy(p_sel[rank], p_sel_e, n_sel * 4, engine)?;
11064                raw_copy(p_route_w[rank], p_w_e, n_sel * 4, engine)?;
11065                {
11066                    let Nvfp4DeviceRoutesWorkspace {
11067                        input, in_q, in_d, ..
11068                    } = &mut *workspace;
11069                    engine.quantize_q8_1_into(
11070                        &input[rank],
11071                        1,
11072                        width,
11073                        &mut in_q[rank],
11074                        &mut in_d[rank],
11075                    )?;
11076                }
11077                self.nvfp4_routes_batched_sweeps_rank(
11078                    experts,
11079                    workspace,
11080                    &[],
11081                    &[],
11082                    &[],
11083                    local_out,
11084                    n_sel,
11085                    activation_limit,
11086                    true,
11087                    rank,
11088                )?;
11089                Ok(())
11090            })?;
11091            children.push(child);
11092        }
11093        {
11094            let root = &self.ranks[0];
11095            let _main = root.gpu.enter_main()?;
11096            let (child, _retained) = root.capture_graph_retained(|_| {
11097                raw_copy(p_remote, p_acc1, width * 4, root)?;
11098                {
11099                    let Nvfp4DeviceRoutesWorkspace {
11100                        accumulator,
11101                        remote,
11102                        combined,
11103                        ..
11104                    } = &mut *workspace;
11105                    root.add(&accumulator[0], remote, combined, width)?;
11106                }
11107                raw_copy(p_out_stage, p_combined, width * 4, root)?;
11108                Ok(())
11109            })?;
11110            children.push(child);
11111        }
11112
11113        let mut parent: sys::CUgraph = std::ptr::null_mut();
11114        unsafe {
11115            cu_try(sys::cuGraphCreate(&mut parent, 0), "routes cuGraphCreate")?;
11116        }
11117        let mut n0: sys::CUgraphNode = std::ptr::null_mut();
11118        let mut n1: sys::CUgraphNode = std::ptr::null_mut();
11119        let mut n2: sys::CUgraphNode = std::ptr::null_mut();
11120        unsafe {
11121            cu_try(
11122                sys::cuGraphAddChildGraphNode(
11123                    &mut n0,
11124                    parent,
11125                    std::ptr::null(),
11126                    0,
11127                    children[0].cu_graph(),
11128                ),
11129                "routes child r0",
11130            )?;
11131            cu_try(
11132                sys::cuGraphAddChildGraphNode(
11133                    &mut n1,
11134                    parent,
11135                    std::ptr::null(),
11136                    0,
11137                    children[1].cu_graph(),
11138                ),
11139                "routes child r1",
11140            )?;
11141            let deps = [n0, n1];
11142            cu_try(
11143                sys::cuGraphAddChildGraphNode(
11144                    &mut n2,
11145                    parent,
11146                    deps.as_ptr(),
11147                    2,
11148                    children[2].cu_graph(),
11149                ),
11150                "routes child root",
11151            )?;
11152        }
11153        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
11154        unsafe {
11155            cu_try(
11156                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
11157                "routes instantiate",
11158            )?;
11159        }
11160        Ok(RoutesGraph {
11161            exec,
11162            parent,
11163            _children: children,
11164        })
11165    }
11166
11167    /// One rank's routes section for the token graph (event-free): staged input copy (raw
11168    /// when the caller supplies the source pointer), quantize, and the batched sweeps.
11169    /// Eager device_routed wraps it with the entry-event wait.
11170    #[allow(clippy::too_many_arguments)]
11171    pub(crate) fn routes_rank_section(
11172        &self,
11173        experts: &ResidentNvfp4TensorParallel,
11174        workspace: &mut Nvfp4DeviceRoutesWorkspace,
11175        raw_input_src: u64,
11176        local_out: usize,
11177        n_sel: usize,
11178        activation_limit: Option<f32>,
11179        rank_index: usize,
11180    ) -> Result<(), Box<dyn std::error::Error>> {
11181        let engine = &self.ranks[rank_index];
11182        {
11183            let _main = engine.gpu.enter_main()?;
11184            // sel/route_w land via raw copies from the e staging (fixed addresses).
11185            let (sel_e_ptr, w_e_ptr) = workspace
11186                .raw_dev_route_e
11187                .ok_or("routes rank section requires armed staging pointers")?;
11188            raw_copy_bytes(
11189                workspace.raw_input[rank_index],
11190                raw_input_src,
11191                experts.input_width * 4,
11192                engine,
11193            )?;
11194            raw_copy_bytes(workspace.raw_sel[rank_index], sel_e_ptr, n_sel * 4, engine)?;
11195            raw_copy_bytes(
11196                workspace.raw_route_w[rank_index],
11197                w_e_ptr,
11198                n_sel * 4,
11199                engine,
11200            )?;
11201            {
11202                let Nvfp4DeviceRoutesWorkspace {
11203                    input, in_q, in_d, ..
11204                } = &mut *workspace;
11205                engine.quantize_q8_1_into(
11206                    &input[rank_index],
11207                    1,
11208                    experts.input_width,
11209                    &mut in_q[rank_index],
11210                    &mut in_d[rank_index],
11211                )?;
11212            }
11213        }
11214        self.nvfp4_routes_batched_sweeps_rank(
11215            experts,
11216            workspace,
11217            &[],
11218            &[],
11219            &[],
11220            local_out,
11221            n_sel,
11222            activation_limit,
11223            true,
11224            rank_index,
11225        )
11226    }
11227
11228    /// The routes ROOT combine section (event-free): peer accumulator read (raw), canonical
11229    /// add, combined row raw-copied into the fixed e-context out stage.
11230    pub(crate) fn routes_root_section(
11231        &self,
11232        experts: &ResidentNvfp4TensorParallel,
11233        workspace: &mut Nvfp4DeviceRoutesWorkspace,
11234    ) -> Result<(), Box<dyn std::error::Error>> {
11235        let root = &self.ranks[0];
11236        let _main = root.gpu.enter_main()?;
11237        let (acc1_ptr, remote_ptr, combined_ptr, out_stage_ptr) = workspace
11238            .raw_combine
11239            .ok_or("routes root section requires armed combine pointers")?;
11240        raw_copy_bytes(remote_ptr, acc1_ptr, experts.input_width * 4, root)?;
11241        {
11242            let Nvfp4DeviceRoutesWorkspace {
11243                accumulator,
11244                remote,
11245                combined,
11246                ..
11247            } = &mut *workspace;
11248            root.add(&accumulator[0], remote, combined, experts.input_width)?;
11249        }
11250        raw_copy_bytes(out_stage_ptr, combined_ptr, experts.input_width * 4, root)?;
11251        Ok(())
11252    }
11253
11254    /// Arm the routes raw pointers (once): staging pair, per-rank input/sel/route_w, and the
11255    /// combine set. Requires dev_route_e + in/out stages already allocated.
11256    pub(crate) fn routes_arm_raw(
11257        &self,
11258        experts: &ResidentNvfp4TensorParallel,
11259        workspace: &mut Nvfp4DeviceRoutesWorkspace,
11260    ) -> Result<(), Box<dyn std::error::Error>> {
11261        use cudarc::driver::DevicePtr;
11262        if workspace.raw_dev_route_e.is_some() {
11263            return Ok(());
11264        }
11265        let _ = experts;
11266        let (sel_e, w_e) = workspace
11267            .dev_route_e
11268            .as_ref()
11269            .ok_or("routes staging not armed")?;
11270        let root = &self.ranks[0];
11271        {
11272            let _main = root.gpu.enter_main()?;
11273            let stream = root.stream();
11274            let (a, _g) = sel_e.device_ptr(&stream);
11275            let (b, _g) = w_e.device_ptr(&stream);
11276            workspace.raw_dev_route_e = Some((a as u64, b as u64));
11277            let (c, _g) = workspace.accumulator[1].device_ptr(&stream);
11278            let (d, _g) = workspace.remote.device_ptr(&stream);
11279            let (f, _g) = workspace.combined.device_ptr(&stream);
11280            let out_stage = workspace
11281                .out_stage_e
11282                .as_ref()
11283                .ok_or("routes out stage not armed")?;
11284            let (g_, _g) = out_stage.device_ptr(&stream);
11285            workspace.raw_combine = Some((c as u64, d as u64, f as u64, g_ as u64));
11286        }
11287        for rank in 0..self.ranks.len() {
11288            let engine = &self.ranks[rank];
11289            let _main = engine.gpu.enter_main()?;
11290            let stream = engine.stream();
11291            let (a, _g) = workspace.input[rank].device_ptr(&stream);
11292            let (b, _g) = workspace.sel[rank].device_ptr(&stream);
11293            let (c, _g) = workspace.route_w[rank].device_ptr(&stream);
11294            workspace.raw_input.push(a as u64);
11295            workspace.raw_sel.push(b as u64);
11296            workspace.raw_route_w.push(c as u64);
11297        }
11298        Ok(())
11299    }
11300
11301    /// Routed NVFP4 expert program, host-canonical transport. Native/bulk P2P transport for the
11302    /// NVFP4 bank is a separate increment; this entry point is exactness-first and reports no
11303    /// throughput claim.
11304    pub fn run_tensor_parallel_routes_nvfp4(
11305        &self,
11306        experts: &ResidentNvfp4TensorParallel,
11307        input: &[f32],
11308        tokens: usize,
11309        selected: &[usize],
11310        route_weights: &[f32],
11311        experts_per_token: usize,
11312        activation_limit: Option<f32>,
11313    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
11314        validate_activations(input, tokens, experts.input_width)?;
11315        let pairs = tokens
11316            .checked_mul(experts_per_token)
11317            .ok_or("NVFP4 TP route count overflow")?;
11318        if selected.len() != pairs || route_weights.len() != pairs {
11319            return Err(format!(
11320                "NVFP4 TP routes selected={} weights={} != tokens {tokens} x experts/token \
11321                 {experts_per_token} ({pairs})",
11322                selected.len(),
11323                route_weights.len(),
11324            )
11325            .into());
11326        }
11327        if !route_weights.iter().all(|weight| weight.is_finite()) {
11328            return Err("NVFP4 TP route weights contain a non-finite value".into());
11329        }
11330
11331        let mut output = vec![0.0f32; tokens * experts.input_width];
11332        for token in 0..tokens {
11333            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
11334            for slot in 0..experts_per_token {
11335                let pair = token * experts_per_token + slot;
11336                let expert = selected[pair];
11337                if expert >= experts.expert_count {
11338                    return Err(format!(
11339                        "NVFP4 TP selected expert {expert} outside 0..{}",
11340                        experts.expert_count
11341                    )
11342                    .into());
11343                }
11344                let gate = self.run_column_bank_expert_nvfp4(
11345                    &experts.gate,
11346                    &experts.macros_gate,
11347                    expert,
11348                    input_row,
11349                )?;
11350                let up = self.run_column_bank_expert_nvfp4(
11351                    &experts.up,
11352                    &experts.macros_up,
11353                    expert,
11354                    input_row,
11355                )?;
11356                let activated: Vec<f32> = gate
11357                    .iter()
11358                    .zip(&up)
11359                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
11360                    .collect();
11361                debug_assert_eq!(activated.len(), experts.expert_width);
11362                let down = self.run_row_bank_expert_nvfp4(
11363                    &experts.down,
11364                    &experts.macros_down,
11365                    expert,
11366                    &activated,
11367                )?;
11368                let weight = route_weights[pair];
11369                for (sum, value) in output
11370                    [token * experts.input_width..(token + 1) * experts.input_width]
11371                    .iter_mut()
11372                    .zip(down)
11373                {
11374                    *sum += weight * value;
11375                }
11376            }
11377        }
11378        Ok(output)
11379    }
11380}
11381
11382#[cfg(test)]
11383mod tests {
11384    use super::*;
11385
11386    #[test]
11387    fn step_expert_activation_clamps_each_arm_by_the_official_contract() {
11388        let limit = Some(7.0);
11389        assert_eq!(step_expert_activation_host(20.0, 9.0, limit), 49.0);
11390        assert_eq!(step_expert_activation_host(20.0, -9.0, limit), -49.0);
11391        assert!(
11392            step_expert_activation_host(-20.0, 9.0, limit).abs()
11393                < step_expert_activation_host(-20.0, 9.0, None).abs()
11394        );
11395        assert!(validate_step_expert_activation_limit(Some(f32::NAN)).is_err());
11396        assert!(validate_step_expert_activation_limit(Some(0.0)).is_err());
11397        assert!(validate_step_expert_activation_limit(limit).is_ok());
11398    }
11399
11400    #[test]
11401    fn moe_residual_host_preserves_official_add_order() {
11402        let output = moe_residual_host(&[1.0e20], &[-1.0e20], &[1.0]).unwrap();
11403        assert_eq!(output, [0.0]);
11404        assert_eq!(
11405            moe_residual_host(&[0.0], &[0.0, 1.0], &[0.0]).unwrap_err(),
11406            "MoE residual lengths residual=1 routed=2 shared=1"
11407        );
11408    }
11409
11410    #[test]
11411    fn expert_owner_routes_preserve_global_pair_order_with_local_expert_ids() {
11412        let selected = [0, 36, 72, 108, 144, 180, 216, 252];
11413        let owners = partition_expert_owner_routes(288, 4, 1, 8, &selected).unwrap();
11414        assert_eq!(owners.len(), 4);
11415        for (rank, owner) in owners.iter().enumerate() {
11416            assert_eq!(owner.rank, rank);
11417            assert_eq!(owner.selected, vec![0, 36]);
11418            assert_eq!(owner.token_rows, vec![0, 0]);
11419            assert_eq!(owner.global_pairs, vec![rank * 2, rank * 2 + 1]);
11420        }
11421    }
11422
11423    #[test]
11424    fn expert_owner_routes_validate_geometry_and_selected_experts() {
11425        assert!(partition_expert_owner_routes(288, 5, 1, 8, &[0; 8]).is_err());
11426        assert!(partition_expert_owner_routes(288, 4, 2, 8, &[0; 8]).is_err());
11427        let error = partition_expert_owner_routes(288, 4, 1, 8, &[288; 8]).unwrap_err();
11428        assert!(error.contains("outside 0..288"));
11429    }
11430
11431    #[test]
11432    fn step_grouped_owner_routes_validate_dynamic_top8_shapes() {
11433        let selected = [
11434            1, 73, 80, 145, 152, 159, 217, 224, 12, 84, 91, 156, 163, 170, 228, 235,
11435        ];
11436        assert_eq!(
11437            validate_step_grouped_owner_routes(288, 2, &selected).unwrap(),
11438            16
11439        );
11440        let owners = partition_expert_owner_routes(288, 4, 2, 8, &selected).unwrap();
11441        assert_eq!(
11442            owners
11443                .iter()
11444                .map(|owner| owner.selected.len())
11445                .collect::<Vec<_>>(),
11446            vec![2, 4, 6, 4]
11447        );
11448        assert!(validate_step_grouped_owner_routes(288, 2, &selected[..8]).is_err());
11449        assert!(validate_step_grouped_owner_routes(288, 1, &[0; 8]).is_err());
11450        assert!(validate_step_grouped_owner_routes(287, 2, &selected).is_err());
11451    }
11452
11453    #[test]
11454    fn weighted_route_combine_requires_a_canonical_pair_permutation() {
11455        let owner0 = [0usize, 3];
11456        let owner1 = [1usize, 2];
11457        let owners = [owner0.as_slice(), owner1.as_slice()];
11458        assert_eq!(
11459            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, 0.2, 0.3, 0.4],)
11460                .unwrap(),
11461            WeightedRouteCombineShape {
11462                pairs: 4,
11463                max_pairs: 12,
11464            }
11465        );
11466        let duplicate = [owner0.as_slice(), &[1usize, 1][..]];
11467        assert!(
11468            validate_weighted_route_combine(4096, 4, 3, 1, &duplicate, &[0.1, 0.2, 0.3, 0.4],)
11469                .is_err()
11470        );
11471        assert!(
11472            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, f32::NAN, 0.3, 0.4],)
11473                .is_err()
11474        );
11475        assert!(
11476            validate_weighted_route_combine(4096, 4, 1, 2, &owners, &[0.1, 0.2, 0.3, 0.4],)
11477                .is_err()
11478        );
11479    }
11480
11481    #[test]
11482    fn native_p2p_door_is_strict_and_default_off() {
11483        assert!(!parse_step_tp_native_p2p(None).unwrap());
11484        assert!(!parse_step_tp_native_p2p(Some("")).unwrap());
11485        assert!(!parse_step_tp_native_p2p(Some("0")).unwrap());
11486        assert!(parse_step_tp_native_p2p(Some("1")).unwrap());
11487        assert!(parse_step_tp_native_p2p(Some("true")).is_err());
11488        assert!(parse_step_tp_native_p2p(Some("2")).is_err());
11489    }
11490
11491    #[test]
11492    fn bulk_p2p_door_is_strict_and_default_off() {
11493        assert!(!parse_step_tp_bulk_p2p(None).unwrap());
11494        assert!(!parse_step_tp_bulk_p2p(Some("")).unwrap());
11495        assert!(!parse_step_tp_bulk_p2p(Some("0")).unwrap());
11496        assert!(parse_step_tp_bulk_p2p(Some("1")).unwrap());
11497        assert!(parse_step_tp_bulk_p2p(Some("true")).is_err());
11498        assert!(parse_step_tp_bulk_p2p(Some("2")).is_err());
11499    }
11500
11501    #[test]
11502    fn ep_device_arithmetic_door_is_strict_and_default_off() {
11503        assert!(!parse_step_ep_device_arithmetic(None).unwrap());
11504        assert!(!parse_step_ep_device_arithmetic(Some("")).unwrap());
11505        assert!(!parse_step_ep_device_arithmetic(Some("0")).unwrap());
11506        assert!(parse_step_ep_device_arithmetic(Some("1")).unwrap());
11507        assert!(parse_step_ep_device_arithmetic(Some("true")).is_err());
11508        assert!(parse_step_ep_device_arithmetic(Some("2")).is_err());
11509    }
11510
11511    #[test]
11512    fn f32_mirror_door_is_strict_and_default_off() {
11513        assert!(!parse_step_tp_f32_mirror(None).unwrap());
11514        assert!(!parse_step_tp_f32_mirror(Some("")).unwrap());
11515        assert!(!parse_step_tp_f32_mirror(Some("0")).unwrap());
11516        assert!(parse_step_tp_f32_mirror(Some("1")).unwrap());
11517        assert!(parse_step_tp_f32_mirror(Some("true")).is_err());
11518        assert!(parse_step_tp_f32_mirror(Some("2")).is_err());
11519    }
11520
11521    fn matrix(out_features: usize, in_features: usize) -> (Vec<u8>, Vec<f32>) {
11522        let codes = (0..out_features * in_features)
11523            .map(|index| (index % 251) as u8)
11524            .collect();
11525        let scales = (0..out_features.div_ceil(FP8_BLOCK) * in_features.div_ceil(FP8_BLOCK))
11526            .map(|index| index as f32 + 1.0)
11527            .collect();
11528        (codes, scales)
11529    }
11530
11531    fn bf16_matrix_bytes(out_features: usize, in_features: usize) -> Vec<u8> {
11532        (0..out_features * in_features)
11533            .flat_map(|value| (value as u16).to_le_bytes())
11534            .collect()
11535    }
11536
11537    fn decode_u16(bytes: &[u8]) -> Vec<u16> {
11538        bytes
11539            .chunks_exact(2)
11540            .map(|bytes| u16::from_le_bytes([bytes[0], bytes[1]]))
11541            .collect()
11542    }
11543
11544    #[test]
11545    fn bf16_matrix_rejects_wrong_byte_count() {
11546        let bytes = vec![0u8; 4 * 4 * 2 - 1];
11547        let matrix = Bf16Matrix {
11548            bytes: &bytes,
11549            out_features: 4,
11550            in_features: 4,
11551        };
11552        assert!(matrix.validate().unwrap_err().contains("4x4x2"));
11553    }
11554
11555    #[test]
11556    fn replicated_device_rows_require_exact_rank_local_shapes() {
11557        assert_eq!(
11558            replicated_device_row_values(3, 4096, 4, &[12_288; 4]).unwrap(),
11559            12_288
11560        );
11561        assert!(replicated_device_row_values(0, 4096, 4, &[0; 4]).is_err());
11562        assert!(replicated_device_row_values(3, 0, 4, &[0; 4]).is_err());
11563        assert!(replicated_device_row_values(3, 4096, 4, &[12_288; 3]).is_err());
11564        assert!(
11565            replicated_device_row_values(3, 4096, 4, &[12_288, 12_288, 12_287, 12_288]).is_err()
11566        );
11567        assert!(replicated_device_row_values(usize::MAX, 2, 1, &[0]).is_err());
11568    }
11569
11570    #[test]
11571    fn replicated_device_row_refresh_requires_exact_root_source() {
11572        assert_eq!(
11573            replicated_device_row_source_values(1, 12_288, 12_288, 3, 3).unwrap(),
11574            12_288
11575        );
11576        assert!(replicated_device_row_source_values(0, 12_288, 0, 3, 3).is_err());
11577        assert!(replicated_device_row_source_values(1, 0, 0, 3, 3).is_err());
11578        assert!(replicated_device_row_source_values(1, 12_288, 12_287, 3, 3).is_err());
11579        assert!(replicated_device_row_source_values(1, 12_288, 12_288, 2, 3).is_err());
11580        assert!(replicated_device_row_source_values(usize::MAX, 2, 0, 3, 3).is_err());
11581    }
11582
11583    #[test]
11584    fn step_bf16_canonical_rows_are_topology_invariant_through_tp8() {
11585        for tp in [1, 2, 4, 8] {
11586            assert_eq!(step_bf16_canonical_chunk_rows(8_192, tp).unwrap(), 1_024);
11587            assert_eq!(step_bf16_canonical_chunk_rows(12_288, tp).unwrap(), 1_536);
11588            assert_eq!(step_bf16_canonical_chunk_rows(1_024, tp).unwrap(), 128);
11589            assert_eq!(step_bf16_canonical_chunk_cols(8_192, tp).unwrap(), 1_024);
11590            assert_eq!(step_bf16_canonical_chunk_cols(12_288, tp).unwrap(), 1_536);
11591        }
11592        assert!(step_bf16_canonical_chunk_rows(12_288, 3).is_err());
11593        assert!(step_bf16_canonical_chunk_rows(1_001, 2).is_err());
11594        assert!(step_bf16_canonical_chunk_cols(12_288, 3).is_err());
11595        assert!(step_bf16_canonical_chunk_cols(1_001, 2).is_err());
11596    }
11597
11598    #[test]
11599    fn cache_rows_split_by_token_then_rank() {
11600        let rows = (0u8..24).collect::<Vec<_>>();
11601        assert_eq!(
11602            cache_rank_rows(&rows, 3, 4, 2, 0).unwrap(),
11603            vec![0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19]
11604        );
11605        assert_eq!(
11606            cache_rank_rows(&rows, 3, 4, 2, 1).unwrap(),
11607            vec![4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23]
11608        );
11609        assert!(cache_rank_rows(&rows[..23], 3, 4, 2, 0).is_err());
11610        assert!(cache_rank_rows(&rows, 3, 4, 2, 2).is_err());
11611    }
11612
11613    #[test]
11614    fn bf16_column_shard_preserves_contiguous_output_rows() {
11615        let bytes = bf16_matrix_bytes(4, 4);
11616        let matrix = Bf16Matrix {
11617            bytes: &bytes,
11618            out_features: 4,
11619            in_features: 4,
11620        };
11621        let shard = bf16_column_shard(matrix, 2, 1).unwrap();
11622        assert_eq!(shard.out_features, 2);
11623        assert_eq!(shard.in_features, 4);
11624        assert_eq!(decode_u16(shard.bytes), (8..16).collect::<Vec<_>>());
11625    }
11626
11627    #[test]
11628    fn bf16_row_shard_preserves_each_input_column_window() {
11629        let bytes = bf16_matrix_bytes(3, 4);
11630        let matrix = Bf16Matrix {
11631            bytes: &bytes,
11632            out_features: 3,
11633            in_features: 4,
11634        };
11635        let shard = bf16_row_shard(matrix, 2, 1).unwrap();
11636        assert_eq!(decode_u16(&shard), vec![2, 3, 6, 7, 10, 11]);
11637    }
11638
11639    #[test]
11640    fn bf16_row_block_preserves_global_column_order() {
11641        let bytes = bf16_matrix_bytes(3, 8);
11642        let matrix = Bf16Matrix {
11643            bytes: &bytes,
11644            out_features: 3,
11645            in_features: 8,
11646        };
11647        let block = bf16_row_block(matrix, 2, 3).unwrap();
11648        assert_eq!(decode_u16(&block), vec![2, 3, 4, 10, 11, 12, 18, 19, 20]);
11649    }
11650
11651    #[test]
11652    fn column_shard_preserves_contiguous_weight_and_scale_rows() {
11653        let (codes, scales) = matrix(1280, 4096);
11654        let matrix = E4m3BlockMatrix {
11655            codes: &codes,
11656            scales: &scales,
11657            out_features: 1280,
11658            in_features: 4096,
11659        };
11660        let shard = column_shard(matrix, 2, 1).unwrap();
11661        assert_eq!(shard.out_features, 640);
11662        assert_eq!(shard.codes, &codes[640 * 4096..]);
11663        assert_eq!(shard.scales, &scales[5 * 32..]);
11664    }
11665
11666    #[test]
11667    fn row_shard_preserves_each_weight_and_scale_column_window() {
11668        let (codes, scales) = matrix(4096, 1280);
11669        let matrix = E4m3BlockMatrix {
11670            codes: &codes,
11671            scales: &scales,
11672            out_features: 4096,
11673            in_features: 1280,
11674        };
11675        let (shard_codes, shard_scales) = row_shard(matrix, 2, 1).unwrap();
11676        assert_eq!(shard_codes.len(), 4096 * 640);
11677        assert_eq!(&shard_codes[..640], &codes[640..1280]);
11678        assert_eq!(&shard_codes[640..1280], &codes[1280 + 640..2560]);
11679        assert_eq!(shard_scales.len(), 32 * 5);
11680        assert_eq!(&shard_scales[..5], &scales[5..10]);
11681        assert_eq!(&shard_scales[5..10], &scales[15..20]);
11682    }
11683
11684    #[test]
11685    fn activation_shards_keep_token_rows_separate() {
11686        let activations: Vec<f32> = (0..2 * 8).map(|value| value as f32).collect();
11687        assert_eq!(
11688            activation_shard(&activations, 2, 8, 2, 1),
11689            vec![4.0, 5.0, 6.0, 7.0, 12.0, 13.0, 14.0, 15.0],
11690        );
11691    }
11692
11693    #[test]
11694    fn expert_bank_selects_expert_major_code_and_scale_planes() {
11695        let expert_count = 2;
11696        let out_features = 128;
11697        let in_features = 128;
11698        let code_stride = out_features * in_features;
11699        let codes: Vec<u8> = (0..expert_count * code_stride)
11700            .map(|index| (index % 251) as u8)
11701            .collect();
11702        let scales = vec![1.0f32, 2.0];
11703        let bank = E4m3ExpertBank {
11704            codes: &codes,
11705            scales: &scales,
11706            expert_count,
11707            out_features,
11708            in_features,
11709        };
11710        bank.validate().unwrap();
11711        let expert = bank.expert(1).unwrap();
11712        assert_eq!(expert.codes, &codes[code_stride..]);
11713        assert_eq!(expert.scales, &[2.0]);
11714    }
11715
11716    #[test]
11717    fn expert_bank_rejects_non_positive_scale() {
11718        let codes = vec![0u8; 128 * 128];
11719        let scales = vec![0.0f32];
11720        let bank = E4m3ExpertBank {
11721            codes: &codes,
11722            scales: &scales,
11723            expert_count: 1,
11724            out_features: 128,
11725            in_features: 128,
11726        };
11727        assert!(bank.validate().unwrap_err().contains("non-positive"));
11728    }
11729
11730    #[test]
11731    fn tensor_parallel_column_bank_keeps_each_expert_scale_plane_separate() {
11732        let expert_count = 2;
11733        let out_features = 256;
11734        let in_features = 128;
11735        let code_stride = out_features * in_features;
11736        let scale_stride = 2;
11737        let codes = (0..expert_count * code_stride)
11738            .map(|index| (index % 251) as u8)
11739            .collect::<Vec<_>>();
11740        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
11741        let bank = E4m3ExpertBank {
11742            codes: &codes,
11743            scales: &scales,
11744            expert_count,
11745            out_features,
11746            in_features,
11747        };
11748
11749        let rank = pack_column_bank_rank(bank, 2, 1).unwrap();
11750        assert_eq!(rank.out_features, 128);
11751        assert_eq!(rank.in_features, 128);
11752        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
11753        assert_eq!(rank.scales, vec![11.0, 21.0]);
11754        assert_eq!(&rank.codes[..128 * 128], &codes[128 * 128..256 * 128]);
11755        assert_eq!(
11756            &rank.codes[128 * 128..],
11757            &codes[code_stride + 128 * 128..2 * code_stride]
11758        );
11759        assert_eq!(scale_stride, scales.len() / expert_count);
11760    }
11761
11762    #[test]
11763    fn tensor_parallel_row_bank_keeps_each_expert_scale_plane_separate() {
11764        let expert_count = 2;
11765        let out_features = 128;
11766        let in_features = 256;
11767        let code_stride = out_features * in_features;
11768        let codes = (0..expert_count * code_stride)
11769            .map(|index| (index % 251) as u8)
11770            .collect::<Vec<_>>();
11771        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
11772        let bank = E4m3ExpertBank {
11773            codes: &codes,
11774            scales: &scales,
11775            expert_count,
11776            out_features,
11777            in_features,
11778        };
11779
11780        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
11781        assert_eq!(rank.out_features, 128);
11782        assert_eq!(rank.in_features, 128);
11783        assert_eq!(rank.k_blocks, Some(1));
11784        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
11785        assert_eq!(rank.scales, vec![11.0, 21.0]);
11786        assert_eq!(&rank.codes[..128], &codes[128..256]);
11787        assert_eq!(
11788            &rank.codes[128 * 128..128 * 128 + 128],
11789            &codes[code_stride + 128..code_stride + 256]
11790        );
11791    }
11792
11793    #[test]
11794    fn tensor_parallel_row_bank_preserves_global_k_block_order() {
11795        let expert_count = 2;
11796        let out_features = 256;
11797        let in_features = 512;
11798        let code_stride = out_features * in_features;
11799        let mut codes = vec![0u8; expert_count * code_stride];
11800        for expert in 0..expert_count {
11801            for row in 0..out_features {
11802                for block in 0..4 {
11803                    let value = (expert * 80 + block * 16 + row % 16) as u8;
11804                    let start = expert * code_stride + row * in_features + block * FP8_BLOCK;
11805                    codes[start..start + FP8_BLOCK].fill(value);
11806                }
11807            }
11808        }
11809        let scales = vec![
11810            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,
11811            112.0, 113.0, 114.0,
11812        ];
11813        let bank = E4m3ExpertBank {
11814            codes: &codes,
11815            scales: &scales,
11816            expert_count,
11817            out_features,
11818            in_features,
11819        };
11820
11821        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
11822        assert_eq!(rank.out_features, out_features);
11823        assert_eq!(rank.in_features, 256);
11824        assert_eq!(rank.k_blocks, Some(2));
11825        assert_eq!(rank.code_stride, out_features * 256);
11826        assert_eq!(rank.scale_stride, 4);
11827        assert_eq!(&rank.scales[..4], &[3.0, 13.0, 4.0, 14.0]);
11828        assert_eq!(&rank.scales[4..], &[103.0, 113.0, 104.0, 114.0]);
11829
11830        let block_stride = out_features * FP8_BLOCK;
11831        assert!(rank.codes[..FP8_BLOCK].iter().all(|&code| code == 32));
11832        assert!(
11833            rank.codes[block_stride..block_stride + FP8_BLOCK]
11834                .iter()
11835                .all(|&code| code == 48)
11836        );
11837        assert!(
11838            rank.codes[rank.code_stride..rank.code_stride + FP8_BLOCK]
11839                .iter()
11840                .all(|&code| code == 112)
11841        );
11842        assert!(
11843            rank.codes
11844                [rank.code_stride + block_stride..rank.code_stride + block_stride + FP8_BLOCK]
11845                .iter()
11846                .all(|&code| code == 128)
11847        );
11848    }
11849
11850    #[test]
11851    fn step_ep_layer_specs_are_literal_and_fail_closed() {
11852        assert!(parse_step_ep_layer_specs(None).unwrap().is_empty());
11853        assert!(parse_step_ep_layer_specs(Some("0")).unwrap().is_empty());
11854        assert_eq!(
11855            parse_step_ep_layer_specs(Some("24@1,2")).unwrap(),
11856            vec![StepEpLayerSpec {
11857                layer: 24,
11858                devices: vec![1, 2],
11859            }]
11860        );
11861        assert_eq!(
11862            parse_step_ep_layer_specs(Some("24-25@1,2;31@0,2")).unwrap(),
11863            vec![
11864                StepEpLayerSpec {
11865                    layer: 24,
11866                    devices: vec![1, 2],
11867                },
11868                StepEpLayerSpec {
11869                    layer: 25,
11870                    devices: vec![1, 2],
11871                },
11872                StepEpLayerSpec {
11873                    layer: 31,
11874                    devices: vec![0, 2],
11875                },
11876            ]
11877        );
11878        assert!(parse_step_ep_layer_specs(Some("24@1")).is_err());
11879        assert!(parse_step_ep_layer_specs(Some("24@1,1")).is_err());
11880        assert!(parse_step_ep_layer_specs(Some("layer@1,2")).is_err());
11881        assert!(parse_step_ep_layer_specs(Some("25-24@1,2")).is_err());
11882        assert!(parse_step_ep_layer_specs(Some("0-128@1,2")).is_err());
11883        assert!(parse_step_ep_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
11884        assert!(parse_step_ep_layer_specs(Some("all@0,1")).is_err());
11885    }
11886
11887    #[test]
11888    fn step_tp_layer_specs_share_the_fail_closed_layer_contract() {
11889        assert!(parse_step_tp_layer_specs(None).unwrap().is_empty());
11890        assert!(parse_step_tp_layer_specs(Some("0")).unwrap().is_empty());
11891        assert_eq!(
11892            parse_step_tp_layer_specs(Some("24-25@1,2")).unwrap(),
11893            vec![
11894                StepTpLayerSpec {
11895                    layer: 24,
11896                    devices: vec![1, 2],
11897                },
11898                StepTpLayerSpec {
11899                    layer: 25,
11900                    devices: vec![1, 2],
11901                },
11902            ]
11903        );
11904        let error = parse_step_tp_layer_specs(Some("24@1")).unwrap_err();
11905        assert!(error.contains("MEMRA_STEP_TP"));
11906        assert!(parse_step_tp_layer_specs(Some("24@1,1")).is_err());
11907        assert!(parse_step_tp_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
11908
11909        let all = parse_step_tp_layer_specs(Some("all@0,1,2,3,4,5,6,7")).unwrap();
11910        assert_eq!(all.len(), STEP37_TRUNK_LAYERS);
11911        assert_eq!(all.first().unwrap().layer, 0);
11912        assert_eq!(all.last().unwrap().layer, STEP37_TRUNK_LAYERS - 1);
11913        let devices = (0..8).collect::<Vec<_>>();
11914        assert!(all.iter().all(|spec| spec.devices == devices));
11915        assert!(parse_step_tp_layer_specs(Some("all@0,1;44@0,1")).is_err());
11916    }
11917}
11918
11919// ===== Whole-token graph builder (increment B) ==================================================
11920//
11921// The decode fns are already sectioned at every e/rank/root seam (the stage flow, sweeps_rank,
11922// finish splits, the dcw arm). `graph_section` is the one annotation those seams call: eager
11923// mode runs the closure verbatim; build mode wraps it in a stream capture on the section's
11924// device and records a child + its dependency edges. A token then assembles as ONE multi-device
11925// parent (children per section per layer), launched once per token — the launch-collapse the
11926// per-layer minis could not reach (routes-mini negative, 2026-08-21).
11927
11928/// One captured section: the child graph plus which parent node it became, and the CUDA
11929/// context it was captured under (exec memset updates need it).
11930struct TokenGraphChild {
11931    graph: cudarc::driver::CudaGraph,
11932    node: cudarc::driver::sys::CUgraphNode,
11933    ctx: cudarc::driver::sys::CUcontext,
11934}
11935
11936/// Exec-updatable fa geometry discovered in one attention rank child: the three partial-pool
11937/// memsets, the dcw fa kernel, and its combine — everything a bucket change touches. Node
11938/// handles address the parent's CLONED child graphs (the M1-probed update path).
11939struct TokenGraphFaSite {
11940    ctx: cudarc::driver::sys::CUcontext,
11941    memset_o: cudarc::driver::sys::CUgraphNode,
11942    memset_m: [cudarc::driver::sys::CUgraphNode; 2],
11943    fa: cudarc::driver::sys::CUgraphNode,
11944    combine: cudarc::driver::sys::CUgraphNode,
11945    window: usize,
11946    n_head: usize,
11947    n_head_kv: usize,
11948    head_dim: usize,
11949}
11950
11951pub struct TokenGraphBuilder {
11952    parent: cudarc::driver::sys::CUgraph,
11953    children: Vec<TokenGraphChild>,
11954    /// Nodes every NEXT section must depend on (the frontier): one node for serial flow,
11955    /// several while a parallel group is open.
11956    frontier: Vec<cudarc::driver::sys::CUgraphNode>,
11957    /// Detached sections: forked from the frontier at issue time, joined ONLY by the next
11958    /// non-group section (they never gate a parallel group merge — the SH1 shape).
11959    pending_detached: Vec<cudarc::driver::sys::CUgraphNode>,
11960    /// Open parallel group: sections issued under the same group id fork from the SAME
11961    /// predecessor set and merge into the frontier together when the group closes.
11962    group: Option<(
11963        u32,
11964        Vec<cudarc::driver::sys::CUgraphNode>,
11965        Vec<cudarc::driver::sys::CUgraphNode>,
11966    )>,
11967}
11968
11969// SAFETY: single decode thread; graph handles are process handles.
11970unsafe impl Send for TokenGraphBuilder {}
11971
11972impl TokenGraphBuilder {
11973    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
11974        use cudarc::driver::sys;
11975        let mut parent: sys::CUgraph = std::ptr::null_mut();
11976        let r = unsafe { sys::cuGraphCreate(&mut parent, 0) };
11977        if r != sys::CUresult::CUDA_SUCCESS {
11978            return Err(format!("token graph create: {r:?}").into());
11979        }
11980        Ok(Self {
11981            parent,
11982            children: Vec::new(),
11983            frontier: Vec::new(),
11984            pending_detached: Vec::new(),
11985            group: None,
11986        })
11987    }
11988
11989    fn push_child(
11990        &mut self,
11991        graph: cudarc::driver::CudaGraph,
11992        parallel_group: Option<u32>,
11993        detached: bool,
11994        absorb: bool,
11995        ctx: cudarc::driver::sys::CUcontext,
11996    ) -> Result<(), Box<dyn std::error::Error>> {
11997        use cudarc::driver::sys;
11998        // Resolve the dependency set: serial sections depend on the current frontier; a
11999        // parallel-group section depends on the frontier AS OF the group opening; a
12000        // DETACHED section forks like a group member but joins only the next serial section.
12001        let deps: Vec<sys::CUgraphNode> = match (&mut self.group, parallel_group) {
12002            (Some((open, base, _)), Some(group)) if *open == group => base.clone(),
12003            (state, Some(group)) => {
12004                // opening a new group (closing any previous one first)
12005                if let Some((_, _, members)) = state.take() {
12006                    self.frontier = members;
12007                }
12008                let base = self.frontier.clone();
12009                *state = Some((group, base.clone(), Vec::new()));
12010                base
12011            }
12012            (state, None) if detached => match state.as_ref() {
12013                Some((_, base, _)) => base.clone(),
12014                None => self.frontier.clone(),
12015            },
12016            (state, None) => {
12017                if let Some((_, _, members)) = state.take() {
12018                    self.frontier = members;
12019                }
12020                let mut deps = self.frontier.clone();
12021                if absorb {
12022                    deps.append(&mut self.pending_detached);
12023                }
12024                deps
12025            }
12026        };
12027        let mut node: sys::CUgraphNode = std::ptr::null_mut();
12028        let r = unsafe {
12029            sys::cuGraphAddChildGraphNode(
12030                &mut node,
12031                self.parent,
12032                if deps.is_empty() {
12033                    std::ptr::null()
12034                } else {
12035                    deps.as_ptr()
12036                },
12037                deps.len(),
12038                graph.cu_graph(),
12039            )
12040        };
12041        if r != sys::CUresult::CUDA_SUCCESS {
12042            return Err(format!("token graph child: {r:?}").into());
12043        }
12044        match (&mut self.group, parallel_group, detached) {
12045            (_, None, true) => self.pending_detached.push(node),
12046            (Some((_, _, members)), Some(_), _) => members.push(node),
12047            _ => self.frontier = vec![node],
12048        }
12049        self.children.push(TokenGraphChild { graph, node, ctx });
12050        Ok(())
12051    }
12052
12053    pub fn finish(mut self) -> Result<TokenGraph, Box<dyn std::error::Error>> {
12054        use cudarc::driver::sys;
12055        if let Some((_, _, members)) = self.group.take() {
12056            self.frontier = members;
12057        }
12058        // Discover the fa sites BEFORE instantiate: the parent's cloned child graphs hold
12059        // the node handles the exec update path (M1) addresses.
12060        let mut fa_sites = Vec::new();
12061        for child in &self.children {
12062            if let Some(site) = discover_fa_site(child.node, child.ctx)? {
12063                fa_sites.push(site);
12064            }
12065        }
12066        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
12067        let r = unsafe { sys::cuGraphInstantiateWithFlags(&mut exec, self.parent, 0) };
12068        if r != sys::CUresult::CUDA_SUCCESS {
12069            return Err(format!("token graph instantiate: {r:?}").into());
12070        }
12071        Ok(TokenGraph {
12072            exec,
12073            parent: self.parent,
12074            _children: self.children,
12075            fa_sites,
12076        })
12077    }
12078}
12079
12080/// Walk one child graph; if it carries the attention-section signature (exactly three MEMSET
12081/// nodes chained memset->memset->memset->fa_kernel->combine_kernel), return its update site.
12082fn discover_fa_site(
12083    child_node: cudarc::driver::sys::CUgraphNode,
12084    ctx: cudarc::driver::sys::CUcontext,
12085) -> Result<Option<TokenGraphFaSite>, Box<dyn std::error::Error>> {
12086    use cudarc::driver::sys;
12087    fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
12088        if r == sys::CUresult::CUDA_SUCCESS {
12089            Ok(())
12090        } else {
12091            Err(format!("{what}: {r:?}").into())
12092        }
12093    }
12094    let mut graph: sys::CUgraph = std::ptr::null_mut();
12095    unsafe {
12096        cu_try(
12097            sys::cuGraphChildGraphNodeGetGraph(child_node, &mut graph),
12098            "fa-site child GetGraph",
12099        )?;
12100    }
12101    let mut count: usize = 0;
12102    unsafe {
12103        cu_try(
12104            sys::cuGraphGetNodes(graph, std::ptr::null_mut(), &mut count),
12105            "fa-site GetNodes(count)",
12106        )?;
12107    }
12108    let mut nodes: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); count];
12109    unsafe {
12110        cu_try(
12111            sys::cuGraphGetNodes(graph, nodes.as_mut_ptr(), &mut count),
12112            "fa-site GetNodes",
12113        )?;
12114    }
12115    nodes.truncate(count);
12116    let node_type =
12117        |node: sys::CUgraphNode| -> Result<sys::CUgraphNodeType, Box<dyn std::error::Error>> {
12118            let mut ty = sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_EMPTY;
12119            unsafe {
12120                cu_try(
12121                    sys::cuGraphNodeGetType(node, &mut ty),
12122                    "fa-site NodeGetType",
12123                )?;
12124            }
12125            Ok(ty)
12126        };
12127    let memsets: Vec<sys::CUgraphNode> = {
12128        let mut v = Vec::new();
12129        for &node in &nodes {
12130            if node_type(node)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_MEMSET {
12131                v.push(node);
12132            }
12133        }
12134        v
12135    };
12136    if memsets.len() != 3 {
12137        return Ok(None);
12138    }
12139    // Single-stream capture makes the chain linear: follow dependent edges from each memset.
12140    let dependents =
12141        |node: sys::CUgraphNode| -> Result<Vec<sys::CUgraphNode>, Box<dyn std::error::Error>> {
12142            let mut n: usize = 0;
12143            unsafe {
12144                cu_try(
12145                    sys::cuGraphNodeGetDependentNodes_v2(
12146                        node,
12147                        std::ptr::null_mut(),
12148                        std::ptr::null_mut(),
12149                        &mut n,
12150                    ),
12151                    "fa-site GetDependentNodes(count)",
12152                )?;
12153            }
12154            let mut v: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); n];
12155            unsafe {
12156                cu_try(
12157                    sys::cuGraphNodeGetDependentNodes_v2(
12158                        node,
12159                        v.as_mut_ptr(),
12160                        std::ptr::null_mut(),
12161                        &mut n,
12162                    ),
12163                    "fa-site GetDependentNodes",
12164                )?;
12165            }
12166            v.truncate(n);
12167            Ok(v)
12168        };
12169    // The LAST memset is the one whose direct dependent is a kernel (fa); the other two are
12170    // ordered among themselves but interchangeable for width updates.
12171    let mut fa: Option<sys::CUgraphNode> = None;
12172    let mut last_memset: Option<sys::CUgraphNode> = None;
12173    for &ms in &memsets {
12174        for dep in dependents(ms)? {
12175            if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
12176                fa = Some(dep);
12177                last_memset = Some(ms);
12178            }
12179        }
12180    }
12181    let (Some(fa), Some(_last)) = (fa, last_memset) else {
12182        return Ok(None);
12183    };
12184    let mut combine: Option<sys::CUgraphNode> = None;
12185    for dep in dependents(fa)? {
12186        if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
12187            combine = Some(dep);
12188        }
12189    }
12190    let Some(combine) = combine else {
12191        return Ok(None);
12192    };
12193    // Read the fa launch geometry from its baked args (arg order pinned by fa_decode_dcw):
12194    // 6=hd 7=nh 8=nhkv 11=win 13=nsp 14=ski.
12195    let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
12196    unsafe {
12197        cu_try(
12198            sys::cuGraphKernelNodeGetParams_v2(fa, &mut params),
12199            "fa-site KernelNodeGetParams",
12200        )?;
12201    }
12202    let arg_i32 =
12203        |slot: usize| -> i32 { unsafe { *(*params.kernelParams.add(slot) as *const i32) } };
12204    let (hd, nh, nhkv, win) = (arg_i32(6), arg_i32(7), arg_i32(8), arg_i32(11));
12205    // Identify the o-partial memset (hd x wider than the m/l pair).
12206    let width_of = |node: sys::CUgraphNode| -> Result<usize, Box<dyn std::error::Error>> {
12207        let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
12208        unsafe {
12209            cu_try(
12210                sys::cuGraphMemsetNodeGetParams(node, &mut mp),
12211                "fa-site MemsetNodeGetParams",
12212            )?;
12213        }
12214        Ok(mp.width)
12215    };
12216    let mut widest = memsets[0];
12217    for &ms in &memsets[1..] {
12218        if width_of(ms)? > width_of(widest)? {
12219            widest = ms;
12220        }
12221    }
12222    let memset_m: Vec<sys::CUgraphNode> =
12223        memsets.iter().copied().filter(|&m| m != widest).collect();
12224    Ok(Some(TokenGraphFaSite {
12225        ctx,
12226        memset_o: widest,
12227        memset_m: [memset_m[0], memset_m[1]],
12228        fa,
12229        combine,
12230        window: win as usize,
12231        n_head: nh as usize,
12232        n_head_kv: nhkv as usize,
12233        head_dim: hd as usize,
12234    }))
12235}
12236
12237pub struct TokenGraph {
12238    exec: cudarc::driver::sys::CUgraphExec,
12239    parent: cudarc::driver::sys::CUgraph,
12240    _children: Vec<TokenGraphChild>,
12241    fa_sites: Vec<TokenGraphFaSite>,
12242}
12243
12244unsafe impl Send for TokenGraph {}
12245
12246impl TokenGraph {
12247    /// Retarget every fa site to a new bucket via exec param updates (M1 path) — replaces the
12248    /// per-bucket whole-graph rebuild (~55ms) with ~450 node updates (~1ms). Per site the
12249    /// bucket caps at the layer window; nsp/ski/gridDimY and the partial-pool memset widths
12250    /// move together so the exec always matches what a fresh build at `bucket` would bake.
12251    pub fn retarget_bucket(&mut self, bucket: usize) -> Result<(), Box<dyn std::error::Error>> {
12252        use cudarc::driver::sys;
12253        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
12254            if r == sys::CUresult::CUDA_SUCCESS {
12255                Ok(())
12256            } else {
12257                Err(format!("{what}: {r:?}").into())
12258            }
12259        }
12260        for site in &self.fa_sites {
12261            let layer_bucket = if site.window > 0 {
12262                bucket.min(site.window)
12263            } else {
12264                bucket
12265            };
12266            let sp = crate::fa_split_keys(layer_bucket, site.n_head_kv);
12267            let nsp = layer_bucket.div_ceil(sp).max(1);
12268            // fa kernel: nsp (slot 13), ski (slot 14), gridDimY = nsp.
12269            let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
12270            unsafe {
12271                cu_try(
12272                    sys::cuGraphKernelNodeGetParams_v2(site.fa, &mut params),
12273                    "retarget fa GetParams",
12274                )?;
12275                *(*params.kernelParams.add(13) as *mut i32) = nsp as i32;
12276                *(*params.kernelParams.add(14) as *mut i32) = sp as i32;
12277                params.gridDimY = nsp as u32;
12278                cu_try(
12279                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.fa, &params),
12280                    "retarget fa SetParams",
12281                )?;
12282            }
12283            // combine: nsp (slot 6).
12284            let mut cparams: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
12285            unsafe {
12286                cu_try(
12287                    sys::cuGraphKernelNodeGetParams_v2(site.combine, &mut cparams),
12288                    "retarget combine GetParams",
12289                )?;
12290                *(*cparams.kernelParams.add(6) as *mut i32) = nsp as i32;
12291                cu_try(
12292                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.combine, &cparams),
12293                    "retarget combine SetParams",
12294                )?;
12295            }
12296            // partial-pool memsets: o = nh*nsp*hd elements, m/l = nh*nsp.
12297            let set_width =
12298                |node: sys::CUgraphNode, width: usize| -> Result<(), Box<dyn std::error::Error>> {
12299                    let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
12300                    unsafe {
12301                        cu_try(
12302                            sys::cuGraphMemsetNodeGetParams(node, &mut mp),
12303                            "retarget memset GetParams",
12304                        )?;
12305                    }
12306                    mp.width = width;
12307                    unsafe {
12308                        cu_try(
12309                            sys::cuGraphExecMemsetNodeSetParams(self.exec, node, &mp, site.ctx),
12310                            "retarget memset SetParams",
12311                        )?;
12312                    }
12313                    Ok(())
12314                };
12315            set_width(site.memset_o, site.n_head * nsp * site.head_dim)?;
12316            set_width(site.memset_m[0], site.n_head * nsp)?;
12317            set_width(site.memset_m[1], site.n_head * nsp)?;
12318        }
12319        Ok(())
12320    }
12321
12322    pub fn launch(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
12323        use cudarc::driver::sys;
12324        let _main = e.gpu.enter_main()?;
12325        let r = unsafe { sys::cuGraphLaunch(self.exec, e.stream().cu_stream() as sys::CUstream) };
12326        if r != sys::CUresult::CUDA_SUCCESS {
12327            return Err(format!("token graph launch: {r:?}").into());
12328        }
12329        Ok(())
12330    }
12331}
12332
12333impl Drop for TokenGraph {
12334    fn drop(&mut self) {
12335        unsafe {
12336            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
12337            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
12338        }
12339    }
12340}
12341
12342std::thread_local! {
12343    static TOKEN_GRAPH_BUILDER: std::cell::RefCell<Option<TokenGraphBuilder>> =
12344        const { std::cell::RefCell::new(None) };
12345}
12346
12347/// Arm the thread-local builder (build mode) — the next `graph_section` calls capture.
12348pub fn token_graph_build_begin() -> Result<(), Box<dyn std::error::Error>> {
12349    let builder = TokenGraphBuilder::new()?;
12350    TOKEN_GRAPH_BUILDER.with(|cell| *cell.borrow_mut() = Some(builder));
12351    Ok(())
12352}
12353
12354/// Take the finished parent (ends build mode).
12355pub fn token_graph_build_finish() -> Result<TokenGraph, Box<dyn std::error::Error>> {
12356    let builder = TOKEN_GRAPH_BUILDER
12357        .with(|cell| cell.borrow_mut().take())
12358        .ok_or("token graph build was not begun")?;
12359    builder.finish()
12360}
12361
12362/// True while the thread-local builder is armed.
12363pub fn token_graph_building() -> bool {
12364    TOKEN_GRAPH_BUILDER.with(|cell| cell.borrow().is_some())
12365}
12366
12367/// The section annotation: eager mode runs the closure verbatim; build mode wraps it in a
12368/// stream capture on `engine`'s stream and records the child. Sections sharing a
12369/// `parallel_group` id fork from the same predecessor set and merge together. The closure
12370/// must be capture-safe (raw copies at cross-context seams, no host syncs, no events).
12371pub fn graph_section<F>(
12372    engine: &Engine,
12373    parallel_group: Option<u32>,
12374    f: F,
12375) -> Result<(), Box<dyn std::error::Error>>
12376where
12377    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
12378{
12379    graph_section_opts(engine, parallel_group, false, false, f)
12380}
12381
12382/// Serial section that ALSO joins every pending detached section (the SH1 consumer shape).
12383pub fn graph_section_absorbing<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
12384where
12385    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
12386{
12387    graph_section_opts(engine, None, false, true, f)
12388}
12389
12390/// `graph_section` with the DETACHED shape: forks from the current frontier (or the open
12391/// group base) and is joined only by the next serial section — never gates a group merge.
12392pub fn graph_section_detached<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
12393where
12394    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
12395{
12396    graph_section_opts(engine, None, true, false, f)
12397}
12398
12399pub fn graph_section_opts<F>(
12400    engine: &Engine,
12401    parallel_group: Option<u32>,
12402    detached: bool,
12403    absorb: bool,
12404    f: F,
12405) -> Result<(), Box<dyn std::error::Error>>
12406where
12407    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
12408{
12409    let building = token_graph_building();
12410    if !building {
12411        let mut f = f;
12412        return f();
12413    }
12414    let (child, ctx) = {
12415        let _main = engine.gpu.enter_main()?;
12416        let mut ctx: cudarc::driver::sys::CUcontext = std::ptr::null_mut();
12417        let r = unsafe { cudarc::driver::sys::cuCtxGetCurrent(&mut ctx) };
12418        if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
12419            return Err(format!("graph section ctx query: {r:?}").into());
12420        }
12421        let mut f = f;
12422        // NO WARMUP RUNS: section bodies carry device side effects (dcw appends, counter
12423        // incs) that a warmup would really execute — the len_d-drift crash of 2026-08-21.
12424        let (child, _retained) = engine.capture_graph_retained_nowarm(|_| f())?;
12425        (child, ctx)
12426    };
12427    TOKEN_GRAPH_BUILDER.with(|cell| {
12428        cell.borrow_mut()
12429            .as_mut()
12430            .expect("builder checked above")
12431            .push_child(child, parallel_group, detached, absorb, ctx)
12432    })
12433}